protected override async Task <AuthenticationTicket> AuthenticateCoreAsync() { var context = new RetrieveTokenContext(Context, Options); await Options.Events.RetrieveToken(context); if (context.Handled) { Logger.LogInformation("The default authentication handling was skipped from user code."); return(context.Ticket); } var token = context.Token; if (string.IsNullOrEmpty(token)) { // Try to retrieve the access token from the authorization header. var header = Request.Headers[OAuthIntrospectionConstants.Headers.Authorization]; if (string.IsNullOrEmpty(header)) { Logger.LogDebug("Authentication was skipped because no bearer token was received."); return(null); } // Ensure that the authorization header contains the mandatory "Bearer" scheme. // See https://tools.ietf.org/html/rfc6750#section-2.1 if (!header.StartsWith(OAuthIntrospectionConstants.Schemes.Bearer + ' ', StringComparison.OrdinalIgnoreCase)) { Logger.LogDebug("Authentication was skipped because an incompatible " + "scheme was used in the 'Authorization' header."); return(null); } // Extract the token from the authorization header. token = header.Substring(OAuthIntrospectionConstants.Schemes.Bearer.Length + 1).Trim(); if (string.IsNullOrEmpty(token)) { Logger.LogDebug("Authentication was skipped because the bearer token " + "was missing from the 'Authorization' header."); return(null); } } // Try to resolve the authentication ticket from the distributed cache. If none // can be found, a new introspection request is sent to the authorization server. var ticket = await RetrieveTicketAsync(token); if (ticket == null) { // Return a failed authentication result if the introspection // request failed or if the "active" claim was false. var payload = await GetIntrospectionPayloadAsync(token); if (payload == null || !payload.Value <bool>(OAuthIntrospectionConstants.Claims.Active)) { Logger.LogError("Authentication failed because the authorization " + "server rejected the access token."); Context.Set(typeof(OAuthIntrospectionError).FullName, new OAuthIntrospectionError { Error = OAuthIntrospectionConstants.Errors.InvalidToken, ErrorDescription = "The access token is not valid." }); return(null); } // Create a new authentication ticket from the introspection // response returned by the authorization server. ticket = await CreateTicketAsync(token, payload); Debug.Assert(ticket != null); await StoreTicketAsync(token, ticket); } // Ensure that the token can be used as an access token. if (!ValidateTokenUsage(ticket)) { Logger.LogError("Authentication failed because the token was not an access token."); Context.Set(typeof(OAuthIntrospectionError).FullName, new OAuthIntrospectionError { Error = OAuthIntrospectionConstants.Errors.InvalidToken, ErrorDescription = "The access token is not valid." }); return(null); } // Ensure that the authentication ticket is still valid. if (ticket.Properties.ExpiresUtc.HasValue && ticket.Properties.ExpiresUtc.Value < Options.SystemClock.UtcNow) { Logger.LogError("Authentication failed because the access token was expired."); Context.Set(typeof(OAuthIntrospectionError).FullName, new OAuthIntrospectionError { Error = OAuthIntrospectionConstants.Errors.InvalidToken, ErrorDescription = "The access token is no longer valid." }); return(null); } // Ensure that the access token was issued // to be used with this resource server. if (!ValidateAudience(ticket)) { Logger.LogError("Authentication failed because the access token " + "was not valid for this resource server."); Context.Set(typeof(OAuthIntrospectionError).FullName, new OAuthIntrospectionError { Error = OAuthIntrospectionConstants.Errors.InvalidToken, ErrorDescription = "The access token is not valid for this resource server." }); return(null); } var notification = new ValidateTokenContext(Context, Options, ticket); await Options.Events.ValidateToken(notification); // Allow the application code to replace the ticket // reference from the ValidateToken event. return(notification.Ticket); }
/// <summary> /// Invoked when a token is to be parsed from a newly-received request. /// </summary> public virtual Task RetrieveToken(RetrieveTokenContext context) => OnRetrieveToken(context);