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);
        }
예제 #6
0
 /// <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);