88using System . Security . Claims ;
99using System . Text . Encodings . Web ;
1010using System . Threading . Tasks ;
11- using IdentityModel . AspNetCore . OAuth2Introspection . Infrastructure ;
1211using IdentityModel . Client ;
1312using Microsoft . AspNetCore . Authentication ;
13+ using Microsoft . AspNetCore . Http ;
1414using Microsoft . Extensions . Caching . Distributed ;
1515using Microsoft . Extensions . Logging ;
1616using Microsoft . Extensions . Options ;
@@ -25,8 +25,8 @@ public class OAuth2IntrospectionHandler : AuthenticationHandler<OAuth2Introspect
2525 private readonly IDistributedCache _cache ;
2626 private readonly ILogger < OAuth2IntrospectionHandler > _logger ;
2727
28- static readonly ConcurrentDictionary < string , Lazy < Task < AuthenticateResult > > > IntrospectionDictionary =
29- new ConcurrentDictionary < string , Lazy < Task < AuthenticateResult > > > ( ) ;
28+ static readonly ConcurrentDictionary < string , Lazy < Task < TokenIntrospectionResponse > > > IntrospectionDictionary =
29+ new ConcurrentDictionary < string , Lazy < Task < TokenIntrospectionResponse > > > ( ) ;
3030
3131 /// <summary>
3232 /// Initializes a new instance of the <see cref="OAuth2IntrospectionHandler"/> class.
@@ -94,10 +94,10 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
9494 var isInActive = claims . FirstOrDefault ( c => string . Equals ( c . Type , "active" , StringComparison . OrdinalIgnoreCase ) && string . Equals ( c . Value , "false" , StringComparison . OrdinalIgnoreCase ) ) ;
9595 if ( isInActive != null )
9696 {
97- return await ReportNonSuccessAndReturn ( "Cached token is not active." ) ;
97+ return await ReportNonSuccessAndReturn ( "Cached token is not active." , Context , Scheme , Events , Options ) ;
9898 }
9999
100- return await CreateTicket ( claims , token ) ;
100+ return await CreateTicket ( claims , token , Context , Scheme , Events , Options ) ;
101101 }
102102
103103 _logger . LogTrace ( "Token is not cached." ) ;
@@ -108,58 +108,64 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
108108 // with the same token come in at the same time
109109 try
110110 {
111- return await IntrospectionDictionary . GetOrAdd ( token , _ =>
111+ Lazy < Task < TokenIntrospectionResponse > > GetTokenIntrospectionResponseLazy ( string _ )
112112 {
113- return new Lazy < Task < AuthenticateResult > > ( async ( ) =>
113+ return new Lazy < Task < TokenIntrospectionResponse > > ( async ( ) => await LoadClaimsForToken ( token , Options ) ) ;
114+ }
115+
116+ var response = await IntrospectionDictionary
117+ . GetOrAdd ( token , GetTokenIntrospectionResponseLazy )
118+ . Value ;
119+
120+ if ( response . IsError )
121+ {
122+ _logger . LogError ( "Error returned from introspection endpoint: " + response . Error ) ;
123+ return await ReportNonSuccessAndReturn ( "Error returned from introspection endpoint: " + response . Error , Context , Scheme , Events , Options ) ;
124+ }
125+
126+ if ( response . IsActive )
127+ {
128+ if ( Options . EnableCaching )
129+ {
130+ await _cache . SetClaimsAsync ( Options . CacheKeyPrefix , token , response . Claims , Options . CacheDuration , _logger ) . ConfigureAwait ( false ) ;
131+ }
132+
133+ return await CreateTicket ( response . Claims , token , Context , Scheme , Events , Options ) ;
134+ }
135+ else
136+ {
137+ if ( Options . EnableCaching )
114138 {
115- var response = await LoadClaimsForToken ( token ) ;
116-
117- if ( response . IsError )
118- {
119- _logger . LogError ( "Error returned from introspection endpoint: " + response . Error ) ;
120- return await ReportNonSuccessAndReturn ( "Error returned from introspection endpoint: " + response . Error ) ;
121- }
122-
123- if ( response . IsActive )
124- {
125- if ( Options . EnableCaching )
126- {
127- await _cache . SetClaimsAsync ( Options . CacheKeyPrefix , token , response . Claims , Options . CacheDuration , _logger ) . ConfigureAwait ( false ) ;
128- }
129-
130- return await CreateTicket ( response . Claims , token ) ;
131- }
132- else
133- {
134- if ( Options . EnableCaching )
135- {
136- // add an exp claim - otherwise caching will not work
137- var claimsWithExp = response . Claims . ToList ( ) ;
138- claimsWithExp . Add ( new Claim ( "exp" ,
139- DateTimeOffset . UtcNow . Add ( Options . CacheDuration ) . ToUnixTimeSeconds ( ) . ToString ( ) ) ) ;
140- await _cache . SetClaimsAsync ( Options . CacheKeyPrefix , token , claimsWithExp , Options . CacheDuration , _logger )
141- . ConfigureAwait ( false ) ;
142- }
143-
144- return await ReportNonSuccessAndReturn ( "Token is not active." ) ;
145- }
146- } ) ;
147- } ) . Value ;
139+ // add an exp claim - otherwise caching will not work
140+ var claimsWithExp = response . Claims . ToList ( ) ;
141+ claimsWithExp . Add ( new Claim ( "exp" ,
142+ DateTimeOffset . UtcNow . Add ( Options . CacheDuration ) . ToUnixTimeSeconds ( ) . ToString ( ) ) ) ;
143+ await _cache . SetClaimsAsync ( Options . CacheKeyPrefix , token , claimsWithExp , Options . CacheDuration , _logger )
144+ . ConfigureAwait ( false ) ;
145+ }
146+
147+ return await ReportNonSuccessAndReturn ( "Token is not active." , Context , Scheme , Events , Options ) ;
148+ }
148149 }
149150 finally
150151 {
151152 IntrospectionDictionary . TryRemove ( token , out _ ) ;
152153 }
153154 }
154155
155- private async Task < AuthenticateResult > ReportNonSuccessAndReturn ( string error )
156+ private static async Task < AuthenticateResult > ReportNonSuccessAndReturn (
157+ string error ,
158+ HttpContext httpContext ,
159+ AuthenticationScheme scheme ,
160+ OAuth2IntrospectionEvents events ,
161+ OAuth2IntrospectionOptions options )
156162 {
157- var authenticationFailedContext = new AuthenticationFailedContext ( Context , Scheme , Options )
163+ var authenticationFailedContext = new AuthenticationFailedContext ( httpContext , scheme , options )
158164 {
159165 Error = error
160166 } ;
161167
162- await Events . AuthenticationFailed ( authenticationFailedContext ) ;
168+ await events . AuthenticationFailed ( authenticationFailedContext ) ;
163169
164170 if ( authenticationFailedContext . Result != null )
165171 {
@@ -169,36 +175,37 @@ private async Task<AuthenticateResult> ReportNonSuccessAndReturn(string error)
169175 return AuthenticateResult . Fail ( error ) ;
170176 }
171177
172- private AsyncLazy < TokenIntrospectionResponse > CreateLazyIntrospection ( string token )
173- {
174- return new AsyncLazy < TokenIntrospectionResponse > ( ( ) => LoadClaimsForToken ( token ) ) ;
175- }
176-
177- private async Task < TokenIntrospectionResponse > LoadClaimsForToken ( string token )
178+ private static async Task < TokenIntrospectionResponse > LoadClaimsForToken ( string token , OAuth2IntrospectionOptions options )
178179 {
179- var introspectionClient = await Options . IntrospectionClient . Value . ConfigureAwait ( false ) ;
180- return await introspectionClient . Introspect ( token , Options . TokenTypeHint ) . ConfigureAwait ( false ) ;
180+ var introspectionClient = await options . IntrospectionClient . Value . ConfigureAwait ( false ) ;
181+ return await introspectionClient . Introspect ( token , options . TokenTypeHint ) . ConfigureAwait ( false ) ;
181182 }
182183
183- private async Task < AuthenticateResult > CreateTicket ( IEnumerable < Claim > claims , string token )
184+ private static async Task < AuthenticateResult > CreateTicket (
185+ IEnumerable < Claim > claims ,
186+ string token ,
187+ HttpContext httpContext ,
188+ AuthenticationScheme scheme ,
189+ OAuth2IntrospectionEvents events ,
190+ OAuth2IntrospectionOptions options )
184191 {
185- var authenticationType = Options . AuthenticationType ?? Scheme . Name ;
186- var id = new ClaimsIdentity ( claims , authenticationType , Options . NameClaimType , Options . RoleClaimType ) ;
192+ var authenticationType = options . AuthenticationType ?? scheme . Name ;
193+ var id = new ClaimsIdentity ( claims , authenticationType , options . NameClaimType , options . RoleClaimType ) ;
187194 var principal = new ClaimsPrincipal ( id ) ;
188195
189- var tokenValidatedContext = new TokenValidatedContext ( Context , Scheme , Options )
196+ var tokenValidatedContext = new TokenValidatedContext ( httpContext , scheme , options )
190197 {
191198 Principal = principal ,
192199 SecurityToken = token
193200 } ;
194201
195- await Events . TokenValidated ( tokenValidatedContext ) ;
202+ await events . TokenValidated ( tokenValidatedContext ) ;
196203 if ( tokenValidatedContext . Result != null )
197204 {
198205 return tokenValidatedContext . Result ;
199206 }
200207
201- if ( Options . SaveToken )
208+ if ( options . SaveToken )
202209 {
203210 tokenValidatedContext . Properties . StoreTokens ( new [ ]
204211 {
0 commit comments