/// <inheritdoc/> public async ValueTask HandleAsync(ProcessAuthenticationContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (context.AccessTokenPrincipal is not null) { return; } if (string.IsNullOrEmpty(context.AccessToken)) { if (context.RequireAccessToken) { context.Reject( error: Errors.MissingToken, description: SR.GetResourceString(SR.ID2000), uri: SR.FormatID8000(SR.ID2000)); return; } return; } var notification = new ValidateTokenContext(context.Transaction) { Token = context.AccessToken, ValidTokenTypes = { TokenTypeHints.AccessToken } }; await _dispatcher.DispatchAsync(notification); if (notification.IsRequestHandled) { context.HandleRequest(); return; } else if (notification.IsRequestSkipped) { context.SkipRequest(); return; } else if (notification.IsRejected) { context.Reject( error: notification.Error ?? Errors.InvalidRequest, description: notification.ErrorDescription, uri: notification.ErrorUri); return; } context.AccessTokenPrincipal = notification.Principal; }
/// <inheritdoc/> public ValueTask HandleAsync(ValidateTokenContext context) { // If a principal was already attached, don't overwrite it. if (context.Principal is not null) { return(default);
public async Task <FinishSsoResult> FinishSsoAsync(HttpContext context) { if (!TryGetSamlResponse(context, out var response, out var binding)) { throw new InvalidOperationException("Bad request."); } Logger.LogInformation("Finishing SAML2P authentication (SP flow)."); Trace($"Received SAMLResponse using {binding} binding.", response); var partnerId = response.Issuer; var partner = await Partners.GetIdentityProviderAsync(partnerId); if (partner == null) { throw new SecurityException($"Partner idp '{partnerId}' not found."); } if (!partner.Enabled) { throw new SecurityException($"Partner idp '{partnerId}' is disabled."); } var request = null as AuthnRequest; if (response.InResponseTo != null) { request = await Cache.FetchRequestAsync(response.InResponseTo); await Cache.RemoveAsync(response.InResponseTo); } if (request == null && !partner.CanInitiateSso) { throw new SecurityException($"Partner idp '{partnerId}' is is not allowed to initiate SSO."); } if (request != null) { Trace("Found cached SAMLRequest.", request); if (request.RelayState != response.RelayState) { throw new SecurityException($"Mismatching relay state."); } } var ssoContext = new FinishSsoContext { PartnerId = partner.Id, Partner = partner, Request = request, Response = response }; await Events.InvokeAsync(Options, partner, e => e.OnFinishSso(context.RequestServices, ssoContext)); if (response.Status.StatusCode.Value != Saml2pConstants.Statuses.Success) { return(FinishSsoResult.Fail(partner.Id, response.Status.StatusCode.Value, response.Status.StatusCode?.SubCode.Value)); } var parameters = _factory.Create(partner); var validateContext = new ValidateTokenContext { PartnerId = partner.Id, Partner = partner, Request = request, Response = response, TokenValidationParameters = parameters, Handler = _handler }; await Events.InvokeAsync(Options, partner, e => e.OnValidatingToken(context.RequestServices, validateContext)); if (validateContext.Subject != null && validateContext.SecurityToken == null || validateContext.Subject == null && validateContext.SecurityToken != null) { Logger.LogWarning($"When manually populating '{nameof(ValidateTokenContext.Subject)}' or '{nameof(ValidateTokenContext.SecurityToken)}' properties of '{nameof(ValidateTokenContext)}', then both must be populated. Otherwise they will be ignored. Clearing values..."); validateContext.SecurityToken = null; validateContext.Subject = null; } if (validateContext.Subject == null) { Logger.LogInformation("Validating incoming token."); var subject = validateContext.Handler.ValidateToken(validateContext.Response.XmlSecurityToken, validateContext.TokenValidationParameters, out var token); var saml2 = token as Saml2SecurityToken; var now = _clock.UtcNow.DateTime; saml2.ValidateResponseToken(validateContext.Request.Id, now); validateContext.Subject = subject; validateContext.SecurityToken = saml2; } await Events.InvokeAsync(Options, partner, e => e.OnValidatedToken(context.RequestServices, validateContext)); context.User = validateContext.Subject; return(FinishSsoResult.Success(partner.Id, validateContext.SecurityToken, validateContext.Subject)); }
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { if (!Options.UseReferenceTokens) { return await base.HandleAuthenticateAsync(); } var context = new RetrieveTokenContext(Context, Scheme, Options); await Events.RetrieveToken(context); if (context.Result != null) { Logger.LogInformation("The default authentication handling was skipped from user code."); return context.Result; } var token = context.Token; if (string.IsNullOrEmpty(token)) { // Try to retrieve the access token from the authorization header. string header = Request.Headers[HeaderNames.Authorization]; if (string.IsNullOrEmpty(header)) { Logger.LogDebug("Authentication was skipped because no bearer token was received."); return AuthenticateResult.NoResult(); } // Ensure that the authorization header contains the mandatory "Bearer" scheme. // See https://tools.ietf.org/html/rfc6750#section-2.1 if (!header.StartsWith(OAuthValidationConstants.Schemes.Bearer + ' ', StringComparison.OrdinalIgnoreCase)) { Logger.LogDebug("Authentication was skipped because an incompatible " + "scheme was used in the 'Authorization' header."); return AuthenticateResult.NoResult(); } // Extract the token from the authorization header. token = header.Substring(OAuthValidationConstants.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 AuthenticateResult.NoResult(); } } // Try to unprotect the token and return an error // if the ticket can't be decrypted or validated. var result = await CreateTicketAsync(token); if (!result.Succeeded) { Context.Features.Set(new OAuthValidationFeature { Error = new OAuthValidationError { Error = OAuthValidationConstants.Errors.InvalidToken, ErrorDescription = "The access token is not valid." } }); return result; } // Ensure that the authentication ticket is still valid. var ticket = result.Ticket; if (ticket.Properties.ExpiresUtc.HasValue && ticket.Properties.ExpiresUtc.Value < Options.SystemClock.UtcNow) { Context.Features.Set(new OAuthValidationFeature { Error = new OAuthValidationError { Error = OAuthValidationConstants.Errors.InvalidToken, ErrorDescription = "The access token is no longer valid." } }); return AuthenticateResult.Fail("Authentication failed because the access token was expired."); } // Ensure that the access token was issued // to be used with this resource server. if (!ValidateAudience(ticket)) { Context.Features.Set(new OAuthValidationFeature { Error = new OAuthValidationError { Error = OAuthValidationConstants.Errors.InvalidToken, ErrorDescription = "The access token is not valid for this resource server." } }); return AuthenticateResult.Fail("Authentication failed because the access token " + "was not valid for this resource server."); } var notification = new ValidateTokenContext(Context, Scheme, Options, ticket); await Events.ValidateToken(notification); if (notification.Result != null) { Logger.LogInformation("The default authentication handling was skipped from user code."); return notification.Result; } // Optimization: avoid allocating a new AuthenticationTicket // if the principal/properties instances were not replaced. if (ReferenceEquals(notification.Principal, ticket.Principal) && ReferenceEquals(notification.Properties, ticket.Properties)) { return AuthenticateResult.Success(ticket); } return AuthenticateResult.Success(new AuthenticationTicket( notification.Principal, notification.Properties, Scheme.Name)); }
private ValueTask ValidatingToken(IServiceProvider arg1, ValidateTokenContext arg2) { return(new ValueTask()); }
/// <summary> /// Invoked when a token is to be validated, before final processing. /// </summary> public virtual Task ValidateToken(ValidateTokenContext context) => OnValidateToken(context);