11
11
using Microsoft . Extensions . Options ;
12
12
using Notifo . Domain . Apps ;
13
13
14
+ #pragma warning disable RECS0082 // Parameter has the same name as a member and hides it
15
+ #pragma warning disable SA1313 // Parameter names should begin with lower-case letter
16
+
14
17
namespace Notifo . Identity . Dynamic ;
15
18
16
19
public sealed class DynamicSchemeProvider : AuthenticationSchemeProvider , IOptionsMonitor < DynamicOpenIdConnectOptions >
@@ -19,23 +22,34 @@ public sealed class DynamicSchemeProvider : AuthenticationSchemeProvider, IOptio
19
22
20
23
private readonly IAppStore appStore ;
21
24
private readonly IHttpContextAccessor httpContextAccessor ;
25
+ private readonly IConfigurationStore < AppAuthScheme > temporarySchemes ;
22
26
private readonly OpenIdConnectPostConfigureOptions configure ;
23
27
24
28
public DynamicOpenIdConnectOptions CurrentValue => null ! ;
25
29
26
- public DynamicSchemeProvider ( IAppStore appStore , IHttpContextAccessor httpContextAccessor ,
30
+ private sealed record SchemeResult ( AuthenticationScheme Scheme , DynamicOpenIdConnectOptions Options ) ;
31
+
32
+ public DynamicSchemeProvider (
33
+ IAppStore appStore ,
34
+ IHttpContextAccessor httpContextAccessor ,
35
+ IConfigurationStore < AppAuthScheme > temporarySchemes ,
27
36
OpenIdConnectPostConfigureOptions configure ,
28
37
IOptions < AuthenticationOptions > options )
29
38
: base ( options )
30
39
{
31
40
this . appStore = appStore ;
32
41
this . httpContextAccessor = httpContextAccessor ;
42
+ this . temporarySchemes = temporarySchemes ;
33
43
this . configure = configure ;
34
44
}
35
45
36
- public Task < bool > HasCustomSchemeAsync ( )
46
+ public async Task < string > AddTemporarySchemeAsync ( AppAuthScheme scheme ,
47
+ CancellationToken ct = default )
37
48
{
38
- return appStore . AnyAuthDomainAsync ( default ) ;
49
+ var id = Guid . NewGuid ( ) . ToString ( ) ;
50
+
51
+ await temporarySchemes . SetAsync ( id , scheme , TimeSpan . FromMinutes ( 10 ) , ct ) ;
52
+ return id ;
39
53
}
40
54
41
55
public async Task < AuthenticationScheme ? > GetSchemaByEmailAddressAsync ( string email )
@@ -64,7 +78,7 @@ public Task<bool> HasCustomSchemeAsync()
64
78
65
79
public override async Task < AuthenticationScheme ? > GetSchemeAsync ( string name )
66
80
{
67
- var result = await GetSchemeCoreAsync ( name ) ;
81
+ var result = await GetSchemeCoreAsync ( name , default ) ;
68
82
69
83
if ( result != null )
70
84
{
@@ -98,7 +112,8 @@ public override async Task<IEnumerable<AuthenticationScheme>> GetRequestHandlerS
98
112
{
99
113
var name = lastSegment [ prefix . Length ..] ;
100
114
101
- var scheme = await GetSchemeCoreAsync ( name ) ;
115
+ var scheme = await GetSchemeCoreAsync ( name , httpContextAccessor . HttpContext . RequestAborted ) ;
116
+
102
117
if ( scheme != null )
103
118
{
104
119
result . Add ( scheme . Scheme ) ;
@@ -116,32 +131,34 @@ public DynamicOpenIdConnectOptions Get(string? name)
116
131
return new DynamicOpenIdConnectOptions ( ) ;
117
132
}
118
133
119
- var scheme = GetSchemeCoreAsync ( name ) . Result ;
134
+ var scheme = GetSchemeCoreAsync ( name , default ) . Result ;
120
135
121
136
return scheme ? . Options ?? new DynamicOpenIdConnectOptions ( ) ;
122
137
}
123
138
124
- public IDisposable ? OnChange ( Action < DynamicOpenIdConnectOptions , string ? > listener )
139
+ private async Task < SchemeResult ? > GetSchemeCoreAsync ( string name ,
140
+ CancellationToken ct )
125
141
{
126
- return null ;
127
- }
142
+ if ( ! Guid . TryParse ( name , out _ ) )
143
+ {
144
+ return null ;
145
+ }
128
146
129
- private async Task < SchemeResult ? > GetSchemeCoreAsync ( string name )
130
- {
131
147
var cacheKey = ( "DYNAMIC_SCHEME" , name ) ;
132
148
133
149
if ( httpContextAccessor . HttpContext ? . Items . TryGetValue ( cacheKey , out var cached ) == true )
134
150
{
135
151
return cached as SchemeResult ;
136
152
}
137
153
138
- var app = await appStore . GetAsync ( name , default ) ;
154
+ var scheme =
155
+ await GetSchemeByAppAsync ( name , ct ) ??
156
+ await GetSchemeByTempNameAsync ( name , ct ) ;
139
157
140
- var result = ( SchemeResult ? ) null ;
141
- if ( app ? . AuthScheme != null )
142
- {
143
- result = CreateScheme ( app . Id , app . AuthScheme ) ;
144
- }
158
+ var result =
159
+ scheme != null ?
160
+ CreateScheme ( name , scheme ) :
161
+ null ;
145
162
146
163
if ( httpContextAccessor . HttpContext != null )
147
164
{
@@ -151,13 +168,29 @@ public DynamicOpenIdConnectOptions Get(string? name)
151
168
return result ;
152
169
}
153
170
171
+ private async Task < AppAuthScheme ? > GetSchemeByAppAsync ( string name ,
172
+ CancellationToken ct )
173
+ {
174
+ var app = await appStore . GetByAuthDomainAsync ( name , ct ) ;
175
+
176
+ return app ? . AuthScheme ;
177
+ }
178
+
179
+ private async Task < AppAuthScheme ? > GetSchemeByTempNameAsync ( string name ,
180
+ CancellationToken ct )
181
+ {
182
+ var scheme = await temporarySchemes . GetAsync ( name , ct ) ;
183
+
184
+ return scheme ;
185
+ }
186
+
154
187
private SchemeResult CreateScheme ( string name , AppAuthScheme config )
155
188
{
156
189
var scheme = new AuthenticationScheme ( name , config . DisplayName , typeof ( DynamicOpenIdConnectHandler ) ) ;
157
190
158
191
var options = new DynamicOpenIdConnectOptions
159
192
{
160
- Events = new OidcHandler ( new OdicOptions
193
+ Events = new OidcHandler ( new OidcOptions
161
194
{
162
195
SignoutRedirectUrl = config . SignoutRedirectUrl
163
196
} ) ,
@@ -176,9 +209,8 @@ private SchemeResult CreateScheme(string name, AppAuthScheme config)
176
209
return new SchemeResult ( scheme , options ) ;
177
210
}
178
211
179
- #pragma warning disable RECS0082 // Parameter has the same name as a member and hides it
180
- #pragma warning disable SA1313 // Parameter names should begin with lower-case letter
181
- private sealed record SchemeResult ( AuthenticationScheme Scheme , DynamicOpenIdConnectOptions Options ) ;
182
- #pragma warning restore SA1313 // Parameter names should begin with lower-case letter
183
- #pragma warning restore RECS0082 // Parameter has the same name as a member and hides it
212
+ public IDisposable ? OnChange ( Action < DynamicOpenIdConnectOptions , string ? > listener )
213
+ {
214
+ return null ;
215
+ }
184
216
}
0 commit comments