Skip to content
This repository was archived by the owner on Feb 23, 2025. It is now read-only.

Remove support for nonce parameter #328

Merged
merged 1 commit into from
Jul 14, 2021
Merged
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
9 changes: 3 additions & 6 deletions src/OidcClient/AuthorizeClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,25 +93,24 @@ public AuthorizeState CreateAuthorizeState(Parameters frontChannelParameters)

var state = new AuthorizeState
{
Nonce = _crypto.CreateNonce(),
State = _crypto.CreateState(),
RedirectUri = _options.RedirectUri,
CodeVerifier = pkce.CodeVerifier,
};

state.StartUrl = CreateAuthorizeUrl(state.State, state.Nonce, pkce.CodeChallenge, frontChannelParameters);
state.StartUrl = CreateAuthorizeUrl(state.State, pkce.CodeChallenge, frontChannelParameters);

_logger.LogDebug(LogSerializer.Serialize(state));

return state;
}

internal string CreateAuthorizeUrl(string state, string nonce, string codeChallenge,
internal string CreateAuthorizeUrl(string state, string codeChallenge,
Parameters frontChannelParameters)
{
_logger.LogTrace("CreateAuthorizeUrl");

var parameters = CreateAuthorizeParameters(state, nonce, codeChallenge, frontChannelParameters);
var parameters = CreateAuthorizeParameters(state, codeChallenge, frontChannelParameters);
var request = new RequestUrl(_options.ProviderInformation.AuthorizeEndpoint);

return request.Create(parameters);
Expand All @@ -129,7 +128,6 @@ internal string CreateEndSessionUrl(string endpoint, LogoutRequest request)

internal Parameters CreateAuthorizeParameters(
string state,
string nonce,
string codeChallenge,
Parameters frontChannelParameters)
{
Expand All @@ -138,7 +136,6 @@ internal Parameters CreateAuthorizeParameters(
var parameters = new Parameters
{
{ OidcConstants.AuthorizeRequest.ResponseType, OidcConstants.ResponseTypes.Code },
{ OidcConstants.AuthorizeRequest.Nonce, nonce },
{ OidcConstants.AuthorizeRequest.State, state },
{ OidcConstants.AuthorizeRequest.CodeChallenge, codeChallenge },
{ OidcConstants.AuthorizeRequest.CodeChallengeMethod, OidcConstants.CodeChallengeMethods.Sha256 },
Expand Down
8 changes: 0 additions & 8 deletions src/OidcClient/AuthorizeState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ public class AuthorizeState
/// </value>
public string StartUrl { get; set; }

/// <summary>
/// Gets or sets the nonce.
/// </summary>
/// <value>
/// The nonce.
/// </value>
public string Nonce { get; set; }

/// <summary>
/// Gets or sets the state.
/// </summary>
Expand Down
24 changes: 0 additions & 24 deletions src/OidcClient/ResponseProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,6 @@ internal async Task<TokenResponseValidationResult> ValidateTokenResponseAsync(To
return new TokenResponseValidationResult(validationResult.Error ?? "Identity token validation error");
}

// validate nonce
if (state != null)
{
if (!ValidateNonce(state.Nonce, validationResult.User))
{
return new TokenResponseValidationResult("Invalid nonce.");
}
}

// validate at_hash
if (!string.Equals(validationResult.SignatureAlgorithm, "none", StringComparison.OrdinalIgnoreCase))
{
Expand All @@ -180,21 +171,6 @@ internal async Task<TokenResponseValidationResult> ValidateTokenResponseAsync(To
return new TokenResponseValidationResult((IdentityTokenValidationResult)null);
}

private bool ValidateNonce(string nonce, ClaimsPrincipal user)
{
_logger.LogTrace("ValidateNonce");

var tokenNonce = user.FindFirst(JwtClaimTypes.Nonce)?.Value ?? "";
var match = string.Equals(nonce, tokenNonce, StringComparison.Ordinal);

if (!match)
{
_logger.LogError($"nonce ({nonce}) does not match nonce from token ({tokenNonce})");
}

return match;
}

private async Task<TokenResponse> RedeemCodeAsync(string code, AuthorizeState state, Parameters backChannelParameters, CancellationToken cancellationToken)
{
_logger.LogTrace("RedeemCodeAsync");
Expand Down
117 changes: 22 additions & 95 deletions test/JwtValidationTests/CodeFlowResponseTestsWithJwtValidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,11 @@ public async Task Valid_response_should_succeed()
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -86,12 +85,11 @@ public async Task Valid_response_with_profile_should_succeed()
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -149,12 +147,11 @@ public async Task Valid_response_with_missing_signature_should_succeed()
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(null, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -187,12 +184,11 @@ public async Task Valid_response_with_missing_signature_should_fail()
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(null, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -221,12 +217,11 @@ public async Task Sending_authorization_header_should_succeed()
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -260,12 +255,11 @@ public async Task Sending_client_credentials_in_body_should_succeed()
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -296,12 +290,11 @@ public async Task Multi_tenant_token_issuer_name_should_succeed_by_policy_option
_options.Policy.Discovery.ValidateEndpoints = false;
_options.Policy.ValidateTokenIssuerName = false;

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://{some_multi_tenant_name}", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -329,12 +322,11 @@ public async Task Extra_parameters_on_backchannel_should_be_sent()
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -366,68 +358,6 @@ public async Task Extra_parameters_on_backchannel_should_be_sent()
body.Should().Contain("bar=bar");
}

[Fact]
public async Task Invalid_nonce_should_fail()
{
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", "invalid"));

var tokenResponse = new Dictionary<string, object>
{
{ "access_token", "token" },
{ "expires_in", 300 },
{ "id_token", idToken },
{ "refresh_token", "refresh_token" }
};

_options.ProviderInformation.KeySet = Crypto.CreateKeySet(key);
_options.BackchannelHandler =
new NetworkHandler(JsonSerializer.Serialize(tokenResponse), HttpStatusCode.OK);

var result = await client.ProcessResponseAsync(url, state);

result.IsError.Should().BeTrue();
result.Error.Should().Be("Error validating token response: Invalid nonce.");
}

[Fact]
public async Task Missing_nonce_should_fail()
{
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
{ "access_token", "token" },
{ "expires_in", 300 },
{ "id_token", idToken },
{ "refresh_token", "refresh_token" }
};

_options.ProviderInformation.KeySet = Crypto.CreateKeySet(key);
_options.BackchannelHandler =
new NetworkHandler(JsonSerializer.Serialize(tokenResponse), HttpStatusCode.OK);

var result = await client.ProcessResponseAsync(url, state);

result.IsError.Should().BeTrue();
result.Error.Should().Be("Error validating token response: Invalid nonce.");
}


[Fact]
public async Task Error_redeeming_code_should_fail()
{
Expand Down Expand Up @@ -502,12 +432,11 @@ public async Task No_identity_token_on_token_response_with_profile_loading_shoul
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", Crypto.HashData("token")),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -637,11 +566,10 @@ public async Task At_hash_policy_should_be_enforced(bool atHashRequired)
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down Expand Up @@ -680,12 +608,11 @@ public async Task Invalid_at_hash_should_fail(bool atHashRequired)
var client = new OidcClient(_options);
var state = await client.PrepareLoginAsync();

var url = $"?state={state.State}&nonce={state.Nonce}&code=bar";
var url = $"?state={state.State}&code=bar";
var key = Crypto.CreateKey();
var idToken = Crypto.CreateJwt(key, "https://authority", "client",
new Claim("at_hash", "invalid"),
new Claim("sub", "123"),
new Claim("nonce", state.Nonce));
new Claim("sub", "123"));

var tokenResponse = new Dictionary<string, object>
{
Expand Down
10 changes: 4 additions & 6 deletions test/OidcClient.Tests/AuthorizeRequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,16 @@ public void Default_parameters_should_be_used_for_authorize_request()
};

var client = new AuthorizeClient(options);
var parameters = client.CreateAuthorizeParameters("state", "nonce", "code_challenge", null);
var parameters = client.CreateAuthorizeParameters("state", "code_challenge", null);

parameters.Should().HaveCount(10);
parameters.Should().HaveCount(9);
parameters.GetValues("client_id").Single().Should().Be("client_id");
parameters.GetValues("scope").Single().Should().Be("openid");
parameters.GetValues("resource").First().Should().Be("urn:resource1");
parameters.GetValues("resource").Skip(1).First().Should().Be("urn:resource2");
parameters.GetValues("redirect_uri").Single().Should().Be("http://redirect");
parameters.GetValues("response_type").Single().Should().Be("code");
parameters.GetValues("state").Single().Should().Be("state");
parameters.GetValues("nonce").Single().Should().Be("nonce");
parameters.GetValues("code_challenge").Single().Should().Be("code_challenge");
parameters.GetValues("code_challenge_method").Single().Should().Be("S256");
}
Expand All @@ -57,15 +56,14 @@ public void Missing_default_parameters_can_be_set_by_extra_parameters()
};

var client = new AuthorizeClient(options);
var parameters = client.CreateAuthorizeParameters("state", "nonce", "code_challenge", frontChannel);
var parameters = client.CreateAuthorizeParameters("state", "code_challenge", frontChannel);

parameters.Should().HaveCount(10);
parameters.Should().HaveCount(9);
parameters.GetValues("client_id").Single().Should().Be("client_id2");
parameters.GetValues("scope").Single().Should().Be("openid extra");
parameters.GetValues("redirect_uri").Single().Should().Be("http://redirect2");
parameters.GetValues("response_type").Single().Should().Be("code");
parameters.GetValues("state").Single().Should().Be("state");
parameters.GetValues("nonce").Single().Should().Be("nonce");
parameters.GetValues("code_challenge").Single().Should().Be("code_challenge");
parameters.GetValues("code_challenge_method").Single().Should().Be("S256");

Expand Down
Loading