Browse Source

Update the ValidatePrincipal handler to ensure the token type of the claims principal matches the expected type

pull/915/head
Kévin Chalet 6 years ago
parent
commit
8b097321c3
  1. 2
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs
  2. 31
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  3. 8
      src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionHandlers.cs
  4. 29
      src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
  5. 4
      test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs
  6. 38
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs
  7. 132
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs

2
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs

@ -139,7 +139,7 @@ namespace OpenIddict.Server.DataProtection
// Note: since the data format relies on a data protector using different "purposes" strings
// per token type, the token processed at this stage is guaranteed to be of the expected type.
return _options.CurrentValue.Formatter.ReadToken(reader)?.SetClaim(Claims.Private.TokenType, type);
return _options.CurrentValue.Formatter.ReadToken(reader)?.SetTokenType(type);
}
catch (Exception exception)

31
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -483,7 +483,7 @@ namespace OpenIddict.Server
context.Principal = new ClaimsPrincipal(result.ClaimsIdentity);
// Store the token type as a special private claim.
context.Principal.SetClaim(Claims.Private.TokenType, token.Typ switch
context.Principal.SetTokenType(token.Typ switch
{
JsonWebTokenTypes.AccessToken => TokenTypeHints.AccessToken,
JsonWebTokenTypes.IdentityToken => TokenTypeHints.IdToken,
@ -634,7 +634,7 @@ namespace OpenIddict.Server
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
.SetInternalAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
.SetInternalTokenId(await _tokenManager.GetIdAsync(token))
.SetClaim(Claims.Private.TokenType, await _tokenManager.GetTypeAsync(token));
.SetTokenType(await _tokenManager.GetTypeAsync(token));
}
}
@ -693,6 +693,31 @@ namespace OpenIddict.Server
return default;
}
// When using JWT or Data Protection tokens, the correct token type is always enforced by IdentityModel
// (using the "typ" header) or by ASP.NET Core Data Protection (using per-token-type purposes strings).
// To ensure tokens deserialized using a custom routine are of the expected type, a manual check is used,
// which requires that a special claim containing the token type be present in the security principal.
if (!string.IsNullOrEmpty(context.TokenType))
{
var type = context.Principal.GetTokenType();
if (string.IsNullOrEmpty(type))
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The deserialized principal doesn't contain the mandatory 'oi_tkn_typ' claim.")
.Append("When implementing custom token deserialization, a 'oi_tkn_typ' claim containing ")
.Append("the type of the token being processed must be added to the security principal.")
.ToString());
}
if (!string.Equals(type, context.TokenType, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(new StringBuilder()
.AppendFormat("The type of token associated with the deserialized principal ({0})", type)
.AppendFormat("doesn't match the expected token type ({0}).", context.TokenType)
.ToString());
}
}
return default;
}
}
@ -872,7 +897,7 @@ namespace OpenIddict.Server
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
.SetInternalAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
.SetInternalTokenId(await _tokenManager.GetIdAsync(token))
.SetClaim(Claims.Private.TokenType, await _tokenManager.GetTypeAsync(token));
.SetTokenType(await _tokenManager.GetTypeAsync(token));
async ValueTask TryRevokeAuthorizationChainAsync(string identifier)
{

8
src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionHandlers.cs

@ -86,7 +86,9 @@ namespace OpenIddict.Validation.DataProtection
using var buffer = new MemoryStream(protector.Unprotect(Base64UrlEncoder.DecodeBytes(context.Token)));
using var reader = new BinaryReader(buffer);
principal = _options.CurrentValue.Formatter.ReadToken(reader);
// Note: since the data format relies on a data protector using different "purposes" strings
// per token type, the token processed at this stage is guaranteed to be of the expected type.
principal = _options.CurrentValue.Formatter.ReadToken(reader)?.SetTokenType(TokenTypeHints.AccessToken);
}
catch (Exception exception)
@ -100,10 +102,6 @@ namespace OpenIddict.Validation.DataProtection
return default;
}
// Note: since the data format relies on a data protector using different "purposes" strings
// per token type, the token processed at this stage is guaranteed to be of the expected type.
context.Principal = principal.SetClaim(Claims.Private.TokenType, TokenTypeHints.AccessToken);
context.Logger.LogTrace("The self-contained DP token '{Token}' was successfully validated and the following " +
"claims could be extracted: {Claims}.", context.Token, context.Principal.Claims);

29
src/OpenIddict.Validation/OpenIddictValidationHandlers.cs

@ -218,13 +218,10 @@ namespace OpenIddict.Validation
return default;
}
// Attach the principal extracted from the token to the parent event context.
context.Principal = new ClaimsPrincipal(result.ClaimsIdentity);
// Note: tokens that are considered valid at this point are guaranteed to be access tokens,
// as a "typ" header validation is performed by the JWT handler, based on the valid values
// set in the token validation parameters (by default, only "at+jwt" is considered valid).
context.Principal.SetClaim(Claims.Private.TokenType, TokenTypeHints.AccessToken);
context.Principal = new ClaimsPrincipal(result.ClaimsIdentity).SetTokenType(TokenTypeHints.AccessToken);
context.Logger.LogTrace("The self-contained JWT token '{Token}' was successfully validated and the following " +
"claims could be extracted: {Claims}.", context.Token, context.Principal.Claims);
@ -350,7 +347,7 @@ namespace OpenIddict.Validation
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
.SetInternalAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
.SetInternalTokenId(await _tokenManager.GetIdAsync(token))
.SetClaim(Claims.Private.TokenType, await _tokenManager.GetTypeAsync(token));
.SetTokenType(await _tokenManager.GetTypeAsync(token));
}
}
@ -391,6 +388,28 @@ namespace OpenIddict.Validation
return default;
}
// When using JWT or Data Protection tokens, the correct token type is always enforced by IdentityModel
// (using the "typ" header) or by ASP.NET Core Data Protection (using per-token-type purposes strings).
// To ensure tokens deserialized using a custom routine are of the expected type, a manual check is used,
// which requires that a special claim containing the token type be present in the security principal.
var type = context.Principal.GetTokenType();
if (string.IsNullOrEmpty(type))
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The deserialized principal doesn't contain the mandatory 'oi_tkn_typ' claim.")
.Append("When implementing custom token deserialization, a 'oi_tkn_typ' claim containing ")
.Append("the type of the token being processed must be added to the security principal.")
.ToString());
}
if (!string.Equals(type, TokenTypeHints.AccessToken, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(new StringBuilder()
.AppendFormat("The type of token associated with the deserialized principal ({0})", type)
.AppendFormat("doesn't match the expected token type ({0}).", TokenTypeHints.AccessToken)
.ToString());
}
return default;
}
}

4
test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs

@ -1962,7 +1962,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
principal.SetClaim(Claims.Private.TokenType, type);
principal.SetTokenType(type);
// Act and assert
Assert.Equal(type, principal.GetTokenType());
@ -2259,7 +2259,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
principal.SetClaim(Claims.Private.TokenType, TokenTypeHints.AccessToken);
principal.SetTokenType(TokenTypeHints.AccessToken);
// Act and assert
Assert.True(principal.HasTokenType(TokenTypeHints.AccessToken));

38
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs

@ -300,6 +300,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetExpirationDate(DateTimeOffset.UtcNow - TimeSpan.FromDays(1))
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -339,6 +340,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetExpirationDate(DateTimeOffset.UtcNow - TimeSpan.FromDays(1))
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -377,6 +379,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters(Enumerable.Empty<string>())
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -417,6 +420,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Contoso")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -456,6 +460,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetPresenters("Contoso")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -495,6 +500,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Private.RedirectUri, "http://www.fabrikam.com/callback");
@ -536,6 +542,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Private.RedirectUri, "http://www.fabrikam.com/callback");
@ -578,6 +585,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -618,6 +626,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Private.CodeChallenge, "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM")
@ -660,6 +669,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Private.CodeChallenge, "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM")
@ -703,6 +713,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Private.CodeChallenge, "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM")
@ -748,6 +759,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Private.CodeChallenge, challenge)
@ -792,6 +804,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Private.CodeChallenge, challenge)
@ -842,6 +855,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetScopes(Enumerable.Empty<string>())
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -883,6 +897,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetScopes("profile", "email")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -924,6 +939,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Enumerable.Empty<string>())
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -963,6 +979,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes("profile", "email")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -1676,6 +1693,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -1739,6 +1757,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
@ -1890,6 +1909,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -1952,6 +1972,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2006,6 +2027,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2074,6 +2096,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetPresenters("Fabrikam")
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2138,6 +2161,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2216,6 +2240,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2274,6 +2299,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
@ -2367,6 +2393,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2467,6 +2494,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
@ -2564,6 +2592,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetPresenters("Fabrikam")
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
@ -2636,6 +2665,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
@ -2719,6 +2749,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetPresenters("Fabrikam")
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
@ -2777,6 +2808,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
@ -2873,6 +2905,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2950,6 +2983,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
@ -3045,6 +3079,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
@ -3136,6 +3171,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -3217,6 +3253,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -3310,6 +3347,7 @@ namespace OpenIddict.Server.FunctionalTests
builder.UseInlineHandler(context =>
{
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(context.TokenType)
.SetPresenters("Fabrikam")
.SetInternalTokenId("0270F515-C5B1-4FBF-B673-D7CAF7CCDABC")
.SetClaim(Claims.Subject, "Bob le Bricoleur");

132
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs

@ -197,6 +197,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AccessToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AccessToken)
.SetClaim(Claims.Subject, "Bob le Magnifique");
return default;
@ -360,6 +361,109 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(new[] { Scopes.OpenId, Scopes.Profile }, (string[]) response[Claims.Private.Scope]);
}
[Fact]
public async Task ProcessAuthentication_MissingTokenTypeThrowsAnException()
{
// Arrange
var client = CreateClient(options =>
{
options.EnableDegradedMode();
options.SetUserinfoEndpointUris("/authenticate");
options.AddEventHandler<HandleUserinfoRequestContext>(builder =>
builder.UseInlineHandler(context =>
{
context.SkipRequest();
return default;
}));
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{
builder.UseInlineHandler(context =>
{
Assert.Equal("access_token", context.Token);
Assert.Equal(TokenTypeHints.AccessToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(null)
.SetClaim(Claims.Subject, "Bob le Magnifique");
return default;
});
builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500);
});
});
// Act and assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(delegate
{
return client.GetAsync("/authenticate", new OpenIddictRequest
{
AccessToken = "access_token"
});
});
// Assert
Assert.Equal(new StringBuilder()
.AppendLine("The deserialized principal doesn't contain the mandatory 'oi_tkn_typ' claim.")
.Append("When implementing custom token deserialization, a 'oi_tkn_typ' claim containing ")
.Append("the type of the token being processed must be added to the security principal.")
.ToString(), exception.Message);
}
[Fact]
public async Task ProcessAuthentication_InvalidTokenTypeThrowsAnException()
{
// Arrange
var client = CreateClient(options =>
{
options.EnableDegradedMode();
options.SetUserinfoEndpointUris("/authenticate");
options.AddEventHandler<HandleUserinfoRequestContext>(builder =>
builder.UseInlineHandler(context =>
{
context.SkipRequest();
return default;
}));
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{
builder.UseInlineHandler(context =>
{
Assert.Equal("access_token", context.Token);
Assert.Equal(TokenTypeHints.AccessToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetClaim(Claims.Subject, "Bob le Magnifique");
return default;
});
builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500);
});
});
// Act and assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(delegate
{
return client.GetAsync("/authenticate", new OpenIddictRequest
{
AccessToken = "access_token"
});
});
// Assert
Assert.Equal(new StringBuilder()
.AppendFormat("The type of token associated with the deserialized principal ({0})", TokenTypeHints.AuthorizationCode)
.AppendFormat("doesn't match the expected token type ({0}).", TokenTypeHints.AccessToken)
.ToString(), exception.Message);
}
[Fact]
public async Task ProcessAuthentication_MissingIdTokenHintReturnsNull()
{
@ -441,6 +545,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.IdToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.IdToken)
.SetClaim(Claims.Subject, "Bob le Magnifique");
return default;
@ -545,6 +650,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetClaim(Claims.Subject, "Bob le Magnifique")
.SetPresenters("Fabrikam");
@ -650,6 +756,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetClaim(Claims.Subject, "Bob le Magnifique");
return default;
@ -794,6 +901,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal("SlAV32hkKG", context.Token);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AccessToken)
.SetClaim(Claims.Subject, "Bob le Magnifique");
return default;
@ -1280,6 +1388,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.Profile, Scopes.OfflineAccess)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -1411,6 +1520,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -1461,6 +1571,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@ -1706,6 +1817,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetScopes(Scopes.OfflineAccess)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -1757,6 +1869,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OfflineAccess)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -1807,6 +1920,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OfflineAccess)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2074,6 +2188,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetScopes(Scopes.OpenId)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2125,6 +2240,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2394,6 +2510,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Prefixes.Private + "_private_claim", "value");
@ -2443,6 +2560,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2484,6 +2602,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2521,6 +2640,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2573,6 +2693,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2642,6 +2763,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.AuthorizationCode, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
.SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2719,6 +2841,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2782,6 +2905,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2838,6 +2962,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -2918,6 +3043,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
@ -3004,6 +3130,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
@ -3077,6 +3204,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -3134,6 +3262,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -3192,6 +3321,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -3254,6 +3384,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
@ -3314,6 +3445,7 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType);
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
.SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");

Loading…
Cancel
Save