From cda55862bcba67bf3de4ba08cf512ee9e2269cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Chalet?= Date: Fri, 10 Sep 2021 19:57:15 +0200 Subject: [PATCH] Update HandleLogoutRequestContext to allow attaching custom sign-out parameters --- .../OpenIddictServerEvents.Session.cs | 17 +++++++ .../OpenIddictServerEvents.cs | 5 ++ .../OpenIddictServerHandlers.Session.cs | 8 ++++ .../OpenIddictServerHandlers.cs | 46 +++++++++++++++++-- ...penIddictServerIntegrationTests.Session.cs | 37 +++++++++++++++ 5 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/OpenIddict.Server/OpenIddictServerEvents.Session.cs b/src/OpenIddict.Server/OpenIddictServerEvents.Session.cs index 58702e16..889879f6 100644 --- a/src/OpenIddict.Server/OpenIddictServerEvents.Session.cs +++ b/src/OpenIddict.Server/OpenIddictServerEvents.Session.cs @@ -5,6 +5,7 @@ */ using System; +using System.Collections.Generic; using OpenIddict.Abstractions; using SR = OpenIddict.Abstractions.OpenIddictResources; @@ -115,10 +116,26 @@ namespace OpenIddict.Server /// public bool IsSignOutTriggered { get; private set; } + /// + /// Gets the additional parameters returned to the client application. + /// + public Dictionary Parameters { get; private set; } + = new(StringComparer.Ordinal); + /// /// Allows OpenIddict to return a sign-out response. /// public void SignOut() => IsSignOutTriggered = true; + + /// + /// Allows OpenIddict to return a sign-out response. + /// + /// The additional parameters returned to the client application. + public void SignOut(IDictionary parameters) + { + IsSignOutTriggered = true; + Parameters = new(parameters, StringComparer.Ordinal); + } } /// diff --git a/src/OpenIddict.Server/OpenIddictServerEvents.cs b/src/OpenIddict.Server/OpenIddictServerEvents.cs index eba4369e..0c71fc6f 100644 --- a/src/OpenIddict.Server/OpenIddictServerEvents.cs +++ b/src/OpenIddict.Server/OpenIddictServerEvents.cs @@ -733,6 +733,11 @@ namespace OpenIddict.Server get => Transaction.Response!; set => Transaction.Response = value; } + + /// + /// Gets the additional parameters returned to the client application. + /// + public Dictionary Parameters { get; } = new(StringComparer.Ordinal); } } } diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs index 307e4b08..2e6c4a73 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs @@ -227,6 +227,14 @@ namespace OpenIddict.Server Response = new OpenIddictResponse() }; + if (notification.Parameters.Count > 0) + { + foreach (var parameter in notification.Parameters) + { + @event.Parameters.Add(parameter.Key, parameter.Value); + } + } + await _dispatcher.DispatchAsync(@event); if (@event.IsRequestHandled) diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs index 45b7ef8c..33e1a123 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs @@ -82,12 +82,13 @@ namespace OpenIddict.Server GenerateUserCode.Descriptor, GenerateIdentityToken.Descriptor, - AttachTokenParameters.Descriptor, + AttachSignInParameters.Descriptor, /* * Sign-out processing: */ - ValidateSignOutDemand.Descriptor) + ValidateSignOutDemand.Descriptor, + AttachSignOutParameters.Descriptor) .AddRange(Authentication.DefaultHandlers) .AddRange(Device.DefaultHandlers) @@ -2832,16 +2833,16 @@ namespace OpenIddict.Server } /// - /// Contains the logic responsible of attaching the tokens and their metadata to the sign-in response. + /// Contains the logic responsible of attaching the appropriate parameters to the sign-in response. /// - public class AttachTokenParameters : IOpenIddictServerHandler + public class AttachSignInParameters : IOpenIddictServerHandler { /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .UseSingletonHandler() + .UseSingletonHandler() .SetOrder(GenerateIdentityToken.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) .Build(); @@ -3009,5 +3010,40 @@ namespace OpenIddict.Server return default; } } + + /// + /// Contains the logic responsible of attaching the appropriate parameters to the sign-out response. + /// + public class AttachSignOutParameters : IOpenIddictServerHandler + { + /// + /// Gets the default descriptor definition assigned to this handler. + /// + public static OpenIddictServerHandlerDescriptor Descriptor { get; } + = OpenIddictServerHandlerDescriptor.CreateBuilder() + .UseSingletonHandler() + .SetOrder(ValidateSignOutDemand.Descriptor.Order + 1_000) + .SetType(OpenIddictServerHandlerType.BuiltIn) + .Build(); + + /// + public ValueTask HandleAsync(ProcessSignOutContext context) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (context.Parameters.Count > 0) + { + foreach (var parameter in context.Parameters) + { + context.Response.SetParameter(parameter.Key, parameter.Value); + } + } + + return default; + } + } } } diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Session.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Session.cs index b619c763..3e840aad 100644 --- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Session.cs +++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Session.cs @@ -478,6 +478,43 @@ namespace OpenIddict.Server.IntegrationTests Assert.Equal("Bob le Magnifique", (string?) response["name"]); } + [Fact] + public async Task HandleLogoutResponse_ResponseContainsCustomParameters() + { + // Arrange + await using var server = await CreateServerAsync(options => + { + options.EnableDegradedMode(); + + options.AddEventHandler(builder => + builder.UseInlineHandler(context => + { + context.SignOut(); + + context.Parameters["custom_parameter"] = "custom_value"; + context.Parameters["parameter_with_multiple_values"] = new[] + { + "custom_value_1", + "custom_value_2" + }; + + return default; + })); + }); + + await using var client = await server.CreateClientAsync(); + + // Act + var response = await client.PostAsync("/connect/logout", new OpenIddictRequest + { + PostLogoutRedirectUri = "http://www.fabrikam.com/path" + }); + + // Assert + Assert.Equal("custom_value", (string?) response["custom_parameter"]); + Assert.Equal(new[] { "custom_value_1", "custom_value_2" }, (string[]?) response["parameter_with_multiple_values"]); + } + [Fact] public async Task ApplyLogoutResponse_AllowsHandlingResponse() {