From 1517cddc2231ab3a0981d72e5c4e802f68e98fe9 Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Tue, 18 Jun 2024 21:23:42 +0000 Subject: [PATCH 1/5] Add a constant for the profile scope in OpenIdConnectScope class (#2647) Co-authored-by: joegoldman2 <147369450+joegoldman@users.noreply.github.com> --- .../OpenIdConnectScope.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdConnectScope.cs b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdConnectScope.cs index 6a3c753e77..c32880eaaf 100644 --- a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdConnectScope.cs +++ b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdConnectScope.cs @@ -37,10 +37,15 @@ public static class OpenIdConnectScope public const string OpenIdProfile = "openid profile"; /// - /// Indicates phone profile scope see: https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims. + /// Indicates phone scope see: https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims. /// public const string Phone = "phone"; + /// + /// Indicates profile scope see: https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims. + /// + public const string Profile = "profile"; + /// /// Indicates user_impersonation scope for Azure Active Directory. /// From bd2bf8e7098e54b83729c716c30ca29aade7dc31 Mon Sep 17 00:00:00 2001 From: kellyyangsong <69649063+kellyyangsong@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:35:19 -0700 Subject: [PATCH 2/5] Rm SkipAuthenticationTagLengthValidation and UseShortNameForRsaOaepKey App Context Switches (#2644) * rm app context switches * update tests * update changelog --- CHANGELOG.md | 2 +- .../AuthenticatedEncryptionProvider.cs | 9 +-- .../LogMessages.cs | 2 +- .../X509EncryptingCredentials.cs | 14 +--- .../JsonWebTokenHandlerTests.cs | 50 +------------- .../EncryptingCredentialsTests.cs | 8 +-- .../MultiThreadingTests.cs | 4 +- .../X509EncryptingCredentialsTests.cs | 8 +-- ...tyTokenHandlerTests.WithContextSwitches.cs | 66 ------------------- 9 files changed, 16 insertions(+), 147 deletions(-) delete mode 100644 test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.WithContextSwitches.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index f1991880f9..5a9f0c8101 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ See the [releases](https://github.com/AzureAD/azure-activedirectory-identitymode ### Breaking changes: - IdentityModel 8x no longer supports .net461, which has reached end of life and is no longer supported. See issue [#2544](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2544) for details. - Two IdentityModel extension dlls `Microsoft.IdentityModel.KeyVaultExtensions` and `Microsoft.IdentityModel.ManagedKeyVaultSecurityKey` were using ADAL, which is no longer supported . The affected packages have been removed, as the replacement is to use [Microsoft.Identity.Web](https://github.com/AzureAD/microsoft-identity-web/wiki/Certificates). See issue [#2454](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2454) for details. -- `AppContext.SetSwitch` which were included in IdentityModel 7x, have been removed and are the default in IdentityModel 8x. The result is a more performant IdentityModel by default. See issue [#2629](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2629) for details. +- `AppContext.SetSwitch` which were included in IdentityModel 7x, have been removed and are the default in IdentityModel 8x. The result is a more performant IdentityModel by default. See issue [#2629](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2629) and https://aka.ms/IdentityModel8x for details. 7.6.1 ===== diff --git a/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs b/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs index b6b063936d..b9459a1af8 100644 --- a/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs +++ b/src/Microsoft.IdentityModel.Tokens/Encryption/AuthenticatedEncryptionProvider.cs @@ -33,7 +33,6 @@ private struct AuthenticatedKeys private DecryptionDelegate DecryptFunction; private EncryptionDelegate EncryptFunction; private const string _className = "Microsoft.IdentityModel.Tokens.AuthenticatedEncryptionProvider"; - internal const string _skipValidationOfAuthenticationTagLength = "Switch.Microsoft.IdentityModel.SkipAuthenticationTagLengthValidation"; /// /// Initializes a new instance of the class used for encryption and decryption. @@ -167,8 +166,7 @@ private AuthenticatedEncryptionResult EncryptWithAesCbc(byte[] plaintext, byte[] private byte[] DecryptWithAesCbc(byte[] ciphertext, byte[] authenticatedData, byte[] iv, byte[] authenticationTag) { // Verify authentication Tag - if (ShouldValidateAuthenticationTagLength() - && SymmetricSignatureProvider.ExpectedSignatureSizeInBytes.TryGetValue(Algorithm, out int expectedTagLength) + if (SymmetricSignatureProvider.ExpectedSignatureSizeInBytes.TryGetValue(Algorithm, out int expectedTagLength) && expectedTagLength != authenticationTag.Length) throw LogHelper.LogExceptionMessage(new SecurityTokenDecryptionFailedException( LogHelper.FormatInvariant(LogMessages.IDX10625, authenticationTag.Length, expectedTagLength, Base64UrlEncoder.Encode(authenticationTag), Algorithm))); @@ -197,11 +195,6 @@ private byte[] DecryptWithAesCbc(byte[] ciphertext, byte[] authenticatedData, by } } - private static bool ShouldValidateAuthenticationTagLength() - { - return !(AppContext.TryGetSwitch(_skipValidationOfAuthenticationTagLength, out bool skipValidation) && skipValidation); - } - private AuthenticatedKeys CreateAuthenticatedKeys() { ValidateKeySize(Key, Algorithm); diff --git a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs index d54c07479c..689b2ccb9d 100644 --- a/src/Microsoft.IdentityModel.Tokens/LogMessages.cs +++ b/src/Microsoft.IdentityModel.Tokens/LogMessages.cs @@ -136,7 +136,7 @@ internal static class LogMessages // public const string IDX10622 = "IDX10622:"; // public const string IDX10623 = "IDX10623:"; // public const string IDX10624 = "IDX10624:"; - public const string IDX10625 = "IDX10625: Failed to verify the authenticationTag length, the actual tag length '{0}' does not match the expected tag length '{1}'. authenticationTag: '{2}', algorithm: '{3}' See: https://aka.ms/IdentityModel/SkipAuthenticationTagLengthValidation"; + public const string IDX10625 = "IDX10625: Failed to verify the authenticationTag length, the actual tag length '{0}' does not match the expected tag length '{1}'. authenticationTag: '{2}', algorithm: '{3}'."; // public const string IDX10627 = "IDX10627:"; public const string IDX10628 = "IDX10628: Cannot set the MinimumSymmetricKeySizeInBits to less than '{0}'."; public const string IDX10630 = "IDX10630: The '{0}' for signing cannot be smaller than '{1}' bits. KeySize: '{2}'."; diff --git a/src/Microsoft.IdentityModel.Tokens/X509EncryptingCredentials.cs b/src/Microsoft.IdentityModel.Tokens/X509EncryptingCredentials.cs index ec0f483dd8..6a92eaedaa 100644 --- a/src/Microsoft.IdentityModel.Tokens/X509EncryptingCredentials.cs +++ b/src/Microsoft.IdentityModel.Tokens/X509EncryptingCredentials.cs @@ -11,8 +11,6 @@ namespace Microsoft.IdentityModel.Tokens /// public class X509EncryptingCredentials : EncryptingCredentials { - internal const string _useShortNameForRsaOaepKey = "Switch.Microsoft.IdentityModel.UseShortNameForRsaOaepKey"; - /// /// Designed to construct based on a x509 certificate. /// @@ -23,7 +21,7 @@ public class X509EncryptingCredentials : EncryptingCredentials /// /// if 'certificate' is null. public X509EncryptingCredentials(X509Certificate2 certificate) - : this(certificate, GetEncryptionAlgorithm(), SecurityAlgorithms.DefaultSymmetricEncryptionAlgorithm) + : this(certificate, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.DefaultSymmetricEncryptionAlgorithm) { } @@ -50,15 +48,5 @@ public X509Certificate2 Certificate get; private set; } - - private static string GetEncryptionAlgorithm() - { - return ShouldUseShortNameForRsaOaepKey() ? SecurityAlgorithms.RsaOAEP : SecurityAlgorithms.DefaultAsymmetricKeyWrapAlgorithm; - } - - private static bool ShouldUseShortNameForRsaOaepKey() - { - return AppContext.TryGetSwitch(_useShortNameForRsaOaepKey, out var useKeyWrap) && useKeyWrap; - } } } diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs index bd041cac2f..6b67a4f4e3 100644 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs +++ b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/JsonWebTokenHandlerTests.cs @@ -4190,10 +4190,9 @@ public static TheoryData IncludeSecurityTokenOnFailureTes } [Theory, MemberData(nameof(ValidateAuthenticationTagLengthTheoryData))] - public void ValidateTokenAsync_ModifiedAuthNTag(CreateTokenTheoryData theoryData) + public async Task ValidateTokenAsync_ModifiedAuthNTag(CreateTokenTheoryData theoryData) { // arrange - AppContext.SetSwitch(AuthenticatedEncryptionProvider._skipValidationOfAuthenticationTagLength, theoryData.EnableAppContextSwitch); var payload = new JObject() { { JwtRegisteredClaimNames.Email, "Bob@contoso.com" }, @@ -4217,9 +4216,7 @@ public void ValidateTokenAsync_ModifiedAuthNTag(CreateTokenTheoryData theoryData var jweWithExtraCharacters = jwe + "_cannoli_hunts_truffles_"; // act - // calling ValidateTokenAsync.Result to prevent tests from sharing app context switch property - // normally, we would want to await ValidateTokenAsync().ConfigureAwait(false) - var tokenValidationResult = jsonWebTokenHandler.ValidateTokenAsync(jweWithExtraCharacters, theoryData.ValidationParameters).Result; + var tokenValidationResult = await jsonWebTokenHandler.ValidateTokenAsync(jweWithExtraCharacters, theoryData.ValidationParameters).ConfigureAwait(false); // assert Assert.Equal(theoryData.IsValid, tokenValidationResult.IsValid); @@ -4281,47 +4278,6 @@ public static TheoryData ValidateAuthenticationTagLengthT ValidIssuer = "http://Default.Issuer.com", }, IsValid = false - }, - new("A128CBC-HS256_SkipTagLengthValidationAppContextSwitchOn_IsValid") - { - EnableAppContextSwitch = true, - Algorithm = SecurityAlgorithms.Aes128CbcHmacSha256, - EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes128CbcHmacSha256), - ValidationParameters = new TokenValidationParameters - { - TokenDecryptionKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key, - IssuerSigningKey = Default.SymmetricSigningKey256, - ValidAudience = "http://Default.Audience.com", - ValidIssuer = "http://Default.Issuer.com", - }, - IsValid = true - }, - new("A192CBC-HS384_SkipTagLengthValidationAppContextSwitchOn_IsValid") - { - EnableAppContextSwitch = true, - Algorithm = SecurityAlgorithms.Aes192CbcHmacSha384, - EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes192CbcHmacSha384), - ValidationParameters = new TokenValidationParameters - { - TokenDecryptionKey = KeyingMaterial.JsonWebKeyRsa256SigningCredentials.Key, - IssuerSigningKey = Default.SymmetricSigningKey256, - ValidAudience = "http://Default.Audience.com", - ValidIssuer = "http://Default.Issuer.com", - }, - IsValid = true - }, - new("A256CBC-HS512_SkipTagLengthValidationAppContextSwitchOn_IsValid") - { - EnableAppContextSwitch = true, - EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaPKCS1, SecurityAlgorithms.Aes256CbcHmacSha512), - ValidationParameters = new TokenValidationParameters - { - TokenDecryptionKey = signingCredentials512.Key, - IssuerSigningKey = Default.SymmetricSigningKey256, - ValidAudience = "http://Default.Audience.com", - ValidIssuer = "http://Default.Issuer.com", - }, - IsValid = true } }; } @@ -4370,8 +4326,6 @@ public CreateTokenTheoryData(string testId) : base(testId) public IEnumerable ExpectedDecryptionKeys { get; set; } public Dictionary ExpectedClaims { get; set; } - - public bool EnableAppContextSwitch { get; set; } = false; } // Overrides CryptoProviderFactory.CreateAuthenticatedEncryptionProvider to create AuthenticatedEncryptionProviderMock that provides AesGcm encryption. diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/EncryptingCredentialsTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/EncryptingCredentialsTests.cs index 7b44f1b844..ad787f01d4 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/EncryptingCredentialsTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/EncryptingCredentialsTests.cs @@ -57,7 +57,7 @@ public static TheoryData ConstructorATheoryData new EncryptingCredentialsTheoryData { Key = null, - Alg = SecurityAlgorithms.RsaOaepKeyWrap, + Alg = SecurityAlgorithms.RsaOAEP, Enc = SecurityAlgorithms.Aes128CbcHmacSha256, ExpectedException = ExpectedException.ArgumentNullException("IDX10000: The parameter 'key'"), TestId = "NullKey" @@ -73,7 +73,7 @@ public static TheoryData ConstructorATheoryData new EncryptingCredentialsTheoryData { Key = Default.AsymmetricEncryptionKeyPublic, - Alg = SecurityAlgorithms.RsaOaepKeyWrap, + Alg = SecurityAlgorithms.RsaOAEP, Enc = String.Empty, ExpectedException = ExpectedException.ArgumentNullException("IDX10000: The parameter 'enc'"), TestId = "EmptyEncString" @@ -89,7 +89,7 @@ public static TheoryData ConstructorATheoryData new EncryptingCredentialsTheoryData { Key = Default.AsymmetricEncryptionKeyPublic, - Alg = SecurityAlgorithms.RsaOaepKeyWrap, + Alg = SecurityAlgorithms.RsaOAEP, Enc = null, ExpectedException = ExpectedException.ArgumentNullException("IDX10000: The parameter 'enc'"), TestId = "NullEncString" @@ -97,7 +97,7 @@ public static TheoryData ConstructorATheoryData new EncryptingCredentialsTheoryData { Key = Default.AsymmetricEncryptionKeyPublic, - Alg = SecurityAlgorithms.RsaOaepKeyWrap, + Alg = SecurityAlgorithms.RsaOAEP, Enc = SecurityAlgorithms.Aes128CbcHmacSha256, TestId = "ValidTest" } diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/MultiThreadingTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/MultiThreadingTests.cs index f1b5d636b6..6352fc6fe4 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/MultiThreadingTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/MultiThreadingTests.cs @@ -121,7 +121,7 @@ public static TheoryData MultiThreadingCreateAndVerify { Claims = Default.PayloadDictionary, SigningCredentials = new SigningCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaSha256, SecurityAlgorithms.Sha256), - EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaOaepKeyWrap, SecurityAlgorithms.Aes128CbcHmacSha256) + EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKey_2048, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes128CbcHmacSha256) }; var tokenValidationParametersEncryptedRsaKW = new TokenValidationParameters @@ -174,7 +174,7 @@ public static TheoryData MultiThreadingCreateAndVerify { Claims = Default.PayloadDictionary, SigningCredentials = new SigningCredentials(KeyingMaterial.RsaSecurityKeyCng_2048, SecurityAlgorithms.RsaSha256, SecurityAlgorithms.Sha256), - EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKeyCng_2048, SecurityAlgorithms.RsaOaepKeyWrap, SecurityAlgorithms.Aes128CbcHmacSha256) + EncryptingCredentials = new EncryptingCredentials(KeyingMaterial.RsaSecurityKeyCng_2048, SecurityAlgorithms.RsaOAEP, SecurityAlgorithms.Aes128CbcHmacSha256) }; var tokenValidationParametersEncryptedRsaKWCng = new TokenValidationParameters diff --git a/test/Microsoft.IdentityModel.Tokens.Tests/X509EncryptingCredentialsTests.cs b/test/Microsoft.IdentityModel.Tokens.Tests/X509EncryptingCredentialsTests.cs index 6590737fca..2dee4d2e62 100644 --- a/test/Microsoft.IdentityModel.Tokens.Tests/X509EncryptingCredentialsTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Tests/X509EncryptingCredentialsTests.cs @@ -42,7 +42,7 @@ public static TheoryData ConstructorsTheory new X509EncryptingCredentialsTheoryData { Certificate = null, - Alg = SecurityAlgorithms.RsaOaepKeyWrap, + Alg = SecurityAlgorithms.RsaOAEP, Enc = SecurityAlgorithms.Aes128CbcHmacSha256, ExpectedException = ExpectedException.ArgumentNullException("IDX10000: The parameter 'certificate'"), TestId = "NullCertificate" @@ -58,7 +58,7 @@ public static TheoryData ConstructorsTheory new X509EncryptingCredentialsTheoryData { Certificate = Default.Certificate, - Alg = SecurityAlgorithms.RsaOaepKeyWrap, + Alg = SecurityAlgorithms.RsaOAEP, Enc = String.Empty, ExpectedException = ExpectedException.ArgumentNullException("IDX10000: The parameter 'enc'"), TestId = "EmptyEncString" @@ -74,7 +74,7 @@ public static TheoryData ConstructorsTheory new X509EncryptingCredentialsTheoryData { Certificate = Default.Certificate, - Alg = SecurityAlgorithms.RsaOaepKeyWrap, + Alg = SecurityAlgorithms.RsaOAEP, Enc = null, ExpectedException = ExpectedException.ArgumentNullException("IDX10000: The parameter 'enc'"), TestId = "NullEncString" @@ -82,7 +82,7 @@ public static TheoryData ConstructorsTheory new X509EncryptingCredentialsTheoryData { Certificate = Default.Certificate, - Alg = SecurityAlgorithms.RsaOaepKeyWrap, + Alg = SecurityAlgorithms.RsaOAEP, Enc = SecurityAlgorithms.Aes128CbcHmacSha256, TestId = "ValidTest" } diff --git a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.WithContextSwitches.cs b/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.WithContextSwitches.cs deleted file mode 100644 index 7e87575e11..0000000000 --- a/test/System.IdentityModel.Tokens.Jwt.Tests/JwtSecurityTokenHandlerTests.WithContextSwitches.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.IdentityModel.JsonWebTokens; -using Microsoft.IdentityModel.TestUtils; -using Microsoft.IdentityModel.Tokens; -using Xunit; - -namespace System.IdentityModel.Tokens.Jwt.Tests -{ - [CollectionDefinition("JwtSecurityTokenHandlerTestsWithContextSwitches", DisableParallelization = true)] - public class JwtSecurityTokenHandlerTestsWithContextSwitches - { - [Theory] - [InlineData(SecurityAlgorithms.RsaOAEP, true)] - [InlineData(SecurityAlgorithms.RsaOaepKeyWrap, false)] - public void JwtSecurityTokenHandler_CreateToken_AddShortFormMappingForRsaOAEP(string algorithm, bool useShortNameForRsaOaepKey) - { - AppContext.SetSwitch(X509EncryptingCredentials._useShortNameForRsaOaepKey, useShortNameForRsaOaepKey); - var encryptingCredentials = new X509EncryptingCredentials(Default.Certificate); - JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); - - JwtSecurityToken token = CreateJwtSecurityToken(tokenHandler, encryptingCredentials); - - Assert.Equal(token.Header.Alg, algorithm); - - AppContext.SetSwitch(X509EncryptingCredentials._useShortNameForRsaOaepKey, false); - } - - [Theory] - [InlineData(SecurityAlgorithms.RsaOAEP, true)] - [InlineData(SecurityAlgorithms.RsaOaepKeyWrap, false)] - public void JsonWebTokenHandler_CreateToken_AddShortFormMappingForRsaOAEP(string algorithm, bool useShortNameForRsaOaepKey) - { - AppContext.SetSwitch(X509EncryptingCredentials._useShortNameForRsaOaepKey, useShortNameForRsaOaepKey); - var encryptingCredentials = new X509EncryptingCredentials(Default.Certificate); - JsonWebTokenHandler tokenHandler = new JsonWebTokenHandler(); - - JsonWebToken jsonToken = new JsonWebToken(CreateJwtSecurityTokenAsString(tokenHandler, encryptingCredentials)); - - Assert.Equal(jsonToken.Alg, algorithm); - - AppContext.SetSwitch(X509EncryptingCredentials._useShortNameForRsaOaepKey, false); - } - - private JwtSecurityToken CreateJwtSecurityToken(JwtSecurityTokenHandler tokenHandler, X509EncryptingCredentials encryptingCredentials) - { - return tokenHandler.CreateJwtSecurityToken(CreateTokenDescriptor(encryptingCredentials)); - } - - private string CreateJwtSecurityTokenAsString(JsonWebTokenHandler tokenHandler, X509EncryptingCredentials encryptingCredentials) - { - return tokenHandler.CreateToken(CreateTokenDescriptor(encryptingCredentials)); - } - - private SecurityTokenDescriptor CreateTokenDescriptor(X509EncryptingCredentials encryptingCredentials) - { - return new SecurityTokenDescriptor - { - Issuer = Default.Issuer, - SigningCredentials = Default.AsymmetricSigningCredentials, - EncryptingCredentials = encryptingCredentials, - }; - } - } -} From caf123fb476d29f61ef79ee58d6583e0a155bbd6 Mon Sep 17 00:00:00 2001 From: sruthikeerthi <73967733+sruke@users.noreply.github.com> Date: Tue, 18 Jun 2024 23:08:42 -0700 Subject: [PATCH 3/5] Revert PR2597 to reduce allocations (#2649) Co-authored-by: Sruthi Keerthi Rangavajhula (from Dev Box) --- .../AadIssuerValidator/AadIssuerValidator.cs | 24 +++++------------ .../AadTokenValidationParametersExtension.cs | 27 ++++++++----------- .../AadIssuerValidatorTests.cs | 24 ----------------- .../AadSigningKeyIssuerValidatorTests.cs | 15 ----------- 4 files changed, 17 insertions(+), 73 deletions(-) delete mode 100644 test/Microsoft.IdentityModel.Validators.Tests/AadIssuerValidatorTests.cs diff --git a/src/Microsoft.IdentityModel.Validators/AadIssuerValidator/AadIssuerValidator.cs b/src/Microsoft.IdentityModel.Validators/AadIssuerValidator/AadIssuerValidator.cs index 445671d134..323718cc84 100644 --- a/src/Microsoft.IdentityModel.Validators/AadIssuerValidator/AadIssuerValidator.cs +++ b/src/Microsoft.IdentityModel.Validators/AadIssuerValidator/AadIssuerValidator.cs @@ -13,6 +13,7 @@ using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; +using static Microsoft.IdentityModel.Validators.AadIssuerValidator; namespace Microsoft.IdentityModel.Validators { @@ -382,31 +383,18 @@ private ConfigurationManager CreateConfigManager( } } - internal static bool IsValidIssuer(string validIssuerTemplate, string tenantId, string actualIssuer) + private static bool IsValidIssuer(string validIssuerTemplate, string tenantId, string actualIssuer) { - if (string.IsNullOrEmpty(validIssuerTemplate) || string.IsNullOrEmpty(actualIssuer) || string.IsNullOrEmpty(tenantId)) + if (string.IsNullOrEmpty(validIssuerTemplate)) return false; - ReadOnlySpan validIssuerTemplateSpan = validIssuerTemplate.AsSpan(); - ReadOnlySpan actualIssuerSpan = actualIssuer.AsSpan(); - int indexOfTenantIdTemplate = validIssuerTemplate.IndexOf(TenantIdTemplate, StringComparison.Ordinal); - - if (indexOfTenantIdTemplate >= 0 && actualIssuer.Length > indexOfTenantIdTemplate) + if (validIssuerTemplate.Contains(TenantIdTemplate)) { - // ensure the first part of the validIssuerTemplate matches the first part of actualIssuer - if (!validIssuerTemplateSpan.Slice(0, indexOfTenantIdTemplate).SequenceEqual(actualIssuerSpan.Slice(0, indexOfTenantIdTemplate))) - return false; - - // ensure that actualIssuer contains the tenantId from indexOfTenantIdTemplate for the length of tenantId.Length - if (!actualIssuerSpan.Slice(indexOfTenantIdTemplate, tenantId.Length).SequenceEqual(tenantId.AsSpan())) - return false; - - // ensure the second halves are equal - return validIssuerTemplateSpan.Slice(indexOfTenantIdTemplate + TenantIdTemplate.Length).SequenceEqual(actualIssuerSpan.Slice(indexOfTenantIdTemplate + tenantId.Length)); + return validIssuerTemplate.Replace(TenantIdTemplate, tenantId) == actualIssuer; } else { - return validIssuerTemplateSpan.SequenceEqual(actualIssuerSpan); + return validIssuerTemplate == actualIssuer; } } diff --git a/src/Microsoft.IdentityModel.Validators/AadTokenValidationParametersExtension.cs b/src/Microsoft.IdentityModel.Validators/AadTokenValidationParametersExtension.cs index 5335284168..d745bf124c 100644 --- a/src/Microsoft.IdentityModel.Validators/AadTokenValidationParametersExtension.cs +++ b/src/Microsoft.IdentityModel.Validators/AadTokenValidationParametersExtension.cs @@ -76,36 +76,31 @@ internal static bool ValidateIssuerSigningKey(SecurityKey securityKey, SecurityT #if NET6_0_OR_GREATER if (!string.IsNullOrEmpty(tokenIssuer) && !tokenIssuer.Contains(tenantIdFromToken, StringComparison.Ordinal)) throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidIssuerException(LogHelper.FormatInvariant(LogMessages.IDX40004, LogHelper.MarkAsNonPII(tokenIssuer), LogHelper.MarkAsNonPII(tenantIdFromToken)))); + + // creating an effectiveSigningKeyIssuer is required as signingKeyIssuer might contain {tenantid} + var effectiveSigningKeyIssuer = signingKeyIssuer.Replace(AadIssuerValidator.TenantIdTemplate, tenantIdFromToken, StringComparison.Ordinal); + var v2TokenIssuer = openIdConnectConfiguration.Issuer?.Replace(AadIssuerValidator.TenantIdTemplate, tenantIdFromToken, StringComparison.Ordinal); #else if (!string.IsNullOrEmpty(tokenIssuer) && !tokenIssuer.Contains(tenantIdFromToken)) throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidIssuerException(LogHelper.FormatInvariant(LogMessages.IDX40004, LogHelper.MarkAsNonPII(tokenIssuer), LogHelper.MarkAsNonPII(tenantIdFromToken)))); + + // creating an effectiveSigningKeyIssuer is required as signingKeyIssuer might contain {tenantid} + var effectiveSigningKeyIssuer = signingKeyIssuer.Replace(AadIssuerValidator.TenantIdTemplate, tenantIdFromToken); + var v2TokenIssuer = openIdConnectConfiguration.Issuer?.Replace(AadIssuerValidator.TenantIdTemplate, tenantIdFromToken); #endif - // comparing effectiveSigningKeyIssuer with v2TokenIssuer is required because of the following scenario: + + // comparing effectiveSigningKeyIssuer with v2TokenIssuer is required as well because of the following scenario: // 1. service trusts /common/v2.0 endpoint // 2. service receieves a v1 token that has issuer like sts.windows.net // 3. signing key issuers will never match sts.windows.net as v1 endpoint doesn't have issuers attached to keys // v2TokenIssuer is the representation of Token.Issuer (if it was a v2 issuer) - if (!AadIssuerValidator.IsValidIssuer(signingKeyIssuer, tenantIdFromToken, tokenIssuer) - && !AadIssuerValidator.IsValidIssuer(signingKeyIssuer, tenantIdFromToken, openIdConnectConfiguration.Issuer)) - { - int templateStartIndex = signingKeyIssuer.IndexOf(AadIssuerValidator.TenantIdTemplate, StringComparison.Ordinal); - string effectiveSigningKeyIssuer = templateStartIndex > -1 ? CreateIssuer(signingKeyIssuer, AadIssuerValidator.TenantIdTemplate, tenantIdFromToken, templateStartIndex) : signingKeyIssuer; + if (effectiveSigningKeyIssuer != tokenIssuer && effectiveSigningKeyIssuer != v2TokenIssuer) throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidIssuerException(LogHelper.FormatInvariant(LogMessages.IDX40005, LogHelper.MarkAsNonPII(tokenIssuer), LogHelper.MarkAsNonPII(effectiveSigningKeyIssuer)))); - } } return true; } - internal static string CreateIssuer(string issuer, string tenantIdTemplate, string tenantId, int templateStartIndex) - { -#if NET6_0_OR_GREATER - return string.Concat(issuer.AsSpan(0, templateStartIndex), tenantId, issuer.AsSpan(templateStartIndex + tenantIdTemplate.Length, issuer.Length - tenantIdTemplate.Length - templateStartIndex)); -#else - return string.Concat(issuer.Substring(0, templateStartIndex), tenantId, issuer.Substring(templateStartIndex + tenantIdTemplate.Length)); -#endif - } - /// /// Validates the issuer signing key certificate. /// diff --git a/test/Microsoft.IdentityModel.Validators.Tests/AadIssuerValidatorTests.cs b/test/Microsoft.IdentityModel.Validators.Tests/AadIssuerValidatorTests.cs deleted file mode 100644 index 4e05268f1f..0000000000 --- a/test/Microsoft.IdentityModel.Validators.Tests/AadIssuerValidatorTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -using Xunit; - -namespace Microsoft.IdentityModel.Validators.Tests -{ - public class AadIssuerValidatorTests - { - [Theory] - [InlineData(ValidatorConstants.AadInstance + AadIssuerValidator.TenantIdTemplate, ValidatorConstants.AadInstance + ValidatorConstants.TenantIdAsGuid, true)] - [InlineData(ValidatorConstants.AadInstancePPE + AadIssuerValidator.TenantIdTemplate, ValidatorConstants.AadInstance + ValidatorConstants.TenantIdAsGuid, false)] - [InlineData(ValidatorConstants.AadInstance + AadIssuerValidator.TenantIdTemplate, ValidatorConstants.AadInstance + ValidatorConstants.B2CTenantAsGuid, false)] - [InlineData("", ValidatorConstants.AadInstance + ValidatorConstants.TenantIdAsGuid, false)] - [InlineData(ValidatorConstants.AadInstance + AadIssuerValidator.TenantIdTemplate, "", false)] - public static void IsValidIssuer_CanValidateTemplatedIssuers(string templatedIssuer, string issuer, bool expectedResult) - { - // act - var result = AadIssuerValidator.IsValidIssuer(templatedIssuer, ValidatorConstants.TenantIdAsGuid, issuer); - - // assert - Assert.Equal(expectedResult, result); - } - } -} diff --git a/test/Microsoft.IdentityModel.Validators.Tests/AadSigningKeyIssuerValidatorTests.cs b/test/Microsoft.IdentityModel.Validators.Tests/AadSigningKeyIssuerValidatorTests.cs index b979f7c49e..e768a2372f 100644 --- a/test/Microsoft.IdentityModel.Validators.Tests/AadSigningKeyIssuerValidatorTests.cs +++ b/test/Microsoft.IdentityModel.Validators.Tests/AadSigningKeyIssuerValidatorTests.cs @@ -325,21 +325,6 @@ public static TheoryData ValidateIssuerSigningKey } } - [Fact] - public static void CreateIssuer_ReturnsExpectedIssuer() - { - // arrange - var issuerTemplate = "{tenantId}"; - var issuer = ValidatorConstants.AadInstance + issuerTemplate; - int templateStartIndex = issuer.IndexOf(issuerTemplate); - - // act - var result = AadTokenValidationParametersExtension.CreateIssuer(issuer, issuerTemplate, ValidatorConstants.TenantIdAsGuid, templateStartIndex); - - // assert - Assert.Equal(ValidatorConstants.AadInstance + ValidatorConstants.TenantIdAsGuid, result); - } - private static OpenIdConnectConfiguration GetConfigurationMock() { var config = new OpenIdConnectConfiguration(); From 0183521b0f127a214aa28cfb8385acfef8c4aa22 Mon Sep 17 00:00:00 2001 From: joegoldman2 <147369450+joegoldman2@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:02:46 +0000 Subject: [PATCH 4/5] Add additional metadata parameters to OpenIdConnectConfiguration (#2646) Co-authored-by: joegoldman2 <147369450+joegoldman@users.noreply.github.com> --- .../OpenIdConnectConfiguration.cs | 72 +++++++++++++++++++ .../OpenIdConnectConfigurationSerializer.cs | 40 +++++++++++ .../OpenIdProviderMetadataNames.cs | 8 +++ .../OpenIdConfigData.cs | 8 +++ .../OpenIdConnectConfigurationTests.cs | 15 +++- .../OpenIdConnectMetadata.json | 4 ++ 6 files changed, 145 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/Configuration/OpenIdConnectConfiguration.cs b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/Configuration/OpenIdConnectConfiguration.cs index 36fb436a61..c513056b7d 100644 --- a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/Configuration/OpenIdConnectConfiguration.cs +++ b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/Configuration/OpenIdConnectConfiguration.cs @@ -23,6 +23,9 @@ public class OpenIdConnectConfiguration : BaseConfiguration // these are used to lazy create private Dictionary _additionalData; private ICollection _acrValuesSupported; + private ICollection _authorizationEncryptionAlgValuesSupported; + private ICollection _authorizationEncryptionEncValuesSupported; + private ICollection _authorizationSigningAlgValuesSupported; private ICollection _backchannelAuthenticationRequestSigningAlgValuesSupported; private ICollection _backchannelTokenDeliveryModesSupported; private ICollection _claimsSupported; @@ -146,6 +149,24 @@ public OpenIdConnectConfiguration(string json) #endif public string AuthorizationEndpoint { get; set; } + /// + /// Gets the collection of 'authorization_encryption_alg_values_supported' + /// + [JsonPropertyName(OpenIdProviderMetadataNames.AuthorizationEncryptionAlgValuesSupported)] + public ICollection AuthorizationEncryptionAlgValuesSupported => + _authorizationEncryptionAlgValuesSupported ?? + Interlocked.CompareExchange(ref _authorizationEncryptionAlgValuesSupported, new Collection(), null) ?? + _authorizationEncryptionAlgValuesSupported; + + /// + /// Gets the collection of 'authorization_encryption_enc_values_supported' + /// + [JsonPropertyName(OpenIdProviderMetadataNames.AuthorizationEncryptionEncValuesSupported)] + public ICollection AuthorizationEncryptionEncValuesSupported => + _authorizationEncryptionEncValuesSupported ?? + Interlocked.CompareExchange(ref _authorizationEncryptionEncValuesSupported, new Collection(), null) ?? + _authorizationEncryptionEncValuesSupported; + /// /// Gets or sets the 'authorization_response_iss_parameter_supported' /// @@ -155,6 +176,15 @@ public OpenIdConnectConfiguration(string json) #endif public bool AuthorizationResponseIssParameterSupported { get; set; } + /// + /// Gets the collection of 'authorization_signing_alg_values_supported' + /// + [JsonPropertyName(OpenIdProviderMetadataNames.AuthorizationSigningAlgValuesSupported)] + public ICollection AuthorizationSigningAlgValuesSupported => + _authorizationSigningAlgValuesSupported ?? + Interlocked.CompareExchange(ref _authorizationSigningAlgValuesSupported, new Collection(), null) ?? + _authorizationSigningAlgValuesSupported; + /// /// Gets or sets the 'backchannel_authentication_endpoint'. /// @@ -622,6 +652,15 @@ public OpenIdConnectConfiguration(string json) Interlocked.CompareExchange(ref _tokenEndpointAuthSigningAlgValuesSupported, new Collection(), null) ?? _tokenEndpointAuthSigningAlgValuesSupported; + /// + /// Gets or sets the 'tls_client_certificate_bound_access_tokens' + /// + [JsonPropertyName(OpenIdProviderMetadataNames.TlsClientCertificateBoundAccessTokens)] +#if NET6_0_OR_GREATER + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] +#endif + public bool TlsClientCertificateBoundAccessTokens { get; set; } + /// /// Gets the collection of 'ui_locales_supported' /// @@ -681,6 +720,39 @@ public bool ShouldSerializeAcrValuesSupported() return AcrValuesSupported.Count > 0; } + /// + /// Gets a bool that determines if the 'authorization_encryption_alg_values_supported' (AuthorizationEncryptionAlgValuesSupported) property should be serialized. + /// This is used by Json.NET in order to conditionally serialize properties. + /// + /// true if 'authorization_encryption_alg_values_supported' (AuthorizationEncryptionAlgValuesSupported) is not empty; otherwise, false. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool ShouldSerializeAuthorizationEncryptionAlgValuesSupported() + { + return AuthorizationEncryptionAlgValuesSupported.Count > 0; + } + + /// + /// Gets a bool that determines if the 'authorization_encryption_enc_values_supported' (AuthorizationEncryptionEncValuesSupported) property should be serialized. + /// This is used by Json.NET in order to conditionally serialize properties. + /// + /// true if 'authorization_encryption_enc_values_supported' (AuthorizationEncryptionEncValuesSupported) is not empty; otherwise, false. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool ShouldSerializeAuthorizationEncryptionEncValuesSupported() + { + return AuthorizationEncryptionEncValuesSupported.Count > 0; + } + + /// + /// Gets a bool that determines if the 'authorization_signing_alg_values_supported' (AuthorizationSigningAlgValuesSupported) property should be serialized. + /// This is used by Json.NET in order to conditionally serialize properties. + /// + /// true if 'authorization_signing_alg_values_supported' (AuthorizationSigningAlgValuesSupported) is not empty; otherwise, false. + [EditorBrowsable(EditorBrowsableState.Never)] + public bool ShouldSerializeAuthorizationSigningAlgValuesSupported() + { + return AuthorizationSigningAlgValuesSupported.Count > 0; + } + /// /// Gets a bool that determines if the 'backchannel_token_delivery_modes_supported' (BackchannelTokenDeliveryModesSupported) property should be serialized. /// This is used by Json.NET in order to conditionally serialize properties. diff --git a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/Json/OpenIdConnectConfigurationSerializer.cs b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/Json/OpenIdConnectConfigurationSerializer.cs index 9e99a0899d..cffe63744f 100644 --- a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/Json/OpenIdConnectConfigurationSerializer.cs +++ b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/Json/OpenIdConnectConfigurationSerializer.cs @@ -39,7 +39,10 @@ public static readonly { "ACR_VALUES_SUPPORTED", "AUTHORIZATION_ENDPOINT", + "AUTHORIZATION_ENCRYPTION_ALG_VALUES_SUPPORTED", + "AUTHORIZATION_ENCRYPTION_ENC_VALUES_SUPPORTED", "AUTHORIZATION_RESPONSE_ISS_PARAMETER_SUPPORTED", + "AUTHORIZATION_SIGNING_ALG_VALUES_SUPPORTED", "BACKCHANNEL_AUTHENTICATION_ENDPOINT", "BACKCHANNEL_AUTHENTICATION_REQUEST_SIGNING_ALG_VALUES_SUPPORTED", "BACKCHANNEL_TOKEN_DELIVERY_MODES_SUPPORTED", @@ -91,6 +94,7 @@ public static readonly "TOKEN_ENDPOINT", "TOKEN_ENDPOINT_AUTH_METHODS_SUPPORTED", "TOKEN_ENDPOINT_AUTH_SIGNING_ALG_VALUES_SUPPORTED", + "TLS_CLIENT_CERTIFICATE_BOUND_ACCESS_TOKENS", "UI_LOCALES_SUPPORTED", "USERINFO_ENDPOINT", "USERINFO_ENCRYPTION_ALG_VALUES_SUPPORTED", @@ -162,9 +166,18 @@ public static OpenIdConnectConfiguration Read(ref Utf8JsonReader reader, OpenIdC else if (reader.ValueTextEquals(Utf8Bytes.AuthorizationEndpoint)) config.AuthorizationEndpoint = JsonPrimitives.ReadString(ref reader, MetadataName.AuthorizationEndpoint, ClassName, true); + else if (reader.ValueTextEquals(Utf8Bytes.AuthorizationEncryptionAlgValuesSupported)) + JsonPrimitives.ReadStrings(ref reader, config.AuthorizationEncryptionAlgValuesSupported, MetadataName.AuthorizationEncryptionAlgValuesSupported, ClassName, true); + + else if (reader.ValueTextEquals(Utf8Bytes.AuthorizationEncryptionEncValuesSupported)) + JsonPrimitives.ReadStrings(ref reader, config.AuthorizationEncryptionEncValuesSupported, MetadataName.AuthorizationEncryptionEncValuesSupported, ClassName, true); + else if (reader.ValueTextEquals(Utf8Bytes.AuthorizationResponseIssParameterSupported)) config.AuthorizationResponseIssParameterSupported = JsonPrimitives.ReadBoolean(ref reader, MetadataName.AuthorizationResponseIssParameterSupported, ClassName, true); + else if (reader.ValueTextEquals(Utf8Bytes.AuthorizationSigningAlgValuesSupported)) + JsonPrimitives.ReadStrings(ref reader, config.AuthorizationSigningAlgValuesSupported, MetadataName.AuthorizationSigningAlgValuesSupported, ClassName, true); + else if (reader.ValueTextEquals(Utf8Bytes.BackchannelAuthenticationEndpoint)) config.BackchannelAuthenticationEndpoint = JsonPrimitives.ReadString(ref reader, MetadataName.BackchannelAuthenticationEndpoint, ClassName, true); @@ -328,6 +341,9 @@ public static OpenIdConnectConfiguration Read(ref Utf8JsonReader reader, OpenIdC else if (reader.ValueTextEquals(Utf8Bytes.TokenEndpointAuthSigningAlgValuesSupported)) JsonPrimitives.ReadStrings(ref reader, config.TokenEndpointAuthSigningAlgValuesSupported, MetadataName.TokenEndpointAuthSigningAlgValuesSupported, ClassName, true); + else if (reader.ValueTextEquals(Utf8Bytes.TlsClientCertificateBoundAccessTokens)) + config.TlsClientCertificateBoundAccessTokens = JsonPrimitives.ReadBoolean(ref reader, MetadataName.TlsClientCertificateBoundAccessTokens, ClassName, true); + else if (reader.ValueTextEquals(Utf8Bytes.UILocalesSupported)) JsonPrimitives.ReadStrings(ref reader, config.UILocalesSupported, MetadataName.UILocalesSupported, ClassName, true); @@ -366,9 +382,18 @@ public static OpenIdConnectConfiguration Read(ref Utf8JsonReader reader, OpenIdC else if (propertyName.Equals(MetadataName.AuthorizationEndpoint, StringComparison.OrdinalIgnoreCase)) config.AuthorizationEndpoint = JsonPrimitives.ReadString(ref reader, propertyName, ClassName); + else if (propertyName.Equals(MetadataName.AuthorizationEncryptionAlgValuesSupported, StringComparison.OrdinalIgnoreCase)) + JsonPrimitives.ReadStrings(ref reader, config.AuthorizationEncryptionAlgValuesSupported, propertyName, ClassName); + + else if (propertyName.Equals(MetadataName.AuthorizationEncryptionEncValuesSupported, StringComparison.OrdinalIgnoreCase)) + JsonPrimitives.ReadStrings(ref reader, config.AuthorizationEncryptionEncValuesSupported, propertyName, ClassName); + else if (propertyName.Equals(MetadataName.AuthorizationResponseIssParameterSupported, StringComparison.OrdinalIgnoreCase)) config.AuthorizationResponseIssParameterSupported = JsonPrimitives.ReadBoolean(ref reader, propertyName, ClassName); + else if (propertyName.Equals(MetadataName.AuthorizationSigningAlgValuesSupported, StringComparison.OrdinalIgnoreCase)) + JsonPrimitives.ReadStrings(ref reader, config.AuthorizationSigningAlgValuesSupported, propertyName, ClassName); + else if (propertyName.Equals(MetadataName.BackchannelAuthenticationEndpoint, StringComparison.OrdinalIgnoreCase)) config.BackchannelAuthenticationEndpoint = JsonPrimitives.ReadString(ref reader, propertyName, ClassName); @@ -533,6 +558,9 @@ public static OpenIdConnectConfiguration Read(ref Utf8JsonReader reader, OpenIdC else if (propertyName.Equals(MetadataName.TokenEndpointAuthSigningAlgValuesSupported, StringComparison.OrdinalIgnoreCase)) JsonPrimitives.ReadStrings(ref reader, config.TokenEndpointAuthSigningAlgValuesSupported, propertyName, ClassName); + else if (propertyName.Equals(MetadataName.TlsClientCertificateBoundAccessTokens, StringComparison.OrdinalIgnoreCase)) + config.TlsClientCertificateBoundAccessTokens = JsonPrimitives.ReadBoolean(ref reader, propertyName, ClassName); + else if (propertyName.Equals(MetadataName.UILocalesSupported, StringComparison.OrdinalIgnoreCase)) JsonPrimitives.ReadStrings(ref reader, config.UILocalesSupported, propertyName, ClassName); @@ -592,9 +620,18 @@ public static void Write(ref Utf8JsonWriter writer, OpenIdConnectConfiguration c if (!string.IsNullOrEmpty(config.AuthorizationEndpoint)) writer.WriteString(Utf8Bytes.AuthorizationEndpoint, config.AuthorizationEndpoint); + if (config.AuthorizationEncryptionAlgValuesSupported.Count > 0) + JsonPrimitives.WriteStrings(ref writer, Utf8Bytes.AuthorizationEncryptionAlgValuesSupported, config.AuthorizationEncryptionAlgValuesSupported); + + if (config.AuthorizationEncryptionEncValuesSupported.Count > 0) + JsonPrimitives.WriteStrings(ref writer, Utf8Bytes.AuthorizationEncryptionEncValuesSupported, config.AuthorizationEncryptionEncValuesSupported); + if (config.AuthorizationResponseIssParameterSupported) writer.WriteBoolean(Utf8Bytes.AuthorizationResponseIssParameterSupported, config.AuthorizationResponseIssParameterSupported); + if (config.AuthorizationSigningAlgValuesSupported.Count > 0) + JsonPrimitives.WriteStrings(ref writer, Utf8Bytes.AuthorizationSigningAlgValuesSupported, config.AuthorizationSigningAlgValuesSupported); + if (!string.IsNullOrEmpty(config.BackchannelAuthenticationEndpoint)) writer.WriteString(Utf8Bytes.BackchannelAuthenticationEndpoint, config.BackchannelAuthenticationEndpoint); @@ -745,6 +782,9 @@ public static void Write(ref Utf8JsonWriter writer, OpenIdConnectConfiguration c if (config.TokenEndpointAuthSigningAlgValuesSupported.Count > 0) JsonPrimitives.WriteStrings(ref writer, Utf8Bytes.TokenEndpointAuthSigningAlgValuesSupported, config.TokenEndpointAuthSigningAlgValuesSupported); + if (config.TlsClientCertificateBoundAccessTokens) + writer.WriteBoolean(Utf8Bytes.TlsClientCertificateBoundAccessTokens, config.TlsClientCertificateBoundAccessTokens); + if (config.UILocalesSupported.Count > 0) JsonPrimitives.WriteStrings(ref writer, Utf8Bytes.UILocalesSupported, config.UILocalesSupported); diff --git a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdProviderMetadataNames.cs b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdProviderMetadataNames.cs index 62f15637c6..b5c802d3dd 100644 --- a/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdProviderMetadataNames.cs +++ b/src/Microsoft.IdentityModel.Protocols.OpenIdConnect/OpenIdProviderMetadataNames.cs @@ -14,7 +14,10 @@ public static class OpenIdProviderMetadataNames #pragma warning disable 1591 public const string AcrValuesSupported = "acr_values_supported"; public const string AuthorizationEndpoint = "authorization_endpoint"; + public const string AuthorizationEncryptionAlgValuesSupported = "authorization_encryption_alg_values_supported"; + public const string AuthorizationEncryptionEncValuesSupported = "authorization_encryption_enc_values_supported"; public const string AuthorizationResponseIssParameterSupported = "authorization_response_iss_parameter_supported"; + public const string AuthorizationSigningAlgValuesSupported = "authorization_signing_alg_values_supported"; public const string BackchannelAuthenticationEndpoint = "backchannel_authentication_endpoint"; public const string BackchannelAuthenticationRequestSigningAlgValuesSupported = "backchannel_authentication_request_signing_alg_values_supported"; public const string BackchannelTokenDeliveryModesSupported = "backchannel_token_delivery_modes_supported"; @@ -68,6 +71,7 @@ public static class OpenIdProviderMetadataNames public const string TokenEndpointAuthMethodsSupported = "token_endpoint_auth_methods_supported"; public const string TokenEndpointAuthSigningAlgValuesSupported = "token_endpoint_auth_signing_alg_values_supported"; public const string UILocalesSupported = "ui_locales_supported"; + public const string TlsClientCertificateBoundAccessTokens = "tls_client_certificate_bound_access_tokens"; public const string UserInfoEndpoint = "userinfo_endpoint"; public const string UserInfoEncryptionAlgValuesSupported = "userinfo_encryption_alg_values_supported"; public const string UserInfoEncryptionEncValuesSupported = "userinfo_encryption_enc_values_supported"; @@ -84,7 +88,10 @@ internal static class OpenIdProviderMetadataUtf8Bytes { public static ReadOnlySpan AcrValuesSupported => "acr_values_supported"u8; public static ReadOnlySpan AuthorizationEndpoint => "authorization_endpoint"u8; + public static ReadOnlySpan AuthorizationEncryptionAlgValuesSupported => "authorization_encryption_alg_values_supported"u8; + public static ReadOnlySpan AuthorizationEncryptionEncValuesSupported => "authorization_encryption_enc_values_supported"u8; public static ReadOnlySpan AuthorizationResponseIssParameterSupported => "authorization_response_iss_parameter_supported"u8; + public static ReadOnlySpan AuthorizationSigningAlgValuesSupported => "authorization_signing_alg_values_supported"u8; public static ReadOnlySpan BackchannelAuthenticationEndpoint => "backchannel_authentication_endpoint"u8; public static ReadOnlySpan BackchannelAuthenticationRequestSigningAlgValuesSupported => "backchannel_authentication_request_signing_alg_values_supported"u8; public static ReadOnlySpan BackchannelTokenDeliveryModesSupported => "backchannel_token_delivery_modes_supported"u8; @@ -137,6 +144,7 @@ internal static class OpenIdProviderMetadataUtf8Bytes public static ReadOnlySpan TokenEndpoint => "token_endpoint"u8; public static ReadOnlySpan TokenEndpointAuthMethodsSupported => "token_endpoint_auth_methods_supported"u8; public static ReadOnlySpan TokenEndpointAuthSigningAlgValuesSupported => "token_endpoint_auth_signing_alg_values_supported"u8; + public static ReadOnlySpan TlsClientCertificateBoundAccessTokens => "tls_client_certificate_bound_access_tokens"u8; public static ReadOnlySpan UILocalesSupported => "ui_locales_supported"u8; public static ReadOnlySpan UserInfoEndpoint => "userinfo_endpoint"u8; public static ReadOnlySpan UserInfoEncryptionAlgValuesSupported => "userinfo_encryption_alg_values_supported"u8; diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConfigData.cs b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConfigData.cs index 1f60d43365..75a62b1539 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConfigData.cs +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConfigData.cs @@ -68,7 +68,10 @@ public static OpenIdConnectConfiguration FullyPopulatedWithKeys public static string JsonAllValues = @"{ ""acr_values_supported"": [""acr_value1"", ""acr_value2"", ""acr_value3""], ""authorization_endpoint"": ""https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/authorize"", + ""authorization_encryption_alg_values_supported"": [""A192KW"", ""A256KW""], + ""authorization_encryption_enc_values_supported"": [""A128CBC-HS256"", ""A256CBC-HS512""], ""authorization_response_iss_parameter_supported"": false, + ""authorization_signing_alg_values_supported"": [""ES384"", ""ES512""], ""backchannel_authentication_endpoint"": ""https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/bc-authorize"", ""backchannel_authentication_request_signing_alg_values_supported"": [""ES384"", ""ES512""], ""backchannel_token_delivery_modes_supported"": [""poll"", ""ping""], @@ -119,6 +122,7 @@ public static OpenIdConnectConfiguration FullyPopulatedWithKeys ""token_endpoint"": ""https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/token"", ""token_endpoint_auth_methods_supported"": [""client_secret_post"", ""private_key_jwt""], ""token_endpoint_auth_signing_alg_values_supported"": [""ES192"", ""ES256""], + ""tls_client_certificate_bound_access_tokens"": true, ""ui_locales_supported"": [""hak-CN"", ""en-us""], ""userinfo_endpoint"": ""https://login.microsoftonline.com/add29489-7269-41f4-8841-b63c95564420/openid/userinfo"", ""userinfo_encryption_alg_values_supported"": [""ECDH-ES+A128KW"", ""ECDH-ES+A192KW""], @@ -610,7 +614,10 @@ private static OpenIdConnectConfiguration SetDefaultConfiguration(OpenIdConnectC { AddToCollection(config.AcrValuesSupported, "acr_value1", "acr_value2", "acr_value3"); config.AuthorizationEndpoint = "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/authorize"; + AddToCollection(config.AuthorizationEncryptionAlgValuesSupported, "A192KW", "A256KW"); + AddToCollection(config.AuthorizationEncryptionEncValuesSupported, "A128CBC-HS256", "A256CBC-HS512"); config.AuthorizationResponseIssParameterSupported = false; + AddToCollection(config.AuthorizationSigningAlgValuesSupported, "ES384", "ES512"); config.BackchannelAuthenticationEndpoint = "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/bc-authorize"; AddToCollection(config.BackchannelAuthenticationRequestSigningAlgValuesSupported, "ES384", "ES512"); AddToCollection(config.BackchannelTokenDeliveryModesSupported, "poll", "ping"); @@ -660,6 +667,7 @@ private static OpenIdConnectConfiguration SetDefaultConfiguration(OpenIdConnectC config.TokenEndpoint = "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/token"; AddToCollection(config.TokenEndpointAuthMethodsSupported, "client_secret_post", "private_key_jwt"); AddToCollection(config.TokenEndpointAuthSigningAlgValuesSupported, "ES192", "ES256"); + config.TlsClientCertificateBoundAccessTokens = true; AddToCollection(config.UILocalesSupported, "hak-CN", "en-us"); config.UserInfoEndpoint = "https://login.microsoftonline.com/add29489-7269-41f4-8841-b63c95564420/openid/userinfo"; AddToCollection(config.UserInfoEndpointEncryptionAlgValuesSupported, "ECDH-ES+A128KW", "ECDH-ES+A192KW"); diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectConfigurationTests.cs b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectConfigurationTests.cs index 9ee0bb7cdb..c31a60b085 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectConfigurationTests.cs +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectConfigurationTests.cs @@ -75,6 +75,9 @@ public void Defaults() { OpenIdConnectConfiguration configuration = new OpenIdConnectConfiguration(); Assert.NotNull(configuration.AcrValuesSupported); + Assert.NotNull(configuration.AuthorizationEncryptionAlgValuesSupported); + Assert.NotNull(configuration.AuthorizationEncryptionEncValuesSupported); + Assert.NotNull(configuration.AuthorizationSigningAlgValuesSupported); Assert.False(configuration.AuthorizationResponseIssParameterSupported); Assert.NotNull(configuration.BackchannelAuthenticationRequestSigningAlgValuesSupported); Assert.NotNull(configuration.BackchannelTokenDeliveryModesSupported); @@ -110,6 +113,7 @@ public void Defaults() Assert.NotNull(configuration.SubjectTypesSupported); Assert.NotNull(configuration.TokenEndpointAuthMethodsSupported); Assert.NotNull(configuration.TokenEndpointAuthSigningAlgValuesSupported); + Assert.False(configuration.TlsClientCertificateBoundAccessTokens); Assert.NotNull(configuration.UILocalesSupported); Assert.NotNull(configuration.UserInfoEndpointEncryptionAlgValuesSupported); Assert.NotNull(configuration.UserInfoEndpointEncryptionEncValuesSupported); @@ -141,8 +145,8 @@ public void GetSets() OpenIdConnectConfiguration configuration = new OpenIdConnectConfiguration(); Type type = typeof(OpenIdConnectConfiguration); PropertyInfo[] properties = type.GetProperties(); - if (properties.Length != 63) - Assert.True(false, "Number of properties has changed from 63 to: " + properties.Length + ", adjust tests"); + if (properties.Length != 67) + Assert.True(false, "Number of properties has changed from 67 to: " + properties.Length + ", adjust tests"); TestUtilities.CallAllPublicInstanceAndStaticPropertyGets(configuration, "OpenIdConnectConfiguration_GetSets"); @@ -152,7 +156,10 @@ public void GetSets() PropertyNamesAndSetGetValue = new List>> { new KeyValuePair>("AuthorizationEndpoint", new List{ (string)null, Guid.NewGuid().ToString(), Guid.NewGuid().ToString() }), + new KeyValuePair>("AuthorizationEncryptionAlgValuesSupported", new List{ false, true, true }), + new KeyValuePair>("AuthorizationEncryptionEncValuesSupported", new List{ false, true, true }), new KeyValuePair>("AuthorizationResponseIssParameterSupported", new List{ false, true, true }), + new KeyValuePair>("AuthorizationSigningAlgValuesSupported", new List{ false, true, true }), new KeyValuePair>("BackchannelAuthenticationEndpoint", new List{ (string)null, Guid.NewGuid().ToString(), Guid.NewGuid().ToString() }), new KeyValuePair>("BackchannelUserCodeParameterSupported", new List{ false, true, true }), new KeyValuePair>("CheckSessionIframe", new List{ (string)null, Guid.NewGuid().ToString(), Guid.NewGuid().ToString() }), @@ -178,6 +185,7 @@ public void GetSets() new KeyValuePair>("RevocationEndpointAuthMethodsSupported", new List{ false, true, true }), new KeyValuePair>("RevocationEndpointAuthSigningAlgValuesSupported", new List{ false, true, true }), new KeyValuePair>("ServiceDocumentation", new List{ (string)null, Guid.NewGuid().ToString(), Guid.NewGuid().ToString() }), + new KeyValuePair>("TlsClientCertificateBoundAccessTokens", new List{ false, true, false }), new KeyValuePair>("TokenEndpoint", new List{ (string)null, Guid.NewGuid().ToString(), Guid.NewGuid().ToString() }), new KeyValuePair>("UserInfoEndpoint", new List{ (string)null, Guid.NewGuid().ToString(), Guid.NewGuid().ToString() }), }, @@ -289,6 +297,9 @@ public void NonemptyCollectionSerialization() var collectionNames = new List { "acr_values_supported", + "authorization_encryption_alg_values_supported", + "authorization_encryption_enc_values_supported", + "authorization_signing_alg_values_supported", "backchannel_authentication_request_signing_alg_values_supported", "backchannel_token_delivery_modes_supported", "claims_supported", diff --git a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadata.json b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadata.json index bf10bb1f2c..90af72ef9f 100644 --- a/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadata.json +++ b/test/Microsoft.IdentityModel.Protocols.OpenIdConnect.Tests/OpenIdConnectMetadata.json @@ -1,7 +1,10 @@ { "acr_values_supported": ["acr_value1", "acr_value2", "acr_value3"], "authorization_endpoint": "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/authorize", + "authorization_encryption_alg_values_supported": ["A192KW", "A256KW"], + "authorization_encryption_enc_values_supported": ["A128CBC-HS256", "A256CBC-HS512"], "authorization_response_iss_parameter_supported": false, + "authorization_signing_alg_values_supported": ["ES384", "ES512"], "backchannel_authentication_endpoint": "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/bc-authorize", "backchannel_authentication_request_signing_alg_values_supported": ["ES384", "ES512"], "backchannel_token_delivery_modes_supported": ["poll", "ping"], @@ -52,6 +55,7 @@ "token_endpoint": "https://login.windows.net/d062b2b0-9aca-4ff7-b32a-ba47231a4002/oauth2/token", "token_endpoint_auth_methods_supported": ["client_secret_post", "private_key_jwt"], "token_endpoint_auth_signing_alg_values_supported": ["ES192", "ES256"], + "tls_client_certificate_bound_access_tokens": true, "ui_locales_supported": ["hak-CN", "en-us"], "userinfo_endpoint": "https://login.microsoftonline.com/add29489-7269-41f4-8841-b63c95564420/openid/userinfo", "userinfo_encryption_alg_values_supported": ["ECDH-ES+A128KW", "ECDH-ES+A192KW"], From c24bfe683427dbad566fe617d0d590ec3a61d8aa Mon Sep 17 00:00:00 2001 From: jennyf19 Date: Wed, 19 Jun 2024 09:08:34 -0700 Subject: [PATCH 5/5] Update CHANGELOG.md (#2653) --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a9f0c8101..fa81e50d90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,6 @@ See the [releases](https://github.com/AzureAD/azure-activedirectory-identitymode - `JwtRegisteredClaimNames` now contains previously missing Standard OpenIdConnect claims. See issue [#1598](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1598) for details. ### Performance Improvements: -- Reduced allocations in `AadIssuerValidator` by not using `string.Replace` where appropriate. See issue [#2595](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2595) and PR [#2597](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/2597) for more details. - No longer for every string claim, calling DateTime.TryParse on each value, whether it is expected to be a DateTime or not. See issue [#2615](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2615) for details. 7.6.0