From b72b73b540cf188df04f1204b8c04bed1daf4636 Mon Sep 17 00:00:00 2001 From: Brett Hazen <2651260+bhazen@users.noreply.github.com> Date: Thu, 4 Sep 2025 14:06:50 -0500 Subject: [PATCH 1/4] Updated IdentityServer projects to latest preview version of IdentityModel --- Directory.Packages.props | 2 +- .../DPoP/DPoPExtensions.cs | 3 ++- .../DPoP/DPoPProofValidator.cs | 9 +++++---- .../DPoP/DPoPProofValidatorTestBase.cs | 5 +++-- .../Pages/Diagnostics/ViewModel.cs | 4 ++-- .../DPoP/DPoPExtensions.cs | 3 ++- .../DPoP/DPoPProofValidator.cs | 5 +++-- .../src/ConsoleResourceIndicators/Program.cs | 10 +++++----- .../src/Constants/TokenResponseExtensions.cs | 6 +++--- .../UI/Main/Pages/Diagnostics/ViewModel.cs | 4 ++-- .../Configuration/CryptoHelper.cs | 3 ++- .../AuthenticationPropertiesExtensions.cs | 6 +++--- .../Extensions/JsonWebKeyExtensions.cs | 3 ++- .../ValidatedAuthorizeRequestExtensions.cs | 3 ++- .../Extensions/X509CertificateExtensions.cs | 4 ++-- .../Models/Messages/ConsentRequest.cs | 3 ++- .../Default/DiscoveryResponseGenerator.cs | 19 ++++++++++--------- .../Default/ProtectedDataMessageStore.cs | 6 +++--- .../Default/DefaultDPoPProofValidator.cs | 3 ++- .../Default/TokenRequestValidator.cs | 3 ++- .../Clients/ClientAssertionClient.cs | 3 ++- .../Clients/ClientCredentialsClient.cs | 3 ++- .../Clients/CustomTokenResponseClients.cs | 4 ++-- .../Clients/ExtensionGrantClient.cs | 3 ++- .../Clients/ResourceOwnerClient.cs | 4 ++-- .../Clients/UserInfoClient.cs | 4 ++-- .../Conformance/Pkce/PkceTests.cs | 3 ++- .../Endpoints/EndSession/EndSessionTests.cs | 7 ++++--- .../Endpoints/Token/RefreshTokenTests.cs | 10 +++++----- .../Extensibility/CustomClaimsServiceTests.cs | 4 ++-- .../CustomProfileServiceTests.cs | 4 ++-- .../CustomTokenCreationServiceTests.cs | 4 ++-- .../LocalApiAuthenticationTests.cs | 9 +++++---- .../DefaultBackChannelLogoutServiceTests.cs | 4 ++-- .../Validation/DPoPProofValidatorTests.cs | 3 ++- .../Validation/IdentityTokenValidation.cs | 3 ++- .../TokenRequestValidation_PKCE.cs | 3 ++- 37 files changed, 100 insertions(+), 79 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index ab4e81320..0f7bfa57a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -49,7 +49,7 @@ - + diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPExtensions.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPExtensions.cs index d28c3862b..097fe4a78 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPExtensions.cs +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text.Json; using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; @@ -44,5 +45,5 @@ internal static class DPoPExtensions /// /// Create the value of a thumbprint /// - public static string CreateThumbprint(this JsonWebKey jwk) => Base64Url.Encode(jwk.ComputeJwkThumbprint()); + public static string CreateThumbprint(this JsonWebKey jwk) => Base64Url.EncodeToString(jwk.ComputeJwkThumbprint()); } diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs index f048dee75..d80d7a1e4 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs @@ -1,6 +1,7 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Cryptography; using System.Text; using System.Text.Json; @@ -21,7 +22,7 @@ internal class DPoPProofValidator : IDPoPProofValidator private const string DataProtectorPurpose = "DPoPJwtBearerEvents-DPoPProofValidation-nonce"; /// - /// Provides the options for DPoP proof validation. + /// Provides the options for DPoP proof validation. /// internal readonly IOptionsMonitor OptionsMonitor; @@ -263,7 +264,7 @@ internal class DPoPProofValidator : IDPoPProofValidator var bytes = Encoding.UTF8.GetBytes(context.AccessToken); var hash = SHA256.HashData(bytes); - var accessTokenHash = Base64Url.Encode(hash); + var accessTokenHash = Base64Url.EncodeToString(hash); if (accessTokenHash != result.AccessTokenHash) { result.SetError("Invalid 'ath' value."); @@ -278,7 +279,7 @@ internal class DPoPProofValidator : IDPoPProofValidator return; } var jtiBytes = Encoding.UTF8.GetBytes(jtiString); - result.TokenIdHash = Base64Url.Encode(SHA256.HashData(jtiBytes)); + result.TokenIdHash = Base64Url.EncodeToString(SHA256.HashData(jtiBytes)); } if (string.IsNullOrEmpty(result.TokenIdHash)) @@ -382,7 +383,7 @@ internal class DPoPProofValidator : IDPoPProofValidator skew = dPoPOptions.ServerClockSkew; } - // we do x2 here because the clock might be before or after, so we're making cache duration + // we do x2 here because the clock might be before or after, so we're making cache duration // longer than the likelihood of proof token expiration, which is done before replay skew *= 2; var cacheDuration = dPoPOptions.ProofTokenValidityDuration + skew; diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPProofValidatorTestBase.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPProofValidatorTestBase.cs index 1626ba042..1947ac9c9 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPProofValidatorTestBase.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPProofValidatorTestBase.cs @@ -1,6 +1,7 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Security.Cryptography; using System.Text; @@ -19,7 +20,7 @@ public abstract class DPoPProofValidatorTestBase { ProofValidator = CreateProofValidator(); var jtiBytes = Encoding.UTF8.GetBytes(TokenId); - TokenIdHash = Base64Url.Encode(SHA256.HashData(jtiBytes)); + TokenIdHash = Base64Url.EncodeToString(SHA256.HashData(jtiBytes)); Context = new() { Options = Options, @@ -52,7 +53,7 @@ public abstract class DPoPProofValidatorTestBase protected DPoPProofValidationResult Result = new(); - // This is just an arbitrary date that we're going to do all our date arithmetic relative to. + // This is just an arbitrary date that we're going to do all our date arithmetic relative to. // It was chosen because it is convenient to use - it is well within the range of DateTime protected const long IssuedAt = 1704088800; // Mon Jan 01 2024 06:00:00 GMT+0000 protected const long ValidFor = 100; diff --git a/bff/hosts/Hosts.IdentityServer/Pages/Diagnostics/ViewModel.cs b/bff/hosts/Hosts.IdentityServer/Pages/Diagnostics/ViewModel.cs index 58bde0f7c..f312d4caa 100644 --- a/bff/hosts/Hosts.IdentityServer/Pages/Diagnostics/ViewModel.cs +++ b/bff/hosts/Hosts.IdentityServer/Pages/Diagnostics/ViewModel.cs @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; namespace IdentityServerHost.Pages.Diagnostics; @@ -18,7 +18,7 @@ public class ViewModel if (result.Properties.Items.ContainsKey("client_list")) { var encoded = result.Properties.Items["client_list"]; - var bytes = Base64Url.Decode(encoded); + var bytes = Base64Url.DecodeFromChars(encoded); var value = Encoding.UTF8.GetString(bytes); Clients = JsonSerializer.Deserialize(value); diff --git a/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs b/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs index 54656c069..beb2bf0ed 100644 --- a/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs +++ b/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text.Json; using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; @@ -66,7 +67,7 @@ static class DPoPExtensions /// public static string CreateThumbprint(this JsonWebKey jwk) { - var jkt = Base64Url.Encode(jwk.ComputeJwkThumbprint()); + var jkt = Base64Url.EncodeToString(jwk.ComputeJwkThumbprint()); return jkt; } } diff --git a/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs b/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs index 734358666..984f7879c 100644 --- a/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs +++ b/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs @@ -1,6 +1,7 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Cryptography; using System.Text; using System.Text.Json; @@ -226,7 +227,7 @@ public class DPoPProofValidator var bytes = Encoding.UTF8.GetBytes(context.AccessToken); var hash = sha.ComputeHash(bytes); - var accessTokenHash = Base64Url.Encode(hash); + var accessTokenHash = Base64Url.EncodeToString(hash); if (accessTokenHash != result.AccessTokenHash) { result.IsError = true; @@ -328,7 +329,7 @@ public class DPoPProofValidator skew = dpopOptions.ServerClockSkew; } - // we do x2 here because clock might be might be before or after, so we're making cache duration + // we do x2 here because clock might be might be before or after, so we're making cache duration // longer than the likelyhood of proof token expiration, which is done before replay skew *= 2; var cacheDuration = dpopOptions.ProofTokenValidityDuration + skew; diff --git a/identity-server/clients/src/ConsoleResourceIndicators/Program.cs b/identity-server/clients/src/ConsoleResourceIndicators/Program.cs index c3e54c5a2..ac736a9e1 100644 --- a/identity-server/clients/src/ConsoleResourceIndicators/Program.cs +++ b/identity-server/clients/src/ConsoleResourceIndicators/Program.cs @@ -1,10 +1,10 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using Clients; using ConsoleResourceIndicators; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityModel.OidcClient; using Microsoft.Extensions.Hosting; @@ -103,8 +103,8 @@ async Task FrontChannel(string scope, IEnumerable resource) Console.WriteLine(); Console.WriteLine("Standard access token:"); - Console.WriteLine(Encoding.UTF8.GetString(Base64Url.Decode(header)).PrettyPrintJson()); - Console.WriteLine(Encoding.UTF8.GetString(Base64Url.Decode(payload)).PrettyPrintJson()); + Console.WriteLine(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(header)).PrettyPrintJson()); + Console.WriteLine(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)).PrettyPrintJson()); if (result.RefreshToken == null) { @@ -155,8 +155,8 @@ async Task Refresh(string refreshToken, string resource) var header = parts[0]; var payload = parts[1]; - Console.WriteLine(Encoding.UTF8.GetString(Base64Url.Decode(header)).PrettyPrintJson()); - Console.WriteLine(Encoding.UTF8.GetString(Base64Url.Decode(payload)).PrettyPrintJson()); + Console.WriteLine(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(header)).PrettyPrintJson()); + Console.WriteLine(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)).PrettyPrintJson()); } internal class Test diff --git a/identity-server/clients/src/Constants/TokenResponseExtensions.cs b/identity-server/clients/src/Constants/TokenResponseExtensions.cs index 453bbae46..c36d85f14 100644 --- a/identity-server/clients/src/Constants/TokenResponseExtensions.cs +++ b/identity-server/clients/src/Constants/TokenResponseExtensions.cs @@ -1,9 +1,9 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; namespace Clients; @@ -25,8 +25,8 @@ public static class TokenResponseExtensions var header = parts[0]; var payload = parts[1]; - Console.WriteLine(PrettyPrintJson(Encoding.UTF8.GetString(Base64Url.Decode(header)))); - Console.WriteLine(PrettyPrintJson(Encoding.UTF8.GetString(Base64Url.Decode(payload)))); + Console.WriteLine(PrettyPrintJson(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(header)))); + Console.WriteLine(PrettyPrintJson(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)))); } } else diff --git a/identity-server/hosts/UI/Main/Pages/Diagnostics/ViewModel.cs b/identity-server/hosts/UI/Main/Pages/Diagnostics/ViewModel.cs index 2a160b3d6..6bab58ec3 100644 --- a/identity-server/hosts/UI/Main/Pages/Diagnostics/ViewModel.cs +++ b/identity-server/hosts/UI/Main/Pages/Diagnostics/ViewModel.cs @@ -1,9 +1,9 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; namespace Duende.IdentityServer.UI.Pages.Diagnostics; @@ -18,7 +18,7 @@ public class ViewModel { if (encoded != null) { - var bytes = Base64Url.Decode(encoded); + var bytes = Base64Url.DecodeFromChars(encoded); var value = Encoding.UTF8.GetString(bytes); Clients = JsonSerializer.Deserialize(value) ?? Enumerable.Empty(); return; diff --git a/identity-server/src/IdentityServer/Configuration/CryptoHelper.cs b/identity-server/src/IdentityServer/Configuration/CryptoHelper.cs index 1447992d6..e2161f753 100644 --- a/identity-server/src/IdentityServer/Configuration/CryptoHelper.cs +++ b/identity-server/src/IdentityServer/Configuration/CryptoHelper.cs @@ -4,6 +4,7 @@ #nullable enable +using System.Buffers.Text; using System.Globalization; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -75,7 +76,7 @@ public static class CryptoHelper var leftPart = new byte[size]; Array.Copy(hash, leftPart, size); - return Base64Url.Encode(leftPart); + return Base64Url.EncodeToString(leftPart); } /// diff --git a/identity-server/src/IdentityServer/Extensions/AuthenticationPropertiesExtensions.cs b/identity-server/src/IdentityServer/Extensions/AuthenticationPropertiesExtensions.cs index f9a90be67..1cd60d896 100644 --- a/identity-server/src/IdentityServer/Extensions/AuthenticationPropertiesExtensions.cs +++ b/identity-server/src/IdentityServer/Extensions/AuthenticationPropertiesExtensions.cs @@ -2,8 +2,8 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; -using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; namespace Duende.IdentityServer.Extensions; @@ -91,7 +91,7 @@ public static class AuthenticationPropertiesExtensions { if (value.IsPresent()) { - var bytes = Base64Url.Decode(value); + var bytes = Base64Url.DecodeFromChars(value); value = Encoding.UTF8.GetString(bytes); return ObjectSerializer.FromString(value); } @@ -105,7 +105,7 @@ public static class AuthenticationPropertiesExtensions { var value = ObjectSerializer.ToString(list); var bytes = Encoding.UTF8.GetBytes(value); - value = Base64Url.Encode(bytes); + value = Base64Url.EncodeToString(bytes); return value; } diff --git a/identity-server/src/IdentityServer/Extensions/JsonWebKeyExtensions.cs b/identity-server/src/IdentityServer/Extensions/JsonWebKeyExtensions.cs index 753d85f5b..f72e0b300 100644 --- a/identity-server/src/IdentityServer/Extensions/JsonWebKeyExtensions.cs +++ b/identity-server/src/IdentityServer/Extensions/JsonWebKeyExtensions.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text.Json; using Duende.IdentityModel; using Microsoft.IdentityModel.Tokens; @@ -30,7 +31,7 @@ internal static class JsonWebKeyExtensions /// public static string CreateThumbprint(this JsonWebKey jwk) { - var jkt = Base64Url.Encode(jwk.ComputeJwkThumbprint()); + var jkt = Base64Url.EncodeToString(jwk.ComputeJwkThumbprint()); return jkt; } } diff --git a/identity-server/src/IdentityServer/Extensions/ValidatedAuthorizeRequestExtensions.cs b/identity-server/src/IdentityServer/Extensions/ValidatedAuthorizeRequestExtensions.cs index c76d6d57a..852e3e496 100644 --- a/identity-server/src/IdentityServer/Extensions/ValidatedAuthorizeRequestExtensions.cs +++ b/identity-server/src/IdentityServer/Extensions/ValidatedAuthorizeRequestExtensions.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Collections.Specialized; using System.Globalization; using System.Security.Cryptography; @@ -159,7 +160,7 @@ public static class ValidatedAuthorizeRequestExtensions var bytes = Encoding.UTF8.GetBytes(clientId + origin + sessionId + salt); var hash = SHA256.HashData(bytes); - return Base64Url.Encode(hash) + "." + salt; + return Base64Url.EncodeToString(hash) + "." + salt; } private static NameValueCollection ToOptimizedRawValues(this ValidatedAuthorizeRequest request) diff --git a/identity-server/src/IdentityServer/Extensions/X509CertificateExtensions.cs b/identity-server/src/IdentityServer/Extensions/X509CertificateExtensions.cs index d0c4d424c..e06df5329 100644 --- a/identity-server/src/IdentityServer/Extensions/X509CertificateExtensions.cs +++ b/identity-server/src/IdentityServer/Extensions/X509CertificateExtensions.cs @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text.Json; -using Duende.IdentityModel; namespace Duende.IdentityServer.Extensions; @@ -35,5 +35,5 @@ public static class X509CertificateExtensions /// Returns the SHA256 thumbprint of the certificate as a base64url encoded string /// /// - public static string GetSha256Thumbprint(this X509Certificate2 certificate) => Base64Url.Encode(certificate.GetCertHash(HashAlgorithmName.SHA256)); + public static string GetSha256Thumbprint(this X509Certificate2 certificate) => Base64Url.EncodeToString(certificate.GetCertHash(HashAlgorithmName.SHA256)); } diff --git a/identity-server/src/IdentityServer/Models/Messages/ConsentRequest.cs b/identity-server/src/IdentityServer/Models/Messages/ConsentRequest.cs index 247bc34f2..632a31d29 100644 --- a/identity-server/src/IdentityServer/Models/Messages/ConsentRequest.cs +++ b/identity-server/src/IdentityServer/Models/Messages/ConsentRequest.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Collections.Specialized; using System.Security.Cryptography; using System.Text; @@ -89,7 +90,7 @@ public class ConsentRequest var bytes = Encoding.UTF8.GetBytes(value); var hash = SHA256.HashData(bytes); - return Base64Url.Encode(hash); + return Base64Url.EncodeToString(hash); } } } diff --git a/identity-server/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs b/identity-server/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs index 554bb545e..6275b8a56 100644 --- a/identity-server/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs +++ b/identity-server/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Cryptography; using Duende.IdentityModel; using Duende.IdentityServer.Configuration; @@ -435,13 +436,13 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator if (key.Key is X509SecurityKey x509Key) { var cert64 = Convert.ToBase64String(x509Key.Certificate.RawData); - var thumbprint = Base64Url.Encode(x509Key.Certificate.GetCertHash()); + var thumbprint = Base64Url.EncodeToString(x509Key.Certificate.GetCertHash()); if (x509Key.PublicKey is RSA rsa) { var parameters = rsa.ExportParameters(false); - var exponent = Base64Url.Encode(parameters.Exponent); - var modulus = Base64Url.Encode(parameters.Modulus); + var exponent = Base64Url.EncodeToString(parameters.Exponent); + var modulus = Base64Url.EncodeToString(parameters.Modulus); var rsaJsonWebKey = new Models.JsonWebKey { @@ -459,8 +460,8 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator else if (x509Key.PublicKey is ECDsa ecdsa) { var parameters = ecdsa.ExportParameters(false); - var x = Base64Url.Encode(parameters.Q.X); - var y = Base64Url.Encode(parameters.Q.Y); + var x = Base64Url.EncodeToString(parameters.Q.X); + var y = Base64Url.EncodeToString(parameters.Q.Y); var ecdsaJsonWebKey = new Models.JsonWebKey { @@ -484,8 +485,8 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator else if (key.Key is RsaSecurityKey rsaKey) { var parameters = rsaKey.Rsa?.ExportParameters(false) ?? rsaKey.Parameters; - var exponent = Base64Url.Encode(parameters.Exponent); - var modulus = Base64Url.Encode(parameters.Modulus); + var exponent = Base64Url.EncodeToString(parameters.Exponent); + var modulus = Base64Url.EncodeToString(parameters.Modulus); var webKey = new Models.JsonWebKey { @@ -502,8 +503,8 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator else if (key.Key is ECDsaSecurityKey ecdsaKey) { var parameters = ecdsaKey.ECDsa.ExportParameters(false); - var x = Base64Url.Encode(parameters.Q.X); - var y = Base64Url.Encode(parameters.Q.Y); + var x = Base64Url.EncodeToString(parameters.Q.X); + var y = Base64Url.EncodeToString(parameters.Q.Y); var ecdsaJsonWebKey = new Models.JsonWebKey { diff --git a/identity-server/src/IdentityServer/Stores/Default/ProtectedDataMessageStore.cs b/identity-server/src/IdentityServer/Stores/Default/ProtectedDataMessageStore.cs index 321ef61c8..86e73b3b3 100644 --- a/identity-server/src/IdentityServer/Stores/Default/ProtectedDataMessageStore.cs +++ b/identity-server/src/IdentityServer/Stores/Default/ProtectedDataMessageStore.cs @@ -2,8 +2,8 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; -using Duende.IdentityModel; using Duende.IdentityServer.Models; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Logging; @@ -50,7 +50,7 @@ public class ProtectedDataMessageStore : IMessageStore { try { - var bytes = Base64Url.Decode(value); + var bytes = Base64Url.DecodeFromChars(value); bytes = Protector.Unprotect(bytes); var json = Encoding.UTF8.GetString(bytes); result = ObjectSerializer.FromString>(json); @@ -76,7 +76,7 @@ public class ProtectedDataMessageStore : IMessageStore var json = ObjectSerializer.ToString(message); var bytes = Encoding.UTF8.GetBytes(json); bytes = Protector.Protect(bytes); - value = Base64Url.Encode(bytes); + value = Base64Url.EncodeToString(bytes); } catch (Exception ex) { diff --git a/identity-server/src/IdentityServer/Validation/Default/DefaultDPoPProofValidator.cs b/identity-server/src/IdentityServer/Validation/Default/DefaultDPoPProofValidator.cs index 451e98ef3..d51fb7fe1 100644 --- a/identity-server/src/IdentityServer/Validation/Default/DefaultDPoPProofValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/DefaultDPoPProofValidator.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Globalization; using System.Security.Cryptography; using System.Text; @@ -302,7 +303,7 @@ public class DefaultDPoPProofValidator : IDPoPProofValidator var bytes = Encoding.UTF8.GetBytes(context.AccessToken); var hash = SHA256.HashData(bytes); - var accessTokenHash = Base64Url.Encode(hash); + var accessTokenHash = Base64Url.EncodeToString(hash); if (accessTokenHash != result.AccessTokenHash) { result.IsError = true; diff --git a/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs b/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs index abd7c111f..a4b78bfa3 100644 --- a/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Collections.Specialized; using System.Text; using Duende.IdentityModel; @@ -1231,7 +1232,7 @@ internal class TokenRequestValidator : ITokenRequestValidator var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier); var hashedBytes = codeVerifierBytes.Sha256(); - var transformedCodeVerifier = Base64Url.Encode(hashedBytes); + var transformedCodeVerifier = Base64Url.EncodeToString(hashedBytes); return TimeConstantComparer.IsEqual(transformedCodeVerifier.Sha256(), codeChallenge); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs index 56de3fba3..c5cfdd5e0 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; @@ -223,7 +224,7 @@ public class ClientAssertionClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs index a913cbecb..35854ef2c 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Net; using System.Text; using System.Text.Json; @@ -433,7 +434,7 @@ public class ClientCredentialsClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs index 83801d7a6..e157ef7e0 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Clients.Setup; using Duende.IdentityServer.IntegrationTests.Common; @@ -275,7 +275,7 @@ public class CustomTokenResponseClients { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs index 0c6b2ff1b..24156783e 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Text; @@ -588,7 +589,7 @@ public class ExtensionGrantClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs index ef492f51d..fd5b8f050 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Net; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Clients.Setup; using Microsoft.AspNetCore.Hosting; @@ -268,7 +268,7 @@ public class ResourceOwnerClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs index 76875c33e..2a8eb18a7 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Net; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Clients.Setup; using Duende.IdentityServer.IntegrationTests.Common; @@ -204,7 +204,7 @@ public class UserInfoEndpointClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs index 5cd7fddbe..f22f5a3ee 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Text; using Duende.IdentityModel; @@ -528,7 +529,7 @@ public class PkceTests { var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier); var hashedBytes = codeVerifierBytes.Sha256(); - var transformedCodeVerifier = Base64Url.Encode(hashedBytes); + var transformedCodeVerifier = Base64Url.EncodeToString(hashedBytes); return transformedCodeVerifier; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs index 25ea0df75..42b2f9133 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Globalization; using System.Net; using System.Security.Claims; @@ -581,7 +582,7 @@ public class EndSessionTests var parts = token.Split('.'); parts.Length.ShouldBe(3); - var bytes = Base64Url.Decode(parts[1]); + var bytes = Base64Url.DecodeFromChars(parts[1]); var json = Encoding.UTF8.GetString(bytes); var payload = JsonSerializer.Deserialize>(json); @@ -629,7 +630,7 @@ public class EndSessionTests var parts = token.Split('.'); parts.Length.ShouldBe(3); - var bytes = Base64Url.Decode(parts[0]); + var bytes = Base64Url.DecodeFromChars(parts[0]); var json = Encoding.UTF8.GetString(bytes); var header = JsonSerializer.Deserialize>(json); @@ -669,7 +670,7 @@ public class EndSessionTests var parts = token.Split('.'); parts.Length.ShouldBe(3); - var bytes = Base64Url.Decode(parts[0]); + var bytes = Base64Url.DecodeFromChars(parts[0]); var json = Encoding.UTF8.GetString(bytes); var header = JsonSerializer.Deserialize>(json); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs index 940f18fe8..c96235752 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Common; using Duende.IdentityServer.Models; @@ -97,7 +97,7 @@ public class RefreshTokenTests tokenResult1.AccessToken.ShouldNotBeNull(); - var payload1 = JsonSerializer.Deserialize(Base64Url.Decode(tokenResult1.AccessToken.Split('.')[1])); + var payload1 = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(tokenResult1.AccessToken.Split('.')[1])); var sid1 = payload1.TryGetValue("sid").GetString(); sid1.ShouldBe(_mockPipeline.GetSessionCookie().Value); @@ -114,7 +114,7 @@ public class RefreshTokenTests tokenResult2.IsError.ShouldBeFalse(); tokenResult2.AccessToken.ShouldNotBeNull(); - var payload2 = JsonSerializer.Deserialize(Base64Url.Decode(tokenResult2.AccessToken.Split('.')[1])); + var payload2 = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(tokenResult2.AccessToken.Split('.')[1])); var sid2 = payload2.TryGetValue("sid").GetString(); sid1.ShouldBe(sid2); } @@ -155,7 +155,7 @@ public class RefreshTokenTests tokenResult1.AccessToken.ShouldNotBeNull(); - var payload1 = JsonSerializer.Deserialize(Base64Url.Decode(tokenResult1.AccessToken.Split('.')[1])); + var payload1 = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(tokenResult1.AccessToken.Split('.')[1])); var sid1 = payload1.TryGetValue("sid").GetString(); sid1.ShouldBe(_mockPipeline.GetSessionCookie().Value); @@ -172,7 +172,7 @@ public class RefreshTokenTests tokenResult2.IsError.ShouldBeFalse(); tokenResult2.AccessToken.ShouldNotBeNull(); - var payload2 = JsonSerializer.Deserialize(Base64Url.Decode(tokenResult2.AccessToken.Split('.')[1])); + var payload2 = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(tokenResult2.AccessToken.Split('.')[1])); var sid2 = payload2.TryGetValue("sid").GetString(); sid1.ShouldBe(sid2); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs index 290e7ba65..84130fc52 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Common; using Duende.IdentityServer.Models; @@ -64,7 +64,7 @@ public class CustomClaimsServiceTests var accessToken = result.AccessToken; var payload = accessToken.Split('.')[1]; - var json = Encoding.UTF8.GetString(Base64Url.Decode(payload)); + var json = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)); var obj = JsonSerializer.Deserialize>(json); obj["foo"].GetString().ShouldBe("foo1"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs index b5c3869c8..1b662ad82 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs @@ -2,11 +2,11 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Net; using System.Security.Claims; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityServer.IntegrationTests.Common; using Duende.IdentityServer.Models; using Duende.IdentityServer.Services; @@ -73,7 +73,7 @@ public class CustomProfileServiceTests authorization.IdentityToken.ShouldNotBeNull(); var payload = authorization.IdentityToken.Split('.')[1]; - var json = Encoding.UTF8.GetString(Base64Url.Decode(payload)); + var json = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)); var obj = JsonSerializer.Deserialize>(json); obj["foo"].GetString().ShouldBe("bar"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs index c4cd24e17..a8ff3cf5b 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.Configuration; using Duende.IdentityServer.IntegrationTests.Common; @@ -63,7 +63,7 @@ public class CustomTokenCreationServiceTests var accessToken = result.AccessToken; var payload = accessToken.Split('.')[1]; - var json = Encoding.UTF8.GetString(Base64Url.Decode(payload)); + var json = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)); var obj = JsonSerializer.Deserialize>(json); obj["aud"].ToStringList().ShouldContain("custom1"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs index 5ee8c133f..34550eff9 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Net.Http.Headers; @@ -212,11 +213,11 @@ public class LocalApiAuthenticationTests if (!string.IsNullOrWhiteSpace(accessToken)) { - // ath: hash of the access token. The value MUST be the result of a base64url encoding + // ath: hash of the access token. The value MUST be the result of a base64url encoding // the SHA-256 hash of the ASCII encoding of the associated access token's value. using var sha256 = SHA256.Create(); var hash = sha256.ComputeHash(Encoding.ASCII.GetBytes(accessToken)); - var ath = Base64Url.Encode(hash); + var ath = Base64Url.EncodeToString(hash); payload.Add(JwtClaimTypes.DPoPAccessTokenHash, ath); } @@ -293,7 +294,7 @@ public class LocalApiAuthenticationTests // so it should fail. var newKey = GenerateJwk(); var newJwk = new Microsoft.IdentityModel.Tokens.JsonWebKey(newKey); - var newJkt = Base64Url.Encode(newJwk.ComputeJwkThumbprint()); + var newJkt = Base64Url.EncodeToString(newJwk.ComputeJwkThumbprint()); var proofToken = CreateProofToken("GET", "https://server/api", at, jwkString: newKey); req.Headers.Add("DPoP", proofToken); @@ -328,7 +329,7 @@ public class LocalApiAuthenticationTests // so it should fail. var newKey = GenerateJwk(); var newJwk = new Microsoft.IdentityModel.Tokens.JsonWebKey(newKey); - var newJkt = Base64Url.Encode(newJwk.ComputeJwkThumbprint()); + var newJkt = Base64Url.EncodeToString(newJwk.ComputeJwkThumbprint()); var proofToken = CreateProofToken("GET", "https://server/api", at, jwkString: newKey); req.Headers.Add("DPoP", proofToken); diff --git a/identity-server/test/IdentityServer.UnitTests/Services/Default/DefaultBackChannelLogoutServiceTests.cs b/identity-server/test/IdentityServer.UnitTests/Services/Default/DefaultBackChannelLogoutServiceTests.cs index af2e6104b..3bf04ed56 100644 --- a/identity-server/test/IdentityServer.UnitTests/Services/Default/DefaultBackChannelLogoutServiceTests.cs +++ b/identity-server/test/IdentityServer.UnitTests/Services/Default/DefaultBackChannelLogoutServiceTests.cs @@ -2,8 +2,8 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityServer; using Duende.IdentityServer.Configuration; using Duende.IdentityServer.Services; @@ -62,7 +62,7 @@ public class DefaultBackChannelLogoutServiceTests }); - var payload = JsonSerializer.Deserialize>(Base64Url.Decode(rawToken.Split('.')[1])); + var payload = JsonSerializer.Deserialize>(Base64Url.DecodeFromChars(rawToken.Split('.')[1])); payload["iss"].GetString().ShouldBe(expected); } } diff --git a/identity-server/test/IdentityServer.UnitTests/Validation/DPoPProofValidatorTests.cs b/identity-server/test/IdentityServer.UnitTests/Validation/DPoPProofValidatorTests.cs index 19bba6035..caeeb5b3d 100644 --- a/identity-server/test/IdentityServer.UnitTests/Validation/DPoPProofValidatorTests.cs +++ b/identity-server/test/IdentityServer.UnitTests/Validation/DPoPProofValidatorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Security.Cryptography; using System.Text; @@ -168,7 +169,7 @@ public class DPoPProofValidatorTests using var sha = SHA256.Create(); var bytes = Encoding.UTF8.GetBytes(_context.AccessToken); var hash = sha.ComputeHash(bytes); - return Base64Url.Encode(hash); + return Base64Url.EncodeToString(hash); } [Fact] diff --git a/identity-server/test/IdentityServer.UnitTests/Validation/IdentityTokenValidation.cs b/identity-server/test/IdentityServer.UnitTests/Validation/IdentityTokenValidation.cs index 949a38d5e..ca9f0bc18 100644 --- a/identity-server/test/IdentityServer.UnitTests/Validation/IdentityTokenValidation.cs +++ b/identity-server/test/IdentityServer.UnitTests/Validation/IdentityTokenValidation.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.IdentityModel.Tokens.Jwt; using System.Text; using System.Text.Json; @@ -93,7 +94,7 @@ public class IdentityTokenValidation // check that the custom aud was ignored var payload = jwt.Split('.')[1]; - var json = Encoding.UTF8.GetString(Base64Url.Decode(payload)); + var json = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)); var values = JsonSerializer.Deserialize>(json); values["aud"].GetString().ShouldBe("roclient"); } diff --git a/identity-server/test/IdentityServer.UnitTests/Validation/TokenRequest Validation/TokenRequestValidation_PKCE.cs b/identity-server/test/IdentityServer.UnitTests/Validation/TokenRequest Validation/TokenRequestValidation_PKCE.cs index be005306a..19ee332ed 100644 --- a/identity-server/test/IdentityServer.UnitTests/Validation/TokenRequest Validation/TokenRequestValidation_PKCE.cs +++ b/identity-server/test/IdentityServer.UnitTests/Validation/TokenRequest Validation/TokenRequestValidation_PKCE.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Collections.Specialized; using System.Text; using Duende.IdentityModel; @@ -316,7 +317,7 @@ public class TokenRequestValidation_PKCE { var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier); var hashedBytes = codeVerifierBytes.Sha256(); - var transformedCodeVerifier = Base64Url.Encode(hashedBytes); + var transformedCodeVerifier = Base64Url.EncodeToString(hashedBytes); return transformedCodeVerifier; } From 7d87e09c1f79ddfff2c6f0572b5d368ebd3aba45 Mon Sep 17 00:00:00 2001 From: Joe DeCock Date: Thu, 16 Oct 2025 15:15:27 -0500 Subject: [PATCH 2/4] Disable nuget packaging for internal projects --- identity-server/hosts/Shared/Host.Shared.csproj | 1 + identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj | 1 + .../hosts/UI/EntityFramework/UI.EntityFramework.csproj | 1 + identity-server/hosts/UI/Main/UI.Main.csproj | 1 + shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj | 1 + 5 files changed, 5 insertions(+) diff --git a/identity-server/hosts/Shared/Host.Shared.csproj b/identity-server/hosts/Shared/Host.Shared.csproj index dee7a1949..724447fa3 100644 --- a/identity-server/hosts/Shared/Host.Shared.csproj +++ b/identity-server/hosts/Shared/Host.Shared.csproj @@ -5,6 +5,7 @@ enable enable Duende.IdentityServer.Hosts.Shared + false diff --git a/identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj b/identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj index c4badcf24..8286ca8bb 100644 --- a/identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj +++ b/identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj @@ -7,6 +7,7 @@ true Duende.IdentityServer.UI.AspNetIdentity true + false diff --git a/identity-server/hosts/UI/EntityFramework/UI.EntityFramework.csproj b/identity-server/hosts/UI/EntityFramework/UI.EntityFramework.csproj index 64c46b889..90af3cddc 100644 --- a/identity-server/hosts/UI/EntityFramework/UI.EntityFramework.csproj +++ b/identity-server/hosts/UI/EntityFramework/UI.EntityFramework.csproj @@ -7,6 +7,7 @@ true Duende.IdentityServer.UI.EntityFramework true + false diff --git a/identity-server/hosts/UI/Main/UI.Main.csproj b/identity-server/hosts/UI/Main/UI.Main.csproj index b396d5c26..14622405b 100644 --- a/identity-server/hosts/UI/Main/UI.Main.csproj +++ b/identity-server/hosts/UI/Main/UI.Main.csproj @@ -8,6 +8,7 @@ Duende.IdentityServer.UI true true + false diff --git a/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj b/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj index fe2a6dc09..5942a9e3a 100644 --- a/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj +++ b/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj @@ -7,6 +7,7 @@ Duende.Xunit.Playwright true false + false From 2721b7c72380695de96fcae6ef4100fac6fdb4eb Mon Sep 17 00:00:00 2001 From: Joe DeCock Date: Thu, 16 Oct 2025 15:56:09 -0500 Subject: [PATCH 3/4] Update to latest previews of AccessTokenManagement Also temporarily overriding some versions in JwtBearer to work around circular dependencies (we will return to this after releasing IdentityServer) --- Directory.Packages.props | 10 +++++----- .../AspNetCore.Authentication.JwtBearer.csproj | 2 +- .../DPoP/DPoPExtensions.cs | 3 +-- .../DPoP/DPoPProofValidator.cs | 5 ++--- .../AspNetCore.Authentication.JwtBearer.Tests.csproj | 5 ++--- .../DPoP/DPoPProofValidatorTestBase.cs | 3 +-- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 0f7bfa57a..dcd2e318d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -42,15 +42,15 @@ - - - - + + + + - + diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/AspNetCore.Authentication.JwtBearer.csproj b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/AspNetCore.Authentication.JwtBearer.csproj index d0d87a42a..5cf525060 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/AspNetCore.Authentication.JwtBearer.csproj +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/AspNetCore.Authentication.JwtBearer.csproj @@ -8,7 +8,7 @@ - + diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPExtensions.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPExtensions.cs index 097fe4a78..d28c3862b 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPExtensions.cs +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. -using System.Buffers.Text; using System.Text.Json; using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; @@ -45,5 +44,5 @@ internal static class DPoPExtensions /// /// Create the value of a thumbprint /// - public static string CreateThumbprint(this JsonWebKey jwk) => Base64Url.EncodeToString(jwk.ComputeJwkThumbprint()); + public static string CreateThumbprint(this JsonWebKey jwk) => Base64Url.Encode(jwk.ComputeJwkThumbprint()); } diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs index d80d7a1e4..bad212e01 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. -using System.Buffers.Text; using System.Security.Cryptography; using System.Text; using System.Text.Json; @@ -264,7 +263,7 @@ internal class DPoPProofValidator : IDPoPProofValidator var bytes = Encoding.UTF8.GetBytes(context.AccessToken); var hash = SHA256.HashData(bytes); - var accessTokenHash = Base64Url.EncodeToString(hash); + var accessTokenHash = Base64Url.Encode(hash); if (accessTokenHash != result.AccessTokenHash) { result.SetError("Invalid 'ath' value."); @@ -279,7 +278,7 @@ internal class DPoPProofValidator : IDPoPProofValidator return; } var jtiBytes = Encoding.UTF8.GetBytes(jtiString); - result.TokenIdHash = Base64Url.EncodeToString(SHA256.HashData(jtiBytes)); + result.TokenIdHash = Base64Url.Encode(SHA256.HashData(jtiBytes)); } if (string.IsNullOrEmpty(result.TokenIdHash)) diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/AspNetCore.Authentication.JwtBearer.Tests.csproj b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/AspNetCore.Authentication.JwtBearer.Tests.csproj index e9693adfa..0b1f5d96b 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/AspNetCore.Authentication.JwtBearer.Tests.csproj +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/AspNetCore.Authentication.JwtBearer.Tests.csproj @@ -10,12 +10,11 @@ - - + + - diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPProofValidatorTestBase.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPProofValidatorTestBase.cs index 1947ac9c9..baceb26e4 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPProofValidatorTestBase.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPProofValidatorTestBase.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. -using System.Buffers.Text; using System.Security.Claims; using System.Security.Cryptography; using System.Text; @@ -20,7 +19,7 @@ public abstract class DPoPProofValidatorTestBase { ProofValidator = CreateProofValidator(); var jtiBytes = Encoding.UTF8.GetBytes(TokenId); - TokenIdHash = Base64Url.EncodeToString(SHA256.HashData(jtiBytes)); + TokenIdHash = Base64Url.Encode(SHA256.HashData(jtiBytes)); Context = new() { Options = Options, From 672f12830502ad96e8ff1a78b5058bac83f97fc7 Mon Sep 17 00:00:00 2001 From: Joe DeCock Date: Thu, 16 Oct 2025 16:25:56 -0500 Subject: [PATCH 4/4] Revert BFF so that we can update just IdentityServer first --- Directory.Packages.props | 11 +++++++---- .../Pages/Diagnostics/ViewModel.cs | 5 ++--- .../Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs | 3 +-- .../Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs | 3 +-- bff/migrations/UserSessionDb/UserSessionDb.csproj | 1 + 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index dcd2e318d..5199f3b11 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -42,15 +42,17 @@ - + - + - - + + + + @@ -69,6 +71,7 @@ + diff --git a/bff/hosts/Hosts.IdentityServer/Pages/Diagnostics/ViewModel.cs b/bff/hosts/Hosts.IdentityServer/Pages/Diagnostics/ViewModel.cs index f312d4caa..4d93aaf24 100644 --- a/bff/hosts/Hosts.IdentityServer/Pages/Diagnostics/ViewModel.cs +++ b/bff/hosts/Hosts.IdentityServer/Pages/Diagnostics/ViewModel.cs @@ -1,10 +1,9 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. - -using System.Buffers.Text; using System.Text; using System.Text.Json; +using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; namespace IdentityServerHost.Pages.Diagnostics; @@ -18,7 +17,7 @@ public class ViewModel if (result.Properties.Items.ContainsKey("client_list")) { var encoded = result.Properties.Items["client_list"]; - var bytes = Base64Url.DecodeFromChars(encoded); + var bytes = Base64Url.Decode(encoded); var value = Encoding.UTF8.GetString(bytes); Clients = JsonSerializer.Deserialize(value); diff --git a/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs b/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs index beb2bf0ed..54656c069 100644 --- a/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs +++ b/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. -using System.Buffers.Text; using System.Text.Json; using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; @@ -67,7 +66,7 @@ static class DPoPExtensions /// public static string CreateThumbprint(this JsonWebKey jwk) { - var jkt = Base64Url.EncodeToString(jwk.ComputeJwkThumbprint()); + var jkt = Base64Url.Encode(jwk.ComputeJwkThumbprint()); return jkt; } } diff --git a/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs b/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs index 984f7879c..cbff2e5e1 100644 --- a/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs +++ b/bff/hosts/RemoteApis/Hosts.RemoteApi.DPoP/DPoP/DPoPProofValidator.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. -using System.Buffers.Text; using System.Security.Cryptography; using System.Text; using System.Text.Json; @@ -227,7 +226,7 @@ public class DPoPProofValidator var bytes = Encoding.UTF8.GetBytes(context.AccessToken); var hash = sha.ComputeHash(bytes); - var accessTokenHash = Base64Url.EncodeToString(hash); + var accessTokenHash = Base64Url.Encode(hash); if (accessTokenHash != result.AccessTokenHash) { result.IsError = true; diff --git a/bff/migrations/UserSessionDb/UserSessionDb.csproj b/bff/migrations/UserSessionDb/UserSessionDb.csproj index 7b282f273..7bb7a2c0d 100644 --- a/bff/migrations/UserSessionDb/UserSessionDb.csproj +++ b/bff/migrations/UserSessionDb/UserSessionDb.csproj @@ -7,6 +7,7 @@ +