private async Task <AuthenticationTicket> DeserializeAccessTokenAsync(string token, OpenIdConnectRequest request) { var notification = new DeserializeAccessTokenContext(Context, Options, request, token) { DataFormat = Options.AccessTokenFormat, SecurityTokenHandler = Options.AccessTokenHandler }; // Note: ValidateAudience and ValidateLifetime are always set to false: // if necessary, the audience and the expiration can be validated // in InvokeIntrospectionEndpointAsync or InvokeTokenEndpointAsync. notification.TokenValidationParameters = new TokenValidationParameters { IssuerSigningKeys = Options.SigningCredentials.Select(credentials => credentials.Key), NameClaimType = OpenIdConnectConstants.Claims.Name, RoleClaimType = OpenIdConnectConstants.Claims.Role, ValidIssuer = Context.GetIssuer(Options), ValidateAudience = false, ValidateLifetime = false }; await Options.Provider.DeserializeAccessToken(notification); if (notification.HandledResponse || notification.Ticket != null) { notification.Ticket.SetUsage(OpenIdConnectConstants.Usages.AccessToken); return(notification.Ticket); } else if (notification.Skipped) { return(null); } var handler = notification.SecurityTokenHandler as ISecurityTokenValidator; if (handler == null) { return(notification.DataFormat?.Unprotect(token)); } SecurityToken securityToken; ClaimsPrincipal principal; try { if (!handler.CanReadToken(token)) { Logger.LogDebug("The access token handler refused to read the token: {Token}", token); return(null); } principal = handler.ValidateToken(token, notification.TokenValidationParameters, out securityToken); } catch (Exception exception) { Logger.LogDebug("An exception occured when deserializing an identity token: {Message}.", exception.Message); return(null); } // Parameters stored in AuthenticationProperties are lost // when the identity token is serialized using a security token handler. // To mitigate that, they are inferred from the claims or the security token. var properties = new AuthenticationProperties { ExpiresUtc = securityToken.ValidTo, IssuedUtc = securityToken.ValidFrom }; var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); var audiences = principal.FindAll(OpenIdConnectConstants.Claims.Audience); if (audiences.Any()) { ticket.SetAudiences(audiences.Select(claim => claim.Value)); } var presenters = principal.FindAll(OpenIdConnectConstants.Claims.AuthorizedParty); if (presenters.Any()) { ticket.SetPresenters(presenters.Select(claim => claim.Value)); } var scopes = principal.FindAll(OpenIdConnectConstants.Claims.Scope); if (scopes.Any()) { ticket.SetScopes(scopes.Select(claim => claim.Value)); } var identifier = principal.FindFirst(OpenIdConnectConstants.Claims.JwtId); if (identifier != null) { ticket.SetTicketId(identifier.Value); } var usage = principal.FindFirst(OpenIdConnectConstants.Claims.Usage); if (usage != null) { ticket.SetUsage(usage.Value); } var confidentiality = principal.FindFirst(OpenIdConnectConstants.Claims.ConfidentialityLevel); if (confidentiality != null) { ticket.SetProperty(OpenIdConnectConstants.Properties.ConfidentialityLevel, confidentiality.Value); } // Ensure that e received ticket is an access token. if (!ticket.IsAccessToken()) { Logger.LogDebug("The received token was not an access token: {Token}.", token); return(null); } return(ticket); }
private async Task <AuthenticationTicket> DeserializeAccessTokenAsync(string token, OpenIdConnectMessage request) { try { var notification = new DeserializeAccessTokenContext(Context, Options, request, token) { DataFormat = Options.AccessTokenFormat, Issuer = Context.GetIssuer(Options), SecurityTokenHandler = Options.AccessTokenHandler, SignatureProvider = Options.SignatureProvider, SigningKey = Options.SigningCredentials.Select(credentials => credentials.Key).FirstOrDefault() }; // Sets the default deserializer used to resolve the // authentication ticket corresponding to the access token. notification.Deserializer = payload => { var handler = notification.SecurityTokenHandler as ISecurityTokenValidator; if (handler == null) { return(Task.FromResult(notification.DataFormat?.Unprotect(payload))); } // Create new validation parameters to validate the security token. // ValidateAudience and ValidateLifetime are always set to false: // if necessary, the audience and the expiration can be validated // in InvokeValidationEndpointAsync or InvokeTokenEndpointAsync. var parameters = new TokenValidationParameters { IssuerSigningKey = notification.SigningKey, ValidIssuer = notification.Issuer, ValidateAudience = false, ValidateLifetime = false }; SecurityToken securityToken; var principal = handler.ValidateToken(payload, parameters, out securityToken); // Parameters stored in AuthenticationProperties are lost // when the identity token is serialized using a security token handler. // To mitigate that, they are inferred from the claims or the security token. var properties = new AuthenticationProperties { ExpiresUtc = securityToken.ValidTo, IssuedUtc = securityToken.ValidFrom }; var audiences = principal.FindAll(JwtRegisteredClaimNames.Aud); if (audiences.Any()) { properties.SetAudiences(audiences.Select(claim => claim.Value)); } var usage = principal.FindFirst(OpenIdConnectConstants.Extra.Usage); if (usage != null) { properties.SetUsage(usage.Value); } if (principal.Claims.Any(claim => claim.Type == OpenIdConnectConstants.Extra.Confidential)) { properties.Items[OpenIdConnectConstants.Extra.Confidential] = "true"; } return(Task.FromResult(new AuthenticationTicket(principal, properties, Options.AuthenticationScheme))); }; await Options.Provider.DeserializeAccessToken(notification); // Directly return the authentication ticket if one // has been provided by DeserializeAccessToken. // Treat a non-null ticket like an implicit HandleResponse call. if (notification.HandledResponse || notification.AuthenticationTicket != null) { if (notification.AuthenticationTicket == null) { return(null); } // Ensure the received ticket is an access token. if (!notification.AuthenticationTicket.IsAccessToken()) { Logger.LogVerbose("The received token was not an access token: {0}.", token); return(null); } return(notification.AuthenticationTicket); } else if (notification.Skipped) { return(null); } var ticket = await notification.DeserializeTicketAsync(token); if (ticket == null) { return(null); } // Ensure the received ticket is an access token. if (!ticket.IsAccessToken()) { Logger.LogVerbose("The received token was not an access token: {0}.", token); return(null); } return(ticket); } catch (Exception exception) { Logger.LogWarning("An exception occured when deserializing an access token.", exception); return(null); } }
private async Task <AuthenticationTicket> DeserializeAccessTokenAsync(string token, OpenIdConnectRequest request) { var notification = new DeserializeAccessTokenContext(Context, Scheme, Options, request, token) { DataFormat = Options.AccessTokenFormat, SecurityTokenHandler = Options.AccessTokenHandler }; // Note: ValidateAudience and ValidateLifetime are always set to false: // if necessary, the audience and the expiration can be validated // in InvokeIntrospectionEndpointAsync or InvokeTokenEndpointAsync. notification.TokenValidationParameters = new TokenValidationParameters { IssuerSigningKeys = Options.SigningCredentials.Select(credentials => credentials.Key), NameClaimType = OpenIdConnectConstants.Claims.Name, RoleClaimType = OpenIdConnectConstants.Claims.Role, TokenDecryptionKeys = Options.EncryptingCredentials.Select(credentials => credentials.Key) .Where(key => key is SymmetricSecurityKey), ValidIssuer = Context.GetIssuer(Options), ValidateAudience = false, ValidateLifetime = false }; await Provider.DeserializeAccessToken(notification); if (notification.IsHandled || notification.Ticket != null) { notification.Ticket?.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); return(notification.Ticket); } var handler = notification.SecurityTokenHandler as ISecurityTokenValidator; if (handler == null) { if (notification.DataFormat == null) { throw new InvalidOperationException("A security token handler or data formatter must be provided."); } var value = notification.DataFormat.Unprotect(token); if (value == null) { Logger.LogTrace("The received token was invalid or malformed: {Token}.", token); return(null); } // Note: since the data formatter relies on a data protector using different "purposes" strings // per token type, the ticket returned by Unprotect() is guaranteed to be an access token. value.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken); Logger.LogTrace("The access token '{Token}' was successfully validated using " + "the specified token data format: {Claims} ; {Properties}.", token, value.Principal.Claims, value.Properties.Items); return(value); } SecurityToken securityToken; ClaimsPrincipal principal; try { if (!handler.CanReadToken(token)) { Logger.LogTrace("The access token '{Token}' was rejected by the security token handler.", token); return(null); } principal = handler.ValidateToken(token, notification.TokenValidationParameters, out securityToken); } catch (Exception exception) { Logger.LogDebug("An exception occured while deserializing an identity token: {Exception}.", exception); return(null); } // Parameters stored in AuthenticationProperties are lost // when the identity token is serialized using a security token handler. // To mitigate that, they are inferred from the claims or the security token. var properties = new AuthenticationProperties { ExpiresUtc = securityToken.ValidTo, IssuedUtc = securityToken.ValidFrom }; var ticket = new AuthenticationTicket(principal, properties, Scheme.Name) .SetAudiences(principal.FindAll(OpenIdConnectConstants.Claims.Audience).Select(claim => claim.Value)) .SetConfidentialityLevel(principal.GetClaim(OpenIdConnectConstants.Claims.ConfidentialityLevel)) .SetPresenters(principal.FindAll(OpenIdConnectConstants.Claims.AuthorizedParty).Select(claim => claim.Value)) .SetScopes(principal.FindAll(OpenIdConnectConstants.Claims.Scope).Select(claim => claim.Value)) .SetTokenId(principal.GetClaim(OpenIdConnectConstants.Claims.JwtId)) .SetTokenUsage(principal.GetClaim(OpenIdConnectConstants.Claims.TokenUsage)); // Ensure that the received ticket is an access token. if (!ticket.IsAccessToken()) { Logger.LogTrace("The received token was not an access token: {Token}.", token); return(null); } Logger.LogTrace("The access token '{Token}' was successfully validated using " + "the specified security token handler: {Claims} ; {Properties}.", token, ticket.Principal.Claims, ticket.Properties.Items); return(ticket); }
private async Task <AuthenticationTicket> DeserializeAccessTokenAsync(string token, OpenIdConnectMessage request) { var notification = new DeserializeAccessTokenContext(Context, Options, request, token) { DataFormat = Options.AccessTokenFormat, Issuer = Context.GetIssuer(Options), SecurityTokenHandler = Options.AccessTokenHandler, SigningCredentials = Options.SigningCredentials.FirstOrDefault() }; await Options.Provider.DeserializeAccessToken(notification); // Directly return the authentication ticket if one // has been provided by DeserializeAccessToken. if (notification.Ticket != null) { return(notification.Ticket); } var handler = notification.SecurityTokenHandler as ISecurityTokenValidator; if (handler == null) { return(notification.DataFormat?.Unprotect(token)); } // Create new validation parameters to validate the security token. // ValidateAudience and ValidateLifetime are always set to false: // if necessary, the audience and the expiration can be validated // in InvokeIntrospectionEndpointAsync or InvokeTokenEndpointAsync. var parameters = new TokenValidationParameters { IssuerSigningKey = notification.SigningCredentials.Key, ValidIssuer = notification.Issuer, ValidateAudience = false, ValidateLifetime = false }; SecurityToken securityToken; ClaimsPrincipal principal; try { principal = handler.ValidateToken(token, parameters, out securityToken); } catch (Exception exception) { Logger.LogDebug("An exception occured when deserializing an identity token: {Message}.", exception.Message); return(null); } // Parameters stored in AuthenticationProperties are lost // when the identity token is serialized using a security token handler. // To mitigate that, they are inferred from the claims or the security token. var properties = new AuthenticationProperties { ExpiresUtc = securityToken.ValidTo, IssuedUtc = securityToken.ValidFrom }; var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); var audiences = principal.FindAll(JwtRegisteredClaimNames.Aud); if (audiences.Any()) { ticket.SetAudiences(audiences.Select(claim => claim.Value)); } var presenters = principal.FindAll(JwtRegisteredClaimNames.Azp); if (presenters.Any()) { ticket.SetPresenters(presenters.Select(claim => claim.Value)); } var scopes = principal.FindAll(OpenIdConnectConstants.Claims.Scope); if (scopes.Any()) { ticket.SetScopes(scopes.Select(claim => claim.Value)); } var usage = principal.FindFirst(OpenIdConnectConstants.Claims.Usage); if (usage != null) { ticket.SetUsage(usage.Value); } var confidential = principal.FindFirst(OpenIdConnectConstants.Claims.Confidential); if (confidential != null && string.Equals(confidential.Value, "true", StringComparison.OrdinalIgnoreCase)) { ticket.Properties.Items[OpenIdConnectConstants.Properties.Confidential] = "true"; } // Ensure that e received ticket is an access token. if (!ticket.IsAccessToken()) { Logger.LogDebug("The received token was not an access token: {Token}.", token); return(null); } return(ticket); }
/// <summary> /// Called when receiving an access token. An application may use this context /// to deserialize the token using a custom format and to skip the default logic using /// <see cref="BaseControlContext.HandleResponse"/>. /// </summary> /// <param name="context">The context of the event carries information in and results out.</param> /// <returns>Task to enable asynchronous execution</returns> public virtual Task DeserializeAccessToken(DeserializeAccessTokenContext context) => OnDeserializeAccessToken(context);
/// <summary> /// Called when receiving an access token. An application may use this context /// to deserialize the token using a custom format and to skip the default logic using /// <see cref="BaseContext{OpenIdConnectServerOptions}.HandleResponse"/>. /// </summary> /// <param name="context">The context of the event carries information in and results out.</param> /// <returns>Task to enable asynchronous execution</returns> public virtual Task DeserializeAccessToken(DeserializeAccessTokenContext context) => OnDeserializeAccessToken(context);