Skip to content

Commit

Permalink
Merge pull request #1582 from DuendeSoftware/joe/expose-supported-pro…
Browse files Browse the repository at this point in the history
…mpt-modes

Allow SupportedPromptModes customization
  • Loading branch information
josephdecock authored Sep 20, 2024
2 parents 765116a + d4b3e45 commit d9afcc3
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#nullable enable

using Duende.IdentityServer.Extensions;
using Duende.IdentityServer.ResponseHandling;
using System.Collections.Generic;

namespace Duende.IdentityServer.Configuration;
Expand Down Expand Up @@ -132,8 +133,13 @@ public class UserInteractionOptions
public bool AllowOriginInReturnUrl { get; set; }

/// <summary>
/// The collection of OIDC prompt modes supported and that will be published in discovery.
/// The value "create" is omitted unless the CreateAccountUrl value is set.
/// The collection of OIDC prompt modes supported and that will be published
/// in discovery. By default, this includes all values in <see
/// cref="Constants.SupportedPromptModes"/>. If the <see
/// cref="CreateAccountUrl"/> option is set, then the "create" value is also
/// included. If additional prompt values are added, a customized <see
/// cref="IAuthorizeInteractionResponseGenerator"/> is also required to
/// handle those values.
/// </summary>
internal ICollection<string> PromptValuesSupported { get; set; } = new HashSet<string>(Constants.SupportedPromptModes);
public ICollection<string> PromptValuesSupported { get; set; } = new HashSet<string>(Constants.SupportedPromptModes);
}
Original file line number Diff line number Diff line change
Expand Up @@ -1485,14 +1485,72 @@ public async Task custom_request_should_have_authorization_params(Type storeType
_mockPipeline.CustomRequest.Parameters.AllKeys.Should().Contain("foo");
_mockPipeline.CustomRequest.Parameters["foo"].Should().Be("bar");
}

[Fact]
public async Task custom_prompt_values_should_raise_error_with_default_interaction_service()
{
_mockPipeline.Options.UserInteraction.PromptValuesSupported.Add("custom-prompt");
await _mockPipeline.LoginAsync("bob");

var url = _mockPipeline.CreateAuthorizeUrl(
clientId: "client1",
responseType: "id_token",
scope: "openid profile",
redirectUri: "https://client1/callback",
state: "123_state",
nonce: "123_nonce",
extra: new { prompt = "custom-prompt" }
);

_mockPipeline.BrowserClient.AllowAutoRedirect = false;

Func<Task> a = () => _mockPipeline.BrowserClient.GetAsync(url);
await a.Should().ThrowAsync<Exception>();
}

[Fact]
public async Task custom_prompt_value_should_be_passed_to_custom_interaction_service()
{
var mockAuthzInteractionService = new MockAuthzInteractionService();
mockAuthzInteractionService.Response.RedirectUrl = "/custom";
_mockPipeline.OnPostConfigureServices += services =>
{
services.AddTransient(typeof(IAuthorizeInteractionResponseGenerator), svc => mockAuthzInteractionService);
};
_mockPipeline.Initialize();

_mockPipeline.Options.UserInteraction.PromptValuesSupported.Add("custom-prompt");

await _mockPipeline.LoginAsync("bob");

var url = _mockPipeline.CreateAuthorizeUrl(
clientId: "client1",
responseType: "id_token",
scope: "openid profile",
redirectUri: "https://client1/callback",
state: "123_state",
nonce: "123_nonce",
extra: new { prompt = "custom-prompt" }
);

_mockPipeline.BrowserClient.AllowAutoRedirect = false;

var response = await _mockPipeline.BrowserClient.GetAsync(url);
response.Headers.Location.GetLeftPart(UriPartial.Path).Should().Be("https://server/custom");
mockAuthzInteractionService.Request.PromptModes.Should()
.Contain("custom-prompt").And
.HaveCount(1);
}
}

public class MockAuthzInteractionService : IAuthorizeInteractionResponseGenerator
{
public InteractionResponse Response { get; set; } = new InteractionResponse();
public ValidatedAuthorizeRequest Request { get; internal set; }

public Task<InteractionResponse> ProcessInteractionAsync(ValidatedAuthorizeRequest request, ConsentResponse consent = null)
{
Request = request;
return Task.FromResult(Response);
}
}

0 comments on commit d9afcc3

Please sign in to comment.