コード例 #1
0
        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);
                    }
                }
            }
        }
コード例 #2
0
        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));
        }
コード例 #3
0
        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);
                }
            }
        }
コード例 #4
0
                /// <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);
                }
コード例 #5
0
                /// <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);
                    }
                }
コード例 #6
0
            /// <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);
            }
コード例 #7
0
                /// <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());
                    }
                }
コード例 #8
0
                /// <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());
                    }
                }