Beispiel #1
0
        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);