2
2
// Licensed under the MIT License.
3
3
4
4
using System ;
5
+ using System . Collections . Concurrent ;
5
6
using System . Collections . Generic ;
6
7
using Microsoft . Extensions . DependencyInjection ;
7
- using Microsoft . Extensions . Options ;
8
8
using Microsoft . Identity . Abstractions ;
9
9
10
10
namespace Microsoft . Identity . Web
@@ -17,7 +17,7 @@ public DefaultTokenAcquirerFactoryImplementation(IServiceProvider serviceProvide
17
17
}
18
18
private IServiceProvider ServiceProvider { get ; set ; }
19
19
20
- readonly Dictionary < string , ITokenAcquirer > _authSchemes = new Dictionary < string , ITokenAcquirer > ( ) ;
20
+ readonly ConcurrentDictionary < string , ITokenAcquirer > _authSchemes = new ( ) ;
21
21
22
22
/// <inheritdoc/>
23
23
public ITokenAcquirer GetTokenAcquirer (
@@ -26,40 +26,38 @@ public ITokenAcquirer GetTokenAcquirer(
26
26
IEnumerable < CredentialDescription > clientCredentials ,
27
27
string ? region = null )
28
28
{
29
- CheckServiceProviderNotNull ( ) ;
29
+ string key = GetKey ( authority , clientId , region ) ;
30
30
31
- ITokenAcquirer ? tokenAcquirer ;
32
- // Compute the key
33
- string key = GetKey ( authority , clientId ) ;
34
- if ( ! _authSchemes . TryGetValue ( key , out tokenAcquirer ) )
35
- {
36
- MicrosoftIdentityApplicationOptions MicrosoftIdentityApplicationOptions = new MicrosoftIdentityApplicationOptions
37
- {
38
- ClientId = clientId ,
39
- Authority = authority ,
40
- ClientCredentials = clientCredentials ,
41
- SendX5C = true
42
- } ;
43
- if ( region != null )
31
+ // GetOrAdd ONLY synchronizes the outcome. So, the factory might still be invoked multiple times.
32
+ // Therefore, all side-effects within this block must remain idempotent.
33
+ return _authSchemes . GetOrAdd ( key , ( key ) =>
44
34
{
45
- MicrosoftIdentityApplicationOptions . AzureRegion = region ;
46
- }
35
+ MicrosoftIdentityApplicationOptions MicrosoftIdentityApplicationOptions = new ( )
36
+ {
37
+ ClientId = clientId ,
38
+ Authority = authority ,
39
+ ClientCredentials = clientCredentials ,
40
+ SendX5C = true
41
+ } ;
47
42
48
- var optionsMonitor = ServiceProvider . GetRequiredService < IMergedOptionsStore > ( ) ;
49
- var mergedOptions = optionsMonitor . Get ( key ) ;
50
- MergedOptions . UpdateMergedOptionsFromMicrosoftIdentityApplicationOptions ( MicrosoftIdentityApplicationOptions , mergedOptions ) ;
51
- tokenAcquirer = GetTokenAcquirer ( key ) ;
52
- }
53
- return tokenAcquirer ;
43
+ if ( region != null )
44
+ {
45
+ MicrosoftIdentityApplicationOptions . AzureRegion = region ;
46
+ }
47
+
48
+ IMergedOptionsStore optionsMonitor = ServiceProvider . GetRequiredService < IMergedOptionsStore > ( ) ;
49
+ MergedOptions mergedOptions = optionsMonitor . Get ( key ) ;
50
+ MergedOptions . UpdateMergedOptionsFromMicrosoftIdentityApplicationOptions ( MicrosoftIdentityApplicationOptions , mergedOptions ) ;
51
+
52
+ return MakeTokenAcquirer ( key ) ;
53
+ } ) ;
54
54
}
55
55
56
56
/// <inheritdoc/>
57
57
public ITokenAcquirer GetTokenAcquirer ( IdentityApplicationOptions IdentityApplicationOptions )
58
58
{
59
59
_ = Throws . IfNull ( IdentityApplicationOptions ) ;
60
60
61
- CheckServiceProviderNotNull ( ) ;
62
-
63
61
// Compute the Azure region if the option is a MicrosoftIdentityApplicationOptions.
64
62
MicrosoftIdentityApplicationOptions ? MicrosoftIdentityApplicationOptions = IdentityApplicationOptions as MicrosoftIdentityApplicationOptions ;
65
63
if ( MicrosoftIdentityApplicationOptions == null )
@@ -77,33 +75,36 @@ public ITokenAcquirer GetTokenAcquirer(IdentityApplicationOptions IdentityApplic
77
75
} ;
78
76
}
79
77
80
- // Compute the key
81
- ITokenAcquirer ? tokenAcquirer ;
82
- string key = GetKey ( IdentityApplicationOptions . Authority , IdentityApplicationOptions . ClientId ) ;
83
- if ( ! _authSchemes . TryGetValue ( key , out tokenAcquirer ) )
78
+ string key = GetKey ( IdentityApplicationOptions . Authority , IdentityApplicationOptions . ClientId , MicrosoftIdentityApplicationOptions . AzureRegion ) ;
79
+
80
+ return _authSchemes . GetOrAdd ( key , ( key ) =>
84
81
{
85
- var optionsMonitor = ServiceProvider ! . GetRequiredService < IMergedOptionsStore > ( ) ;
86
- var mergedOptions = optionsMonitor . Get ( key ) ;
82
+ IMergedOptionsStore optionsMonitor = ServiceProvider ! . GetRequiredService < IMergedOptionsStore > ( ) ;
83
+ MergedOptions mergedOptions = optionsMonitor . Get ( key ) ;
84
+
85
+
87
86
MergedOptions . UpdateMergedOptionsFromMicrosoftIdentityApplicationOptions ( MicrosoftIdentityApplicationOptions , mergedOptions ) ;
88
- tokenAcquirer = GetTokenAcquirer ( key ) ;
89
- }
90
- return tokenAcquirer ;
87
+ return MakeTokenAcquirer ( key ) ;
88
+ } ) ;
91
89
}
92
90
93
91
/// <inheritdoc/>
94
92
public ITokenAcquirer GetTokenAcquirer ( string authenticationScheme = "" )
93
+ {
94
+ return _authSchemes . GetOrAdd ( authenticationScheme , ( key ) =>
95
+ {
96
+ return MakeTokenAcquirer ( authenticationScheme ) ;
97
+ } ) ;
98
+ }
99
+
100
+ private ITokenAcquirer MakeTokenAcquirer ( string authenticationScheme = "" )
95
101
{
96
102
CheckServiceProviderNotNull ( ) ;
97
103
98
- ITokenAcquirer ? acquirer ;
99
- if ( ! _authSchemes . TryGetValue ( authenticationScheme , out acquirer ) )
100
- {
101
- var tokenAcquisition = ServiceProvider ! . GetRequiredService < ITokenAcquisition > ( ) ;
102
- acquirer = new TokenAcquirer ( tokenAcquisition , authenticationScheme ) ;
103
- _authSchemes . Add ( authenticationScheme , acquirer ) ;
104
- }
105
- return acquirer ;
104
+ ITokenAcquisition tokenAcquisition = ServiceProvider ! . GetRequiredService < ITokenAcquisition > ( ) ;
105
+ return new TokenAcquirer ( tokenAcquisition , authenticationScheme ) ;
106
106
}
107
+
107
108
private void CheckServiceProviderNotNull ( )
108
109
{
109
110
if ( ServiceProvider == null )
@@ -112,10 +113,9 @@ private void CheckServiceProviderNotNull()
112
113
}
113
114
}
114
115
115
-
116
- private static string GetKey ( string ? authority , string ? clientId )
116
+ public static string GetKey ( string ? authority , string ? clientId , string ? region )
117
117
{
118
- return $ "{ authority } { clientId } ";
118
+ return $ "{ authority } { clientId } { region } ";
119
119
}
120
120
}
121
121
}
0 commit comments