Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose processed and original prompt modes #1453

Merged
merged 5 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/IdentityServer/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public static class SigningAlgorithms
//OidcConstants.PromptModes.Create,
};

public const string SuppressedPrompt = "suppressed_" + OidcConstants.AuthorizeRequest.Prompt;
public const string ProcessedPrompt = "processed_" + OidcConstants.AuthorizeRequest.Prompt;
josephdecock marked this conversation as resolved.
Show resolved Hide resolved

public static class KnownAcrValues
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static void RemovePrompt(this ValidatedAuthorizeRequest request)
suppress.Append(OidcConstants.PromptModes.Create);
}

request.Raw.Add(Constants.SuppressedPrompt, suppress.ToString());
request.Raw.Add(Constants.ProcessedPrompt, suppress.ToString());
request.PromptModes = request.PromptModes.Except(new[] {
OidcConstants.PromptModes.Login,
OidcConstants.PromptModes.SelectAccount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,15 +610,15 @@
}
}

var suppressed_prompt = request.Raw.Get(Constants.SuppressedPrompt);
if (suppressed_prompt.IsPresent())
var processed_prompt = request.Raw.Get(Constants.ProcessedPrompt);
if (processed_prompt.IsPresent())
{
var prompts = suppressed_prompt.Split(' ', StringSplitOptions.RemoveEmptyEntries);
var prompts = processed_prompt.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (prompts.All(p => _options.UserInteraction.PromptValuesSupported?.Contains(p) == true))
{
if (prompts.Contains(OidcConstants.PromptModes.None) && prompts.Length > 1)
{
LogError("suppressed_prompt contains 'none' and other values. 'none' should be used by itself.", request);
LogError("processed_prompt contains 'none' and other values. 'none' should be used by itself.", request);
return Invalid(request, description: "Invalid prompt");
}
if (prompts.Contains(OidcConstants.PromptModes.Create) && prompts.Length > 1)
Expand All @@ -627,18 +627,18 @@
return Invalid(request, description: "Invalid prompt");
}

request.SuppressedPromptModes = prompts;
request.ProcessedPromptModes = prompts;
}
else
{
// TODO: change to error in a major release?
// https://github.com/DuendeSoftware/IdentityServer/issues/845#issuecomment-1405377531
// https://openid.net/specs/openid-connect-prompt-create-1_0.html#name-authorization-request
_logger.LogDebug("Unsupported suppressed_prompt mode - ignored: " + prompt);
_logger.LogDebug("Unsupported processed_prompt mode - ignored: " + prompt);
Fixed Show fixed Hide fixed
}
}

request.PromptModes = request.OriginalPromptModes.Except(request.SuppressedPromptModes).ToArray();
request.PromptModes = request.OriginalPromptModes.Except(request.ProcessedPromptModes).ToArray();

//////////////////////////////////////////////////////////
// check ui locales
Expand Down
50 changes: 45 additions & 5 deletions src/IdentityServer/Validation/Models/ValidatedAuthorizeRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,26 +138,66 @@ public class ValidatedAuthorizeRequest : ValidatedRequest
/// <summary>
/// Gets or sets the collection of prompt modes.
/// </summary>
/// <remarks>
/// The <see cref="PromptModes"/> change as they are used. For example, if
/// the prompt mode is login (to force the login UI to be displayed), the
/// collection will initially contain login, but when the login page is
/// displayed, the login prompt will be removed from the collection of
/// prompt modes so that the login page will only be displayed once.
/// <para>
/// See also: <see cref="ProcessedPromptModes"/> and <see
/// cref="OriginalPromptModes"/>.
/// </para>
/// </remarks>
/// <value>
/// The collection of prompt modes.
/// The collection of prompt modes, which changes as the request is
/// processed and various prompts are displayed.
/// </value>
public IEnumerable<string> PromptModes { get; set; } = Enumerable.Empty<string>();

/// <summary>
/// Gets or sets the collection of original prompt modes.
/// </summary>
/// <remarks>
/// The <see cref="PromptModes"/> change as they are used. For example, if
/// the prompt mode is login (to force the login UI to be displayed), the
/// collection will initially contain login, but when the login page is
/// displayed, the login prompt will be removed from the collection of
/// prompt modes so that the login page will only be displayed once.
/// <para>
/// See also:
/// <list type="bullet">
/// <item><seealso cref="ProcessedPromptModes"/></item>
/// <item><seealso cref="PromptModes"/></item>
/// </list>
/// </para>
/// </remarks>
/// <value>
/// The collection of original prompt modes.
/// </value>
internal IEnumerable<string> OriginalPromptModes { get; set; } = Enumerable.Empty<string>();
public IEnumerable<string> OriginalPromptModes { get; set; } = Enumerable.Empty<string>();

/// <summary>
/// Gets or sets the collection of suppressed prompt modes.
/// Gets or sets the collection of previously processed prompt modes.
/// </summary>
/// <remarks>
/// The <see cref="PromptModes"/> change as they are used. For example, if
/// the prompt mode is login (to force the login UI to be displayed), the
/// collection will initially contain login, but when the login page is
/// displayed, the login prompt will be removed from the collection of
/// prompt modes so that the login page will only be displayed once.
/// </remarks>
/// <para>
/// See also:
/// <list type="bullet">
/// <item><seealso cref="PromptModes"/></item>
/// <item><seealso cref="OriginalPromptModes"/></item>
/// </list>
/// </para>
/// <value>
/// The collection of suppressed prompt modes.
/// The collection of processed prompt modes.
/// </value>
internal IEnumerable<string> SuppressedPromptModes { get; set; } = Enumerable.Empty<string>();
public IEnumerable<string> ProcessedPromptModes { get; set; } = Enumerable.Empty<string>();

/// <summary>
/// Gets or sets the maximum age.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,6 @@ public async Task prompt_for_signin_should_suppress_prompt_from_raw_url()

var result = await _subject.ProcessLoginAsync(request);

request.Raw.AllKeys.Should().Contain(Constants.SuppressedPrompt);
request.Raw.AllKeys.Should().Contain(Constants.ProcessedPrompt);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public async Task multiple_prompt_values_should_be_accepted()

[Fact]
[Trait("Category", Category)]
public async Task suppressed_prompt_values_should_overwrite_original_values()
public async Task processed_prompt_values_should_overwrite_original_values()
{
var validator = Factory.CreateAuthorizeRequestValidator();

Expand All @@ -242,19 +242,19 @@ public async Task suppressed_prompt_values_should_overwrite_original_values()
}
{
parameters[OidcConstants.AuthorizeRequest.Prompt] = "consent login";
parameters[Constants.SuppressedPrompt] = "login";
parameters[Constants.ProcessedPrompt] = "login";
var result = await validator.ValidateAsync(parameters);
result.ValidatedRequest.PromptModes.Should().BeEquivalentTo(new[] { OidcConstants.PromptModes.Consent });
result.ValidatedRequest.OriginalPromptModes.Should().BeEquivalentTo(new[] { OidcConstants.PromptModes.Consent, OidcConstants.PromptModes.Login });
result.ValidatedRequest.SuppressedPromptModes.Should().BeEquivalentTo(new[] { OidcConstants.PromptModes.Login });
result.ValidatedRequest.ProcessedPromptModes.Should().BeEquivalentTo(new[] { OidcConstants.PromptModes.Login });
}
{
parameters[OidcConstants.AuthorizeRequest.Prompt] = "consent login";
parameters[Constants.SuppressedPrompt] = "login consent";
parameters[Constants.ProcessedPrompt] = "login consent";
var result = await validator.ValidateAsync(parameters);
result.ValidatedRequest.PromptModes.Should().BeEmpty();
result.ValidatedRequest.OriginalPromptModes.Should().BeEquivalentTo(new[] { OidcConstants.PromptModes.Consent, OidcConstants.PromptModes.Login });
result.ValidatedRequest.SuppressedPromptModes.Should().BeEquivalentTo(new[] { OidcConstants.PromptModes.Consent, OidcConstants.PromptModes.Login });
result.ValidatedRequest.ProcessedPromptModes.Should().BeEquivalentTo(new[] { OidcConstants.PromptModes.Consent, OidcConstants.PromptModes.Login });
}
}
}