Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions docs/reference/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ IdentityServer Options
* ``StrictJarValidation``
When enabled, applies strict JWT-secured authorization request validation, including typ and content-type checks, according to IETF spec. Defaults to ``false``.

* ``StrictAuthorizeErrorResponses``
When enabled, the authorize endpoint returns every error to the client's redirect URI once the redirect URI and response mode have been validated, as RFC 6749 section 4.1.2.1 describes. Errors found before that still go to the error page: an unknown client or redirect URI, an invalid request object or ``request_uri``, and a missing or unknown ``response_type``.
Defaults to ``false``, which returns only ``access_denied``, ``account_selection_required``, ``login_required``, ``consent_required`` and ``interaction_required`` to the client.

* ``EnableAuthorizeResponseIssuerParam``
When enabled, the authorize response will include the issuer ``iss`` parameter, and advertises support in the discovery document. Defaults to ``false``.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public class IdentityServerOptions
/// </summary>
public bool StrictJarValidation { get; set; } = false;

/// <summary>
/// Specifies whether the authorize endpoint returns all errors to the client once the redirect URI and response mode have been validated, as RFC 6749 section 4.1.2.1 describes.
/// </summary>
public bool StrictAuthorizeErrorResponses { get; set; } = false;

/// <summary>
/// Gets or sets the supported JWT request object signing algorithms.
/// Defaults to an empty collection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ private async Task ProcessErrorAsync(HttpContext context)
Response.Error == OidcConstants.AuthorizeErrors.ConsentRequired ||
Response.Error == OidcConstants.AuthorizeErrors.InteractionRequired;

if (isSafeError)
var returnToClientInStrictMode = _options.StrictAuthorizeErrorResponses && Response.RedirectUri != null &&
Response.Request?.ResponseMode != null;
if (isSafeError || returnToClientInStrictMode)
{
// this scenario we can return back to the client
await ProcessResponseAsync(context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,69 @@ public async Task SafeErrors_ShouldReturnToClient(string error)
location.Should().Contain("#_");
}

[Theory]
[InlineData(OidcConstants.AuthorizeErrors.InvalidRequest)]
[InlineData(OidcConstants.AuthorizeErrors.TemporarilyUnavailable)]
[InlineData(OidcConstants.AuthorizeErrors.UnmetAuthenticationRequirements)]
public async Task OtherErrors_WhenStrictAuthorizeErrorResponsesDisabled_ShouldRedirectToErrorPage(string error)
{
_response.Error = error;
_response.Request = new ValidatedAuthorizeRequest
{
ResponseMode = OidcConstants.ResponseModes.Query,
RedirectUri = "http://client/callback"
};

await _subject.ExecuteAsync(_context);

_mockErrorMessageStore.Messages.Count.Should().Be(1);
_context.Response.Headers["Location"].First().Should().StartWith("https://server/error");
}

[Theory]
[InlineData(OidcConstants.AuthorizeErrors.InvalidRequest)]
[InlineData(OidcConstants.AuthorizeErrors.TemporarilyUnavailable)]
[InlineData(OidcConstants.AuthorizeErrors.UnmetAuthenticationRequirements)]
[InlineData("some_error")]
public async Task OtherErrors_WhenStrictAuthorizeErrorResponsesEnabled_ShouldReturnToClient(string error)
{
_options.StrictAuthorizeErrorResponses = true;
_response.Error = error;
_response.Request = new ValidatedAuthorizeRequest
{
ResponseMode = OidcConstants.ResponseModes.Query,
RedirectUri = "http://client/callback"
};

await _subject.ExecuteAsync(_context);

_mockErrorMessageStore.Messages.Should().BeEmpty();
var location = _context.Response.Headers["Location"].First();
location.Should().StartWith("http://client/callback");
QueryHelpers.ParseQuery(new Uri(location).Query)["error"].First().Should().Be(error);
}

[Theory]
[InlineData(OidcConstants.ResponseModes.Query, null)]
[InlineData(null, "http://client/callback")]
public async Task OtherErrors_WhenStrictAuthorizeErrorResponsesEnabled_AndResponseNotRoutable_ShouldRedirectToErrorPage(
string responseMode, string redirectUri)
{
// the validator sets these only once the redirect uri and response mode are known to be valid
_options.StrictAuthorizeErrorResponses = true;
_response.Error = OidcConstants.AuthorizeErrors.InvalidRequest;
_response.Request = new ValidatedAuthorizeRequest
{
ResponseMode = responseMode,
RedirectUri = redirectUri
};

await _subject.ExecuteAsync(_context);

_mockErrorMessageStore.Messages.Count.Should().Be(1);
_context.Response.Headers["Location"].First().Should().StartWith("https://server/error");
}

[Theory]
[InlineData(OidcConstants.AuthorizeErrors.AccountSelectionRequired)]
[InlineData(OidcConstants.AuthorizeErrors.LoginRequired)]
Expand Down
Loading