From bdf3b56db8c3e5d81e7228d0b159cfec90277381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Wed, 26 Feb 2025 19:04:45 +0100 Subject: [PATCH] Do not reject end session requests that don't include an explicit client_id when request caching is used --- .../OpenIddictServerHandlers.Session.cs | 13 +---- ...penIddictServerIntegrationTests.Session.cs | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs index 2d2032288..9ecb5e2a7 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs @@ -404,17 +404,8 @@ public ValueTask HandleAsync(ValidateEndSessionRequestContext context) return default; } - // For consistency with authorization requests, the client_id parameter - // is also required when using a request_uri parameter is present. - if (string.IsNullOrEmpty(context.Request.ClientId)) - { - context.Reject( - error: Errors.InvalidRequest, - description: SR.FormatID2037(Parameters.RequestUri, Parameters.ClientId), - uri: SR.FormatID8000(SR.ID2037)); - - return default; - } + // Note: unlike authorization requests, the client_id parameter is not required for end + // session requests and may not be present in the original request before it is cached. return default; } diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Session.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Session.cs index e5f029258..69c19eebb 100644 --- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Session.cs +++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Session.cs @@ -206,6 +206,62 @@ public async Task ValidateEndSession_ValidRequestUriDoesNotCauseAnError() Assert.Equal("af0ifjsldkj", response.State); } + [Fact] + public async Task ValidateEndSession_MissingClientIdDoesNotCauseAnError() + { + // Arrange + await using var server = await CreateServerAsync(options => + { + options.EnableDegradedMode(); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.SignOut(); + + return default; + })); + + options.AddEventHandler(builder => + { + builder.UseInlineHandler(context => + { + Assert.Equal("6esc_11ACC5bwc014ltc14eY22c", context.Token); + Assert.Equal([TokenTypeHints.Private.RequestToken], context.ValidTokenTypes); + + context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) + .SetTokenType(TokenTypeHints.Private.RequestToken) + .SetClaim(Claims.Private.RequestTokenType, RequestTokenTypes.Private.CachedEndSessionRequest) + .SetClaim(Claims.Private.RequestParameters, $$""" + { + "post_logout_redirect_uri": "http://www.fabrikam.com/path", + "state": "af0ifjsldkj" + } + """); + + return default; + }); + + builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); + }); + }); + + await using var client = await server.CreateClientAsync(); + + // Act + var response = await client.GetAsync("/connect/endsession", new OpenIddictRequest + { + ClientId = null, + RequestUri = RequestUris.Prefixes.Generic + "6esc_11ACC5bwc014ltc14eY22c" + }); + + // Assert + Assert.Null(response.Error); + Assert.Null(response.ErrorDescription); + Assert.Null(response.ErrorUri); + Assert.Equal("af0ifjsldkj", response.State); + } + [Theory] [InlineData("/path", SR.ID2030)] [InlineData("/tmp/file.xml", SR.ID2030)]