public override async Task HandleAuthorizationRequest([NotNull] HandleAuthorizationRequestContext context) { var options = context.HttpContext.RequestServices.GetRequiredService <IOptions <OpenIddictOptions> >(); // If no request_id parameter can be found in the current request, assume the OpenID Connect request // was not serialized yet and store the entire payload in the distributed cache to make it easier // to flow across requests and internal/external authentication/registration workflows. if (options.Value.EnableRequestCaching && string.IsNullOrEmpty(context.Request.RequestId)) { // Generate a request identifier. Note: using a crypto-secure // random number generator is not necessary in this case. context.Request.RequestId = Guid.NewGuid().ToString(); // Store the serialized authorization request parameters in the distributed cache. var stream = new MemoryStream(); using (var writer = new BsonWriter(stream)) { writer.CloseOutput = false; var serializer = JsonSerializer.CreateDefault(); serializer.Serialize(writer, context.Request); } // Note: the cache key is always prefixed with a specific marker // to avoid collisions with the other types of cached requests. var key = OpenIddictConstants.Environment.AuthorizationRequest + context.Request.RequestId; await options.Value.Cache.SetAsync(key, stream.ToArray(), new DistributedCacheEntryOptions { AbsoluteExpiration = context.Options.SystemClock.UtcNow + TimeSpan.FromMinutes(30), SlidingExpiration = TimeSpan.FromMinutes(10) }); // Create a new authorization request containing only the request_id parameter. var address = QueryHelpers.AddQueryString( uri: context.HttpContext.Request.Scheme + "://" + context.HttpContext.Request.Host + context.HttpContext.Request.PathBase + context.HttpContext.Request.Path, name: OpenIdConnectConstants.Parameters.RequestId, value: context.Request.RequestId); context.HttpContext.Response.Redirect(address); // Mark the response as handled // to skip the rest of the pipeline. context.HandleResponse(); return; } context.SkipToNextMiddleware(); }
public override async Task HandleAuthorizationRequest([NotNull] HandleAuthorizationRequestContext context) { var services = context.HttpContext.RequestServices.GetRequiredService <OpenIddictServices <TUser, TApplication, TAuthorization, TScope, TToken> >(); if (string.Equals(context.Request.Prompt, "none", StringComparison.Ordinal)) { // Note: principal is guaranteed to be non-null since ValidateAuthorizationRequest // rejects prompt=none requests missing or having an invalid id_token_hint. var principal = await context.HttpContext.Authentication.AuthenticateAsync(context.Options.AuthenticationScheme); Debug.Assert(principal != null, "The principal extracted from the id_token_hint shouldn't be null."); // Note: user may be null if the user was removed after // the initial check made by ValidateAuthorizationRequest. var user = await services.Users.GetUserAsync(principal); if (user == null) { services.Logger.LogError("The authorization request was aborted because the profile corresponding " + "to the logged in user was not found in the database: {Identifier}.", context.HttpContext.User.GetClaim(ClaimTypes.NameIdentifier)); context.Reject( error: OpenIdConnectConstants.Errors.ServerError, description: "An internal error has occurred."); return; } // Note: filtering the username is not needed at this stage as OpenIddictController.Accept // and OpenIddictProvider.HandleTokenRequest are expected to reject requests that don't // include the "email" scope if the username corresponds to the registed email address. var identity = await services.Users.CreateIdentityAsync(user, context.Request.GetScopes()); if (identity == null) { throw new InvalidOperationException("The authorization request was aborted because the user manager returned a null " + $"identity for user '{await services.Users.GetUserNameAsync(user)}'."); } // Create a new authentication ticket holding the user identity. var ticket = new AuthenticationTicket( new ClaimsPrincipal(identity), new AuthenticationProperties(), context.Options.AuthenticationScheme); ticket.SetResources(context.Request.GetResources()); ticket.SetScopes(context.Request.GetScopes()); // Call SignInAsync to create and return a new OpenID Connect response containing the serialized code/tokens. await context.HttpContext.Authentication.SignInAsync(ticket.AuthenticationScheme, ticket.Principal, ticket.Properties); // Mark the response as handled // to skip the rest of the pipeline. context.HandleResponse(); return; } // If no request_id parameter can be found in the current request, assume the OpenID Connect request // was not serialized yet and store the entire payload in the distributed cache to make it easier // to flow across requests and internal/external authentication/registration workflows. if (string.IsNullOrEmpty(context.Request.RequestId)) { // Generate a request identifier. Note: using a crypto-secure // random number generator is not necessary in this case. context.Request.RequestId = Guid.NewGuid().ToString(); // Store the serialized authorization request parameters in the distributed cache. var stream = new MemoryStream(); using (var writer = new BsonWriter(stream)) { writer.CloseOutput = false; var serializer = JsonSerializer.CreateDefault(); serializer.Serialize(writer, context.Request); } // Note: the cache key is always prefixed with a specific marker // to avoid collisions with the other types of cached requests. var key = OpenIddictConstants.Environment.AuthorizationRequest + context.Request.RequestId; await services.Options.Cache.SetAsync(key, stream.ToArray(), new DistributedCacheEntryOptions { AbsoluteExpiration = context.Options.SystemClock.UtcNow + TimeSpan.FromMinutes(30), SlidingExpiration = TimeSpan.FromMinutes(10) }); // Create a new authorization request containing only the request_id parameter. var address = QueryHelpers.AddQueryString( uri: context.HttpContext.Request.PathBase + context.HttpContext.Request.Path, name: OpenIdConnectConstants.Parameters.RequestId, value: context.Request.RequestId); context.HttpContext.Response.Redirect(address); // Mark the response as handled // to skip the rest of the pipeline. context.HandleResponse(); return; } context.SkipToNextMiddleware(); }