private async Task <string> SerializeAuthorizationCodeAsync( ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) { // Note: claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. // Create a new ticket containing the updated properties. var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); ticket.Properties.IssuedUtc = Options.SystemClock.UtcNow; ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc + (ticket.GetAuthorizationCodeLifetime() ?? Options.AuthorizationCodeLifetime); ticket.SetUsage(OpenIdConnectConstants.Usages.AuthorizationCode); // Associate a random identifier with the authorization code. ticket.SetTicketId(Guid.NewGuid().ToString()); // By default, add the client_id to the list of the // presenters allowed to use the authorization code. if (!string.IsNullOrEmpty(request.ClientId)) { ticket.SetPresenters(request.ClientId); } var notification = new SerializeAuthorizationCodeContext(Context, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; await Options.Provider.SerializeAuthorizationCode(notification); if (notification.HandledResponse || !string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } else if (notification.Skipped) { return(null); } if (!ReferenceEquals(ticket, notification.Ticket)) { throw new InvalidOperationException("The authentication ticket cannot be replaced."); } if (notification.DataFormat == null) { return(null); } return(notification.DataFormat.Protect(ticket)); }
private async Task <string> SerializeAuthorizationCodeAsync( ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) { // Note: claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. // Create a new ticket containing the updated properties. var ticket = new AuthenticationTicket(principal, properties, Scheme.Name); ticket.Properties.IssuedUtc = Options.SystemClock.UtcNow; ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc; ticket.Properties.ExpiresUtc += ticket.GetAuthorizationCodeLifetime() ?? Options.AuthorizationCodeLifetime; // Associate a random identifier with the authorization code. ticket.SetTokenId(Guid.NewGuid().ToString()); // Store the code_challenge, code_challenge_method and nonce parameters for later comparison. ticket.SetProperty(OpenIdConnectConstants.Properties.CodeChallenge, request.CodeChallenge) .SetProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod, request.CodeChallengeMethod) .SetProperty(OpenIdConnectConstants.Properties.Nonce, request.Nonce); // Store the original redirect_uri sent by the client application for later comparison. ticket.SetProperty(OpenIdConnectConstants.Properties.OriginalRedirectUri, request.GetProperty <string>(OpenIdConnectConstants.Properties.OriginalRedirectUri)); // Remove the unwanted properties from the authentication ticket. ticket.RemoveProperty(OpenIdConnectConstants.Properties.AuthorizationCodeLifetime) .RemoveProperty(OpenIdConnectConstants.Properties.TokenUsage); var notification = new SerializeAuthorizationCodeContext(Context, Scheme, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; await Provider.SerializeAuthorizationCode(notification); if (notification.IsHandled || !string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } if (notification.DataFormat == null) { throw new InvalidOperationException("A data formatter must be provided."); } var result = notification.DataFormat.Protect(ticket); Logger.LogTrace("A new authorization code was successfully generated using " + "the specified data format: {Code} ; {Claims} ; {Properties}.", result, ticket.Principal.Claims, ticket.Properties.Items); return(result); }
private async Task <string> SerializeAuthorizationCodeAsync( ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) { // Note: claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. // Create a new ticket containing the updated properties. var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); ticket.Properties.IssuedUtc = Options.SystemClock.UtcNow; ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc + (ticket.GetAuthorizationCodeLifetime() ?? Options.AuthorizationCodeLifetime); ticket.SetUsage(OpenIdConnectConstants.Usages.AuthorizationCode); // Associate a random identifier with the authorization code. ticket.SetTicketId(Guid.NewGuid().ToString()); // Store the code_challenge, code_challenge_method and nonce parameters for later comparison. ticket.SetProperty(OpenIdConnectConstants.Properties.CodeChallenge, request.CodeChallenge) .SetProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod, request.CodeChallengeMethod) .SetProperty(OpenIdConnectConstants.Properties.Nonce, request.Nonce); // Store the original redirect_uri sent by the client application for later comparison. ticket.SetProperty(OpenIdConnectConstants.Properties.RedirectUri, request.GetProperty <string>(OpenIdConnectConstants.Properties.OriginalRedirectUri)); // Remove the unwanted properties from the authentication ticket. ticket.RemoveProperty(OpenIdConnectConstants.Properties.AuthorizationCodeLifetime) .RemoveProperty(OpenIdConnectConstants.Properties.ClientId); var notification = new SerializeAuthorizationCodeContext(Context, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; await Options.Provider.SerializeAuthorizationCode(notification); if (notification.HandledResponse || !string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } else if (notification.Skipped) { return(null); } if (!ReferenceEquals(ticket, notification.Ticket)) { throw new InvalidOperationException("The authentication ticket cannot be replaced."); } if (notification.DataFormat == null) { return(null); } return(notification.DataFormat.Protect(ticket)); }
private async Task <string> SerializeAuthorizationCodeAsync( ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectMessage request, OpenIdConnectMessage response) { try { // properties.IssuedUtc and properties.ExpiresUtc // should always be preferred when explicitly set. if (properties.IssuedUtc == null) { properties.IssuedUtc = Options.SystemClock.UtcNow; } if (properties.ExpiresUtc == null) { properties.ExpiresUtc = properties.IssuedUtc + Options.AuthorizationCodeLifetime; } properties.SetUsage(OpenIdConnectConstants.Usages.Code); // Claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); var notification = new SerializeAuthorizationCodeContext(Context, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; // Sets the default authorization code serializer. notification.Serializer = payload => { return(Task.FromResult(notification.DataFormat?.Protect(payload))); }; await Options.Provider.SerializeAuthorizationCode(notification); // Treat a non-null authorization code like an implicit HandleResponse call. if (notification.HandledResponse || !string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } else if (notification.Skipped) { return(null); } // Allow the application to change the authentication // ticket from the SerializeAuthorizationCode event. ticket = notification.AuthenticationTicket; ticket.Properties.CopyTo(properties); var key = GenerateKey(256 / 8); using (var stream = new MemoryStream()) using (var writter = new StreamWriter(stream)) { writter.Write(await notification.SerializeTicketAsync()); writter.Flush(); await Options.Cache.SetAsync(key, options => { options.AbsoluteExpiration = ticket.Properties.ExpiresUtc; return(stream.ToArray()); }); } return(key); } catch (Exception exception) { Logger.LogWarning("An exception occured when serializing an authorization code.", exception); return(null); } }
private async Task <string> SerializeAuthorizationCodeAsync( ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectMessage request, OpenIdConnectMessage response) { // properties.IssuedUtc and properties.ExpiresUtc // should always be preferred when explicitly set. if (properties.IssuedUtc == null) { properties.IssuedUtc = Options.SystemClock.UtcNow; } if (properties.ExpiresUtc == null) { properties.ExpiresUtc = properties.IssuedUtc + Options.AuthorizationCodeLifetime; } // Claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); ticket.SetUsage(OpenIdConnectConstants.Usages.Code); // By default, add the client_id to the list of the // presenters allowed to use the authorization code. if (!string.IsNullOrEmpty(request.ClientId)) { ticket.SetPresenters(request.ClientId); } var notification = new SerializeAuthorizationCodeContext(Context, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; await Options.Provider.SerializeAuthorizationCode(notification); if (!string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } if (notification.DataFormat == null) { return(null); } var key = Options.RandomNumberGenerator.GenerateKey(length: 256 / 8); using (var stream = new MemoryStream()) using (var writter = new StreamWriter(stream)) { writter.Write(notification.DataFormat.Protect(ticket)); writter.Flush(); // Serialize the authorization code. var bytes = stream.ToArray(); // Store the authorization code in the distributed cache. await Options.Cache.SetAsync($"asos-authorization-code:{key}", bytes, new DistributedCacheEntryOptions { AbsoluteExpiration = ticket.Properties.ExpiresUtc }); } return(key); }
/// <summary> /// Called to create a new authorization code. An application may use this context /// to replace the authentication ticket before it is serialized or to use its own code store /// and 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 SerializeAuthorizationCode(SerializeAuthorizationCodeContext context) => OnSerializeAuthorizationCode(context);
/// <summary> /// Called to create a new authorization code. An application may use this context /// to replace the authentication ticket before it is serialized or to use its own code store /// and 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 SerializeAuthorizationCode(SerializeAuthorizationCodeContext context) => OnSerializeAuthorizationCode(context);