public override async Task ExtractLogoutRequest([NotNull] ExtractLogoutRequestContext context) { var logger = context.HttpContext.RequestServices.GetRequiredService <ILogger <OpenIddictProvider <TApplication, TAuthorization, TScope, TToken> > >(); var options = context.HttpContext.RequestServices.GetRequiredService <IOptions <OpenIddictOptions> >(); // If a request_id parameter can be found in the logout request, // restore the complete logout request from the distributed cache. if (!string.IsNullOrEmpty(context.Request.RequestId)) { // Return an error if request caching support was not enabled. if (!options.Value.EnableRequestCaching) { logger.LogError("The logout request was rejected because " + "request caching support was not enabled."); context.Reject( error: OpenIdConnectConstants.Errors.InvalidRequest, description: "The request_id parameter is not supported."); return; } // 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.LogoutRequest + context.Request.RequestId; var payload = await options.Value.Cache.GetAsync(key); if (payload == null) { logger.LogError("The logout request was rejected because an unknown " + "or invalid request_id parameter was specified."); context.Reject( error: OpenIdConnectConstants.Errors.InvalidRequest, description: "Invalid request: timeout expired."); return; } // Restore the logout request parameters from the serialized payload. using (var reader = new BsonReader(new MemoryStream(payload))) { foreach (var parameter in JObject.Load(reader)) { // Avoid overriding the current request parameters. if (context.Request.HasParameter(parameter.Key)) { continue; } context.Request.SetParameter(parameter.Key, parameter.Value); } } } }
public override async Task ExtractLogoutRequest([NotNull] ExtractLogoutRequestContext context) { var options = (OpenIddictServerOptions)context.Options; // If a request_id parameter can be found in the logout request, // restore the complete logout request from the distributed cache. if (!string.IsNullOrEmpty(context.Request.RequestId)) { // Return an error if request caching support was not enabled. if (!options.EnableRequestCaching) { _logger.LogError("The logout request was rejected because request caching support was not enabled."); context.Reject( error: OpenIdConnectConstants.Errors.InvalidRequest, description: "The 'request_id' parameter is not supported."); return; } // 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.LogoutRequest + context.Request.RequestId; var payload = await options.Cache.GetAsync(key); if (payload == null) { _logger.LogError("The logout request was rejected because an unknown " + "or invalid request_id parameter was specified."); context.Reject( error: OpenIdConnectConstants.Errors.InvalidRequest, description: "The specified 'request_id' parameter is invalid."); return; } // Restore the logout request parameters from the serialized payload. using (var reader = new BsonDataReader(new MemoryStream(payload))) { foreach (var parameter in JObject.Load(reader)) { // Avoid overriding the current request parameters. if (context.Request.HasParameter(parameter.Key)) { continue; } context.Request.SetParameter(parameter.Key, parameter.Value); } } } await _eventService.PublishAsync(new OpenIddictServerEvents.ExtractLogoutRequest(context)); }
public override async Task ExtractLogoutRequest([NotNull] ExtractLogoutRequestContext context) { var services = context.HttpContext.RequestServices.GetRequiredService <OpenIddictServices <TApplication, TAuthorization, TScope, TToken> >(); // If a request_id parameter can be found in the logout request, // restore the complete logout request from the distributed cache. if (!string.IsNullOrEmpty(context.Request.RequestId)) { // Return an error if request caching support was not enabled. if (!services.Options.EnableRequestCaching) { services.Logger.LogError("The logout request was rejected because " + "request caching support was not enabled."); context.Reject( error: OpenIdConnectConstants.Errors.InvalidRequest, description: "The request_id parameter is not supported."); return; } // 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.LogoutRequest + context.Request.RequestId; var payload = await services.Options.Cache.GetAsync(key); if (payload == null) { services.Logger.LogError("The logout request was rejected because an unknown " + "or invalid request_id parameter was specified."); context.Reject( error: OpenIdConnectConstants.Errors.InvalidRequest, description: "Invalid request: timeout expired."); return; } // Restore the logout request parameters from the serialized payload. using (var reader = new BsonReader(new MemoryStream(payload))) { var serializer = JsonSerializer.CreateDefault(); // Note: JsonSerializer.Populate() automatically preserves // the original request parameters resolved from the cache // when parameters with the same names are specified. serializer.Populate(reader, context.Request); } } }
/// <summary> /// Processes the event. /// </summary> /// <param name="context">The context associated with the event to process.</param> /// <returns> /// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation. /// </returns> public async ValueTask HandleAsync([NotNull] ProcessRequestContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.EndpointType != OpenIddictServerEndpointType.Logout) { return; } var notification = new ExtractLogoutRequestContext(context.Transaction); await _provider.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; } if (notification.Request == null) { throw new InvalidOperationException(new StringBuilder() .Append("The logout request was not correctly extracted. To extract logout requests, ") .Append("create a class implementing 'IOpenIddictServerHandler<ExtractLogoutRequestContext>' ") .AppendLine("and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.") .ToString()); } context.Logger.LogInformation("The logout request was successfully extracted: {Request}.", notification.Request); }
/// <summary> /// Processes the event. /// </summary> /// <param name="context">The context associated with the event to process.</param> /// <returns> /// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation. /// </returns> public async ValueTask HandleAsync([NotNull] ExtractLogoutRequestContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } // If a request_id parameter can be found in the logout request, // restore the complete logout request from the distributed cache. if (string.IsNullOrEmpty(context.Request.RequestId)) { return; } // Note: the cache key is always prefixed with a specific marker // to avoid collisions with the other types of cached payloads. var payload = await _cache.GetAsync(Cache.LogoutRequest + context.Request.RequestId); if (payload == null) { context.Logger.LogError("The logout request was rejected because an unknown " + "or invalid request_id parameter was specified."); context.Reject( error: Errors.InvalidRequest, description: "The specified 'request_id' parameter is invalid."); return; } // Restore the logout request parameters from the serialized payload. using var reader = new BsonDataReader(new MemoryStream(payload)); foreach (var parameter in JObject.Load(reader)) { // Avoid overriding the current request parameters. if (context.Request.HasParameter(parameter.Key)) { continue; } context.Request.SetParameter(parameter.Key, parameter.Value); } }
/// <inheritdoc/> public async ValueTask HandleAsync(ProcessRequestContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } var notification = new ExtractLogoutRequestContext(context.Transaction); 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; } if (notification.Request is null) { throw new InvalidOperationException(SR.GetResourceString(SR.ID0050)); } context.Logger.LogInformation(SR.GetResourceString(SR.ID6124), notification.Request); }
/// <inheritdoc/> public async ValueTask HandleAsync(ExtractLogoutRequestContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } Debug.Assert(context.Request is not null, SR.GetResourceString(SR.ID4008)); // If a request_id parameter can be found in the logout request, // restore the complete logout request from the distributed cache. if (string.IsNullOrEmpty(context.Request.RequestId)) { return; } // Note: the cache key is always prefixed with a specific marker // to avoid collisions with the other types of cached payloads. var token = await _cache.GetStringAsync(Cache.LogoutRequest + context.Request.RequestId); if (token is null || !context.Options.JsonWebTokenHandler.CanReadToken(token)) { context.Logger.LogError(SR.GetResourceString(SR.ID6150), Parameters.RequestId); context.Reject( error: Errors.InvalidRequest, description: context.Localizer[SR.ID2052, Parameters.RequestId]); return; } var parameters = context.Options.TokenValidationParameters.Clone(); parameters.ValidIssuer ??= context.Issuer?.AbsoluteUri; parameters.ValidAudience = context.Issuer?.AbsoluteUri; parameters.ValidTypes = new[] { JsonWebTokenTypes.Private.LogoutRequest }; var result = context.Options.JsonWebTokenHandler.ValidateToken(token, parameters); if (!result.IsValid) { context.Logger.LogError(SR.GetResourceString(SR.ID6150), Parameters.RequestId); context.Reject( error: Errors.InvalidRequest, description: context.Localizer[SR.ID2052, Parameters.RequestId]); return; } using var document = JsonDocument.Parse( Base64UrlEncoder.Decode(((JsonWebToken)result.SecurityToken).InnerToken.EncodedPayload)); if (document.RootElement.ValueKind != JsonValueKind.Object) { throw new InvalidOperationException(SR.GetResourceString(SR.ID0118)); } // Restore the authorization request parameters from the serialized payload. foreach (var parameter in document.RootElement.EnumerateObject()) { // Avoid overriding the current request parameters. if (context.Request.HasParameter(parameter.Name)) { continue; } context.Request.SetParameter(parameter.Name, parameter.Value.Clone()); } }
/// <summary> /// Processes the event. /// </summary> /// <param name="context">The context associated with the event to process.</param> /// <returns> /// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation. /// </returns> public async ValueTask HandleAsync([NotNull] ExtractLogoutRequestContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } // If a request_id parameter can be found in the logout request, // restore the complete logout request from the distributed cache. if (string.IsNullOrEmpty(context.Request.RequestId)) { return; } // Note: the cache key is always prefixed with a specific marker // to avoid collisions with the other types of cached payloads. var token = await _cache.GetStringAsync(Cache.LogoutRequest + context.Request.RequestId); if (token == null || !context.Options.JsonWebTokenHandler.CanReadToken(token)) { context.Logger.LogError("The logout request was rejected because an unknown " + "or invalid request_id parameter was specified."); context.Reject( error: Errors.InvalidRequest, description: "The specified 'request_id' parameter is invalid."); return; } // Restore the authorization request parameters from the serialized payload. var parameters = new TokenValidationParameters { IssuerSigningKeys = context.Options.SigningCredentials.Select(credentials => credentials.Key), TokenDecryptionKeys = context.Options.EncryptionCredentials.Select(credentials => credentials.Key), ValidateLifetime = false, ValidAudience = context.Issuer.AbsoluteUri, ValidIssuer = context.Issuer.AbsoluteUri, ValidTypes = new[] { JsonWebTokenTypes.LogoutRequest } }; var result = context.Options.JsonWebTokenHandler.ValidateToken(token, parameters); if (!result.IsValid) { context.Logger.LogError("The logout request was rejected because an unknown " + "or invalid request_id parameter was specified."); context.Reject( error: Errors.InvalidRequest, description: "The specified 'request_id' parameter is invalid."); return; } using var document = JsonDocument.Parse( Base64UrlEncoder.Decode(((JsonWebToken)result.SecurityToken).InnerToken.EncodedPayload)); if (document.RootElement.ValueKind != JsonValueKind.Object) { throw new InvalidOperationException("The logout request payload is malformed."); } foreach (var parameter in document.RootElement.EnumerateObject()) { // Avoid overriding the current request parameters. if (context.Request.HasParameter(parameter.Name)) { continue; } context.Request.SetParameter(parameter.Name, parameter.Value.Clone()); } }