Skip to content

Commit 154ff11

Browse files
committed
Lazy load temporary access key
1 parent cda95fe commit 154ff11

File tree

4 files changed

+69
-4
lines changed

4 files changed

+69
-4
lines changed

src/Microsoft.Azure.SignalR.Common/Auth/MicrosoftEntra/AccessKeySynchronizer.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,38 @@ internal AccessKeySynchronizer(ILoggerFactory loggerFactory, bool start)
3838
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<AccessKeySynchronizer>();
3939
}
4040

41-
public void AddServiceEndpoint(ServiceEndpoint endpoint)
41+
public Task AddServiceEndpoint(ServiceEndpoint endpoint)
4242
{
4343
if (endpoint.AccessKey is MicrosoftEntraAccessKey key)
4444
{
45-
_ = InitializeAccessKeyTask(key);
4645
_keyMap.TryAdd(key, true);
46+
return InitializeAccessKeyTask(key);
4747
}
48+
return Task.CompletedTask;
4849
}
4950

5051
public void Dispose() => _timer.Stop();
5152

5253
public void UpdateServiceEndpoints(IEnumerable<ServiceEndpoint> endpoints)
5354
{
55+
_keyMap.Clear();
5456
foreach (var endpoint in endpoints)
5557
{
5658
AddServiceEndpoint(endpoint);
5759
}
5860
}
5961

62+
/// <summary>
63+
/// Test only
64+
/// </summary>
65+
/// <param name="e"></param>
66+
/// <returns></returns>
6067
internal bool ContainsKey(ServiceEndpoint e) => _keyMap.ContainsKey(e.AccessKey as MicrosoftEntraAccessKey);
6168

69+
/// <summary>
70+
/// Test only
71+
/// </summary>
72+
/// <returns></returns>
6273
internal int Count() => _keyMap.Count;
6374

6475
private static async Task InitializeAccessKeyTask(MicrosoftEntraAccessKey key)

src/Microsoft.Azure.SignalR.Common/Auth/MicrosoftEntra/IAccessKeySynchronizer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.Collections.Generic;
5+
using System.Threading.Tasks;
56

67
namespace Microsoft.Azure.SignalR;
78

89
internal interface IAccessKeySynchronizer
910
{
10-
public void AddServiceEndpoint(ServiceEndpoint endpoint);
11+
public Task AddServiceEndpoint(ServiceEndpoint endpoint);
1112

1213
public void UpdateServiceEndpoints(IEnumerable<ServiceEndpoint> endpoints);
1314
}

test/Microsoft.Azure.SignalR.Common.Tests/Endpoints/AccessKeySynchronizerFacts.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Copyright (c) Microsoft. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4+
using System;
5+
using System.Threading;
6+
using System.Threading.Tasks;
47
using Azure.Identity;
58
using Microsoft.Azure.SignalR.Tests.Common;
69
using Microsoft.Extensions.Logging.Abstractions;
@@ -34,6 +37,54 @@ public void AddAndRemoveServiceEndpointsTest()
3437
Assert.Equal(0, synchronizer.Count());
3538
}
3639

40+
[Fact]
41+
public async Task GenerateAccessTokenTriggerLoadedTaskTest()
42+
{
43+
var synchronizer = GetInstanceForTest();
44+
45+
var credential = new DefaultAzureCredential();
46+
var endpoint = new TestServiceEndpoint(credential);
47+
48+
var initializeTask = synchronizer.AddServiceEndpoint(endpoint);
49+
50+
var source = new CancellationTokenSource(1000);
51+
52+
var key = Assert.IsType<MicrosoftEntraAccessKey>(endpoint.AccessKey);
53+
Assert.False(key.LoadedTask.IsCompleted);
54+
55+
await Assert.ThrowsAsync<TaskCanceledException>(
56+
async () => await key.GenerateAccessTokenAsync("https://localhost", [], TimeSpan.FromSeconds(1), AccessTokenAlgorithm.HS256, source.Token)
57+
);
58+
Assert.True(key.LoadedTask.IsCompletedSuccessfully);
59+
60+
await initializeTask;
61+
Assert.False(key.Available);
62+
63+
await Assert.ThrowsAsync<AzureSignalRAccessTokenNotAuthorizedException>(
64+
async () => await key.GenerateAccessTokenAsync("https://localhost", [], TimeSpan.FromSeconds(1), AccessTokenAlgorithm.HS256)
65+
);
66+
}
67+
68+
[Fact(Skip = "local test only")]
69+
public async Task GenerateAccessTokenTest()
70+
{
71+
var synchronizer = GetInstanceForTest();
72+
var credential = new VisualStudioCredential();
73+
var endpoint = new ServiceEndpoint(new Uri("https://test-signalr-sdk.service.signalr.net"), credential);
74+
75+
var key = Assert.IsType<MicrosoftEntraAccessKey>(endpoint.AccessKey);
76+
Assert.False(key.LoadedTask.IsCompleted);
77+
78+
var initializeTask = synchronizer.AddServiceEndpoint(endpoint);
79+
80+
var token = await key.GenerateAccessTokenAsync("https://localhost", [], TimeSpan.FromMinutes(1), AccessTokenAlgorithm.HS256);
81+
Assert.NotNull(token);
82+
83+
Assert.True(initializeTask.IsCompleted);
84+
Assert.True(key.LoadedTask.IsCompleted);
85+
Assert.True(key.Available);
86+
}
87+
3788
private static AccessKeySynchronizer GetInstanceForTest()
3889
{
3990
return new AccessKeySynchronizer(NullLoggerFactory.Instance, false);

test/Microsoft.Azure.SignalR.Tests.Common/TestClasses/TestAccessKeySynchronizer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.Threading.Tasks;
23

34
namespace Microsoft.Azure.SignalR.Tests.Common;
45

@@ -10,7 +11,8 @@ public void UpdateServiceEndpoints(IEnumerable<ServiceEndpoint> endpoints)
1011
{
1112
}
1213

13-
public void AddServiceEndpoint(ServiceEndpoint endpoint)
14+
public Task AddServiceEndpoint(ServiceEndpoint endpoint)
1415
{
16+
return Task.CompletedTask;
1517
}
1618
}

0 commit comments

Comments
 (0)