Browse Source

Automatically normalize "amr" claims in identity tokens to ensure a JSON array is always returned

pull/2233/head
Kévin Chalet 1 year ago
parent
commit
ff752efe09
  1. 25
      src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs
  2. 14
      src/OpenIddict.Server/OpenIddictServerHandlers.cs

25
src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs

@ -1384,6 +1384,8 @@ public static partial class OpenIddictServerHandlers
Claims.Private.Scope when context.TokenType is TokenTypeHints.AccessToken => false,
Claims.AuthenticationMethodReference when context.TokenType is TokenTypeHints.IdToken => false,
_ => true
});
@ -1398,10 +1400,27 @@ public static partial class OpenIddictServerHandlers
var audiences = context.Principal.GetAudiences();
if (audiences.Any())
{
claims.Add(Claims.Audience, audiences.Length switch
claims.Add(Claims.Audience, audiences switch
{
[string audience] => audience,
_ => audiences.ToArray()
});
}
}
// Note: unlike other claims (e.g "aud"), the "amr" claim MUST be represented as a unique
// claim representing a JSON array, even if a single authentication method reference is
// present in the collection. To ensure an array is always returned, the "amr" claim is
// filtered out from the clone principal and manually added as a "string[]" claim value.
if (context.TokenType is TokenTypeHints.IdToken)
{
var methods = context.Principal.GetClaims(Claims.AuthenticationMethodReference);
if (methods.Any())
{
claims.Add(Claims.AuthenticationMethodReference, methods switch
{
1 => audiences.ElementAt(0),
_ => audiences
[string method] => [method],
_ => methods.ToArray()
});
}
}

14
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -2216,8 +2216,7 @@ public static partial class OpenIddictServerHandlers
=> values is [{ ValueType: ClaimValueTypes.String }],
// The following claims MUST be represented as unique strings or array of strings.
Claims.AuthenticationMethodReference or Claims.Private.Audience or
Claims.Private.Presenter or Claims.Private.Resource
Claims.Private.Audience or Claims.Private.Presenter or Claims.Private.Resource
=> values.TrueForAll(static value => value.ValueType is ClaimValueTypes.String) ||
// Note: a unique claim using the special JSON_ARRAY claim value type is allowed
// if the individual elements of the parsed JSON array are all string values.
@ -2225,6 +2224,17 @@ public static partial class OpenIddictServerHandlers
JsonSerializer.Deserialize<JsonElement>(value) is { ValueKind: JsonValueKind.Array } element &&
OpenIddictHelpers.ValidateArrayElements(element, JsonValueKind.String)),
// Note: unlike other claims (e.g "aud"), the "amr" claim MUST be represented as a unique
// claim representing a JSON array, even if a single authentication method reference
// is present in the collection. To avoid forcing users to use the special JSON_ARRAY
// value type, string values are also allowed here and normalized to JSON arrays
// by OpenIddict when generating an identity token based on the specified principal.
Claims.AuthenticationMethodReference
=> values.TrueForAll(static value => value.ValueType is ClaimValueTypes.String) ||
(values is [{ ValueType: JsonClaimValueTypes.JsonArray, Value: string value }] &&
JsonSerializer.Deserialize<JsonElement>(value) is { ValueKind: JsonValueKind.Array } element &&
OpenIddictHelpers.ValidateArrayElements(element, JsonValueKind.String)),
// The following claims MUST be represented as unique integers.
Claims.Private.AccessTokenLifetime or Claims.Private.AuthorizationCodeLifetime or
Claims.Private.DeviceCodeLifetime or Claims.Private.IdentityTokenLifetime or

Loading…
Cancel
Save