diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs index 327c05f8..4832f6a3 100644 --- a/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs +++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs @@ -99,11 +99,6 @@ namespace OpenIddict.Abstractions throw new ArgumentException("The value cannot be null or empty.", nameof(value)); } - if (string.IsNullOrEmpty(request.AcrValues)) - { - return false; - } - return HasValue(request.AcrValues, value, Separators.Space); } @@ -124,11 +119,6 @@ namespace OpenIddict.Abstractions throw new ArgumentException("The prompt cannot be null or empty.", nameof(prompt)); } - if (string.IsNullOrEmpty(request.Prompt)) - { - return false; - } - return HasValue(request.Prompt, prompt, Separators.Space); } @@ -149,11 +139,6 @@ namespace OpenIddict.Abstractions throw new ArgumentException("The response type cannot be null or empty.", nameof(type)); } - if (string.IsNullOrEmpty(request.ResponseType)) - { - return false; - } - return HasValue(request.ResponseType, type, Separators.Space); } @@ -174,11 +159,6 @@ namespace OpenIddict.Abstractions throw new ArgumentException("The scope cannot be null or empty.", nameof(scope)); } - if (string.IsNullOrEmpty(request.Scope)) - { - return false; - } - return HasValue(request.Scope, scope, Separators.Space); } @@ -1192,25 +1172,7 @@ namespace OpenIddict.Abstractions /// The claims principal. /// The access token lifetime or null if the claim cannot be found. public static TimeSpan? GetAccessTokenLifetime([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - var value = principal.GetClaim(Claims.Private.AccessTokenLifetime); - if (string.IsNullOrEmpty(value)) - { - return null; - } - - if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) - { - return TimeSpan.FromSeconds(result); - } - - return null; - } + => GetLifetime(principal, Claims.Private.AccessTokenLifetime); /// /// Gets the authorization code lifetime associated with the claims principal. @@ -1218,25 +1180,7 @@ namespace OpenIddict.Abstractions /// The claims principal. /// The authorization code lifetime or null if the claim cannot be found. public static TimeSpan? GetAuthorizationCodeLifetime([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - var value = principal.GetClaim(Claims.Private.AuthorizationCodeLifetime); - if (string.IsNullOrEmpty(value)) - { - return null; - } - - if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) - { - return TimeSpan.FromSeconds(result); - } - - return null; - } + => GetLifetime(principal, Claims.Private.AuthorizationCodeLifetime); /// /// Gets the device code lifetime associated with the claims principal. @@ -1244,25 +1188,7 @@ namespace OpenIddict.Abstractions /// The claims principal. /// The device code lifetime or null if the claim cannot be found. public static TimeSpan? GetDeviceCodeLifetime([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - var value = principal.GetClaim(Claims.Private.DeviceCodeLifetime); - if (string.IsNullOrEmpty(value)) - { - return null; - } - - if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) - { - return TimeSpan.FromSeconds(result); - } - - return null; - } + => GetLifetime(principal, Claims.Private.DeviceCodeLifetime); /// /// Gets the identity token lifetime associated with the claims principal. @@ -1270,25 +1196,7 @@ namespace OpenIddict.Abstractions /// The claims principal. /// The identity token lifetime or null if the claim cannot be found. public static TimeSpan? GetIdentityTokenLifetime([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - var value = principal.GetClaim(Claims.Private.IdentityTokenLifetime); - if (string.IsNullOrEmpty(value)) - { - return null; - } - - if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) - { - return TimeSpan.FromSeconds(result); - } - - return null; - } + => GetLifetime(principal, Claims.Private.IdentityTokenLifetime); /// /// Gets the refresh token lifetime associated with the claims principal. @@ -1296,25 +1204,7 @@ namespace OpenIddict.Abstractions /// The claims principal. /// The refresh token lifetime or null if the claim cannot be found. public static TimeSpan? GetRefreshTokenLifetime([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - var value = principal.GetClaim(Claims.Private.RefreshTokenLifetime); - if (string.IsNullOrEmpty(value)) - { - return null; - } - - if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) - { - return TimeSpan.FromSeconds(result); - } - - return null; - } + => GetLifetime(principal, Claims.Private.RefreshTokenLifetime); /// /// Gets the user code lifetime associated with the claims principal. @@ -1322,25 +1212,7 @@ namespace OpenIddict.Abstractions /// The claims principal. /// The user code lifetime or null if the claim cannot be found. public static TimeSpan? GetUserCodeLifetime([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - var value = principal.GetClaim(Claims.Private.UserCodeLifetime); - if (string.IsNullOrEmpty(value)) - { - return null; - } - - if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) - { - return TimeSpan.FromSeconds(result); - } - - return null; - } + => GetLifetime(principal, Claims.Private.UserCodeLifetime); /// /// Gets the internal authorization identifier associated with the claims principal. @@ -1366,96 +1238,6 @@ namespace OpenIddict.Abstractions public static string GetTokenType([NotNull] this ClaimsPrincipal principal) => principal.GetClaim(Claims.Private.TokenType); - /// - /// Gets a boolean value indicating whether the claims principal corresponds to an access token. - /// - /// The claims principal. - /// true if the principal corresponds to an access token. - public static bool IsAccessToken([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - return string.Equals(principal.GetTokenType(), TokenTypeHints.AccessToken, StringComparison.OrdinalIgnoreCase); - } - - /// - /// Gets a boolean value indicating whether the claims principal corresponds to an access token. - /// - /// The claims principal. - /// true if the principal corresponds to an authorization code. - public static bool IsAuthorizationCode([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - return string.Equals(principal.GetTokenType(), TokenTypeHints.AuthorizationCode, StringComparison.OrdinalIgnoreCase); - } - - /// - /// Gets a boolean value indicating whether the claims principal corresponds to a device code. - /// - /// The claims principal. - /// true if the principal corresponds to a device code. - public static bool IsDeviceCode([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - return string.Equals(principal.GetTokenType(), TokenTypeHints.DeviceCode, StringComparison.OrdinalIgnoreCase); - } - - /// - /// Gets a boolean value indicating whether the claims principal corresponds to an identity token. - /// - /// The claims principal. - /// true if the principal corresponds to an identity token. - public static bool IsIdentityToken([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - return string.Equals(principal.GetTokenType(), TokenTypeHints.IdToken, StringComparison.OrdinalIgnoreCase); - } - - /// - /// Gets a boolean value indicating whether the claims principal corresponds to a refresh token. - /// - /// The claims principal. - /// true if the principal corresponds to a refresh token. - public static bool IsRefreshToken([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - return string.Equals(principal.GetTokenType(), TokenTypeHints.RefreshToken, StringComparison.OrdinalIgnoreCase); - } - - /// - /// Gets a boolean value indicating whether the claims principal corresponds to a user code. - /// - /// The claims principal. - /// true if the principal corresponds to a user code. - public static bool IsUserCode([NotNull] this ClaimsPrincipal principal) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - return string.Equals(principal.GetTokenType(), TokenTypeHints.UserCode, StringComparison.OrdinalIgnoreCase); - } - /// /// Determines whether the claims principal contains at least one audience. /// @@ -1633,30 +1415,35 @@ namespace OpenIddict.Abstractions } /// - /// Sets the creation date in the claims principal. + /// Determines whether the token type associated with the claims principal matches the specified type. /// /// The claims principal. - /// The creation date - /// The claims principal. - public static ClaimsPrincipal SetCreationDate([NotNull] this ClaimsPrincipal principal, [CanBeNull] DateTimeOffset? date) + /// The token type. + /// true if the token type matches the specified type. + public static bool HasTokenType([NotNull] this ClaimsPrincipal principal, [NotNull] string type) { if (principal == null) { throw new ArgumentNullException(nameof(principal)); } - principal.RemoveClaims(Claims.IssuedAt); - - if (date.HasValue) + if (string.IsNullOrEmpty(type)) { - var value = date?.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture); - var claim = new Claim(Claims.IssuedAt, value, ClaimValueTypes.Integer64); - ((ClaimsIdentity) principal.Identity).AddClaim(claim); + throw new ArgumentException("The token type cannot be null or empty.", nameof(type)); } - return principal; + return string.Equals(principal.GetTokenType(), type, StringComparison.OrdinalIgnoreCase); } + /// + /// Sets the creation date in the claims principal. + /// + /// The claims principal. + /// The creation date + /// The claims principal. + public static ClaimsPrincipal SetCreationDate([NotNull] this ClaimsPrincipal principal, [CanBeNull] DateTimeOffset? date) + => SetDateClaim(principal, Claims.IssuedAt, date); + /// /// Sets the expiration date in the claims principal. /// @@ -1664,23 +1451,7 @@ namespace OpenIddict.Abstractions /// The expiration date /// The claims principal. public static ClaimsPrincipal SetExpirationDate([NotNull] this ClaimsPrincipal principal, [CanBeNull] DateTimeOffset? date) - { - if (principal == null) - { - throw new ArgumentNullException(nameof(principal)); - } - - principal.RemoveClaims(Claims.ExpiresAt); - - if (date.HasValue) - { - var value = date?.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture); - var claim = new Claim(Claims.ExpiresAt, value, ClaimValueTypes.Integer64); - ((ClaimsIdentity) principal.Identity).AddClaim(claim); - } - - return principal; - } + => SetDateClaim(principal, Claims.ExpiresAt, date); /// /// Sets the audiences list in the claims principal. @@ -1916,7 +1687,11 @@ namespace OpenIddict.Abstractions private static bool HasValue(string source, string value, char[] separators) { - Debug.Assert(!string.IsNullOrEmpty(source), "The source string shouldn't be null or empty."); + if (string.IsNullOrEmpty(source)) + { + return false; + } + Debug.Assert(!string.IsNullOrEmpty(value), "The value string shouldn't be null or empty."); Debug.Assert(separators?.Length != 0, "The separators collection shouldn't be null or empty."); @@ -1996,5 +1771,45 @@ namespace OpenIddict.Abstractions return false; } + + private static TimeSpan? GetLifetime(ClaimsPrincipal principal, string type) + { + if (principal == null) + { + throw new ArgumentNullException(nameof(principal)); + } + + var value = principal.GetClaim(type); + if (string.IsNullOrEmpty(value)) + { + return null; + } + + if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double result)) + { + return TimeSpan.FromSeconds(result); + } + + return null; + } + + private static ClaimsPrincipal SetDateClaim(ClaimsPrincipal principal, string type, DateTimeOffset? date) + { + if (principal == null) + { + throw new ArgumentNullException(nameof(principal)); + } + + principal.RemoveClaims(type); + + if (date.HasValue) + { + var value = date?.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture); + var claim = new Claim(type, value, ClaimValueTypes.Integer64); + ((ClaimsIdentity)principal.Identity).AddClaim(claim); + } + + return principal; + } } } diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs index e5b5e668..c61ca942 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs @@ -837,8 +837,10 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (!context.Principal.IsAccessToken() && !context.Principal.IsAuthorizationCode() && - !context.Principal.IsIdentityToken() && !context.Principal.IsRefreshToken()) + if (!context.Principal.HasTokenType(TokenTypeHints.AccessToken) && + !context.Principal.HasTokenType(TokenTypeHints.AuthorizationCode) && + !context.Principal.HasTokenType(TokenTypeHints.IdToken) && + !context.Principal.HasTokenType(TokenTypeHints.RefreshToken)) { context.Logger.LogError("The introspection request was rejected because " + "the received token was of an unsupported type."); @@ -889,7 +891,7 @@ namespace OpenIddict.Server // When the introspected token is an authorization code, the caller must be // listed as a presenter (i.e the party the authorization code was issued to). - if (context.Principal.IsAuthorizationCode()) + if (context.Principal.HasTokenType(TokenTypeHints.AuthorizationCode)) { if (!context.Principal.HasPresenter()) { @@ -915,7 +917,7 @@ namespace OpenIddict.Server // (i.e the party the token was issued to) or as an audience (i.e a resource server/API). // If the access token doesn't contain any explicit presenter/audience, the token is assumed // to be not specific to any resource server/client application and the check is bypassed. - if (context.Principal.IsAccessToken() && + if (context.Principal.HasTokenType(TokenTypeHints.AccessToken) && context.Principal.HasAudience() && !context.Principal.HasAudience(context.ClientId) && context.Principal.HasPresenter() && !context.Principal.HasPresenter(context.ClientId)) { @@ -933,8 +935,8 @@ namespace OpenIddict.Server // (i.e the client application the identity token was initially issued to). // If the identity token doesn't contain any explicit audience, the token is // assumed to be not specific to any client application and the check is bypassed. - if (context.Principal.IsIdentityToken() && context.Principal.HasAudience() && - !context.Principal.HasAudience(context.ClientId)) + if (context.Principal.HasTokenType(TokenTypeHints.IdToken) && + context.Principal.HasAudience() && !context.Principal.HasAudience(context.ClientId)) { context.Logger.LogError("The introspection request was rejected because the " + "identity token was issued to a different client."); @@ -950,8 +952,8 @@ namespace OpenIddict.Server // listed as a presenter (i.e the party the token was issued to). // If the refresh token doesn't contain any explicit presenter, the token is // assumed to be not specific to any client application and the check is bypassed. - if (context.Principal.IsRefreshToken() && context.Principal.HasPresenter() && - !context.Principal.HasPresenter(context.ClientId)) + if (context.Principal.HasTokenType(TokenTypeHints.RefreshToken) && + context.Principal.HasPresenter() && !context.Principal.HasPresenter(context.ClientId)) { context.Logger.LogError("The introspection request was rejected because the " + "refresh token was issued to a different client."); @@ -1050,7 +1052,7 @@ namespace OpenIddict.Server // Note: only set "token_type" when the received token is an access token. // See https://tools.ietf.org/html/rfc7662#section-2.2 // and https://tools.ietf.org/html/rfc6749#section-5.1 for more information. - if (context.Principal.IsAccessToken()) + if (context.Principal.HasTokenType(TokenTypeHints.AccessToken)) { context.TokenType = TokenTypes.Bearer; } @@ -1104,7 +1106,7 @@ namespace OpenIddict.Server } // Don't return application-specific claims if the token is not an access or identity token. - if (!context.Principal.IsAccessToken() && !context.Principal.IsIdentityToken()) + if (!context.Principal.HasTokenType(TokenTypeHints.AccessToken) && !context.Principal.HasTokenType(TokenTypeHints.IdToken)) { return; } diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs index 6a55ad35..fc73ca89 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs @@ -783,9 +783,9 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (!context.Principal.IsAccessToken() && - !context.Principal.IsAuthorizationCode() && - !context.Principal.IsRefreshToken()) + if (!context.Principal.HasTokenType(TokenTypeHints.AccessToken) && + !context.Principal.HasTokenType(TokenTypeHints.AuthorizationCode) && + !context.Principal.HasTokenType(TokenTypeHints.RefreshToken)) { context.Logger.LogError("The revocation request was rejected because " + "the received token was of an unsupported type."); @@ -798,7 +798,7 @@ namespace OpenIddict.Server } // If the received token is an access token, return an error if reference tokens are not enabled. - if (!context.Options.UseReferenceAccessTokens && context.Principal.IsAccessToken()) + if (!context.Options.UseReferenceAccessTokens && context.Principal.HasTokenType(TokenTypeHints.AccessToken)) { context.Logger.LogError("The revocation request was rejected because the access token was not revocable."); @@ -848,7 +848,7 @@ namespace OpenIddict.Server // When the revoked token is an authorization code, the caller must be // listed as a presenter (i.e the party the authorization code was issued to). - if (context.Principal.IsAuthorizationCode()) + if (context.Principal.HasTokenType(TokenTypeHints.AuthorizationCode)) { if (!context.Principal.HasPresenter()) { @@ -874,7 +874,7 @@ namespace OpenIddict.Server // (i.e the party the token was issued to) or as an audience (i.e a resource server/API). // If the access token doesn't contain any explicit presenter/audience, the token is assumed // to be not specific to any resource server/client application and the check is bypassed. - if (context.Principal.IsAccessToken() && + if (context.Principal.HasTokenType(TokenTypeHints.AccessToken) && context.Principal.HasAudience() && !context.Principal.HasAudience(context.ClientId) && context.Principal.HasPresenter() && !context.Principal.HasPresenter(context.ClientId)) { @@ -892,8 +892,8 @@ namespace OpenIddict.Server // (i.e the client application the identity token was initially issued to). // If the identity token doesn't contain any explicit audience, the token is // assumed to be not specific to any client application and the check is bypassed. - if (context.Principal.IsIdentityToken() && context.Principal.HasAudience() && - !context.Principal.HasAudience(context.ClientId)) + if (context.Principal.HasTokenType(TokenTypeHints.IdToken) && + context.Principal.HasAudience() && !context.Principal.HasAudience(context.ClientId)) { context.Logger.LogError("The revocation request was rejected because the " + "identity token was issued to a different client."); @@ -909,8 +909,8 @@ namespace OpenIddict.Server // listed as a presenter (i.e the party the token was issued to). // If the refresh token doesn't contain any explicit presenter, the token is // assumed to be not specific to any client application and the check is bypassed. - if (context.Principal.IsRefreshToken() && context.Principal.HasPresenter() && - !context.Principal.HasPresenter(context.ClientId)) + if (context.Principal.HasTokenType(TokenTypeHints.RefreshToken) && + context.Principal.HasPresenter() && !context.Principal.HasPresenter(context.ClientId)) { context.Logger.LogError("The revocation request was rejected because the " + "refresh token was issued to a different client."); diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs index df939bfd..f505c7be 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs @@ -501,7 +501,7 @@ namespace OpenIddict.Server context.Principal.SetDestinations(destinations); } - if (context.Principal.IsAccessToken()) + if (context.Principal.HasTokenType(TokenTypeHints.AccessToken)) { // Map the standardized "azp" and "scope" claims to their "oi_" equivalent so that // the ClaimsPrincipal extensions exposed by OpenIddict return consistent results. diff --git a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs index 1590ed22..acbdcdaa 100644 --- a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs +++ b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs @@ -2189,199 +2189,45 @@ namespace OpenIddict.Abstractions.Tests.Primitives } [Fact] - public void IsAccessToken_ThrowsAnExceptionForNullPrincipal() + public void HasTokenType_ThrowsAnExceptionForNullPrincipal() { // Arrange var principal = (ClaimsPrincipal) null; // Act and assert - var exception = Assert.Throws(() => principal.IsAccessToken()); + var exception = Assert.Throws(() => principal.HasTokenType(TokenTypeHints.AccessToken)); Assert.Equal("principal", exception.ParamName); } [Theory] - [InlineData(null, false)] - [InlineData("unknown", false)] - [InlineData(TokenTypeHints.AccessToken, true)] - [InlineData(TokenTypeHints.AuthorizationCode, false)] - [InlineData(TokenTypeHints.DeviceCode, false)] - [InlineData(TokenTypeHints.IdToken, false)] - [InlineData(TokenTypeHints.RefreshToken, false)] - [InlineData(TokenTypeHints.UserCode, false)] - public void IsAccessToken_ReturnsExpectedResult(string type, bool result) - { - // Arrange - var identity = new ClaimsIdentity(); - var principal = new ClaimsPrincipal(identity); - - principal.SetClaim(Claims.Private.TokenType, type); - - // Act and assert - Assert.Equal(result, principal.IsAccessToken()); - } - - [Fact] - public void IsAuthorizationCode_ThrowsAnExceptionForNullPrincipal() - { - // Arrange - var principal = (ClaimsPrincipal) null; - - // Act and assert - var exception = Assert.Throws(() => principal.IsAuthorizationCode()); - - Assert.Equal("principal", exception.ParamName); - } - - [Theory] - [InlineData(null, false)] - [InlineData("unknown", false)] - [InlineData(TokenTypeHints.AccessToken, false)] - [InlineData(TokenTypeHints.AuthorizationCode, true)] - [InlineData(TokenTypeHints.DeviceCode, false)] - [InlineData(TokenTypeHints.IdToken, false)] - [InlineData(TokenTypeHints.RefreshToken, false)] - [InlineData(TokenTypeHints.UserCode, false)] - public void IsAuthorizationCode_ReturnsExpectedResult(string type, bool result) - { - // Arrange - var identity = new ClaimsIdentity(); - var principal = new ClaimsPrincipal(identity); - - principal.SetClaim(Claims.Private.TokenType, type); - - // Act and assert - Assert.Equal(result, principal.IsAuthorizationCode()); - } - - [Fact] - public void IsDeviceCode_ThrowsAnExceptionForNullPrincipal() - { - // Arrange - var principal = (ClaimsPrincipal) null; - - // Act and assert - var exception = Assert.Throws(() => principal.IsDeviceCode()); - - Assert.Equal("principal", exception.ParamName); - } - - [Theory] - [InlineData(null, false)] - [InlineData("unknown", false)] - [InlineData(TokenTypeHints.AccessToken, false)] - [InlineData(TokenTypeHints.AuthorizationCode, false)] - [InlineData(TokenTypeHints.DeviceCode, true)] - [InlineData(TokenTypeHints.IdToken, false)] - [InlineData(TokenTypeHints.RefreshToken, false)] - [InlineData(TokenTypeHints.UserCode, false)] - public void IsDeviceCode_ReturnsExpectedResult(string type, bool result) - { - // Arrange - var identity = new ClaimsIdentity(); - var principal = new ClaimsPrincipal(identity); - - principal.SetClaim(Claims.Private.TokenType, type); - - // Act and assert - Assert.Equal(result, principal.IsDeviceCode()); - } - - [Fact] - public void IsIdentityToken_ThrowsAnExceptionForNullPrincipal() - { - // Arrange - var principal = (ClaimsPrincipal) null; - - // Act and assert - var exception = Assert.Throws(() => principal.IsIdentityToken()); - - Assert.Equal("principal", exception.ParamName); - } - - [Theory] - [InlineData(null, false)] - [InlineData("unknown", false)] - [InlineData(TokenTypeHints.AccessToken, false)] - [InlineData(TokenTypeHints.AuthorizationCode, false)] - [InlineData(TokenTypeHints.DeviceCode, false)] - [InlineData(TokenTypeHints.IdToken, true)] - [InlineData(TokenTypeHints.RefreshToken, false)] - [InlineData(TokenTypeHints.UserCode, false)] - public void IsIdentityToken_ReturnsExpectedResult(string type, bool result) + [InlineData(null)] + [InlineData("")] + public void HasTokenType_ThrowsAnExceptionForNullOrEmptyTokenType(string type) { // Arrange var identity = new ClaimsIdentity(); var principal = new ClaimsPrincipal(identity); - principal.SetClaim(Claims.Private.TokenType, type); - - // Act and assert - Assert.Equal(result, principal.IsIdentityToken()); - } - - [Fact] - public void IsRefreshToken_ThrowsAnExceptionForNullPrincipal() - { - // Arrange - var principal = (ClaimsPrincipal) null; - // Act and assert - var exception = Assert.Throws(() => principal.IsRefreshToken()); + var exception = Assert.Throws(() => principal.HasTokenType(type)); - Assert.Equal("principal", exception.ParamName); - } - - [Theory] - [InlineData(null, false)] - [InlineData("unknown", false)] - [InlineData(TokenTypeHints.AccessToken, false)] - [InlineData(TokenTypeHints.AuthorizationCode, false)] - [InlineData(TokenTypeHints.IdToken, false)] - [InlineData(TokenTypeHints.RefreshToken, true)] - public void IsRefreshToken_ReturnsExpectedResult(string type, bool result) - { - // Arrange - var identity = new ClaimsIdentity(); - var principal = new ClaimsPrincipal(identity); - - principal.SetClaim(Claims.Private.TokenType, type); - - // Act and assert - Assert.Equal(result, principal.IsRefreshToken()); + Assert.Equal("type", exception.ParamName); + Assert.StartsWith("The token type cannot be null or empty.", exception.Message); } [Fact] - public void IsUserCode_ThrowsAnExceptionForNullPrincipal() - { - // Arrange - var principal = (ClaimsPrincipal) null; - - // Act and assert - var exception = Assert.Throws(() => principal.IsUserCode()); - - Assert.Equal("principal", exception.ParamName); - } - - [Theory] - [InlineData(null, false)] - [InlineData("unknown", false)] - [InlineData(TokenTypeHints.AccessToken, false)] - [InlineData(TokenTypeHints.AuthorizationCode, false)] - [InlineData(TokenTypeHints.DeviceCode, false)] - [InlineData(TokenTypeHints.IdToken, false)] - [InlineData(TokenTypeHints.RefreshToken, false)] - [InlineData(TokenTypeHints.UserCode, true)] - public void IsUserCode_ReturnsExpectedResult(string type, bool result) + public void HasTokenType_ReturnsExpectedResult() { // Arrange var identity = new ClaimsIdentity(); var principal = new ClaimsPrincipal(identity); - principal.SetClaim(Claims.Private.TokenType, type); + principal.SetClaim(Claims.Private.TokenType, TokenTypeHints.AccessToken); // Act and assert - Assert.Equal(result, principal.IsUserCode()); + Assert.True(principal.HasTokenType(TokenTypeHints.AccessToken)); + Assert.False(principal.HasTokenType(TokenTypeHints.RefreshToken)); } [Theory]