11using Microsoft . Extensions . Logging ;
22using Microsoft . Extensions . Logging . Abstractions ;
3+ #if NET9_0_OR_GREATER
4+ using System . Buffers . Text ;
5+ #endif
36using System . Diagnostics . CodeAnalysis ;
47using System . Net . Http . Headers ;
58using System . Security . Cryptography ;
@@ -238,14 +241,17 @@ private async Task PerformOAuthAuthorizationAsync(
238241 LogOAuthAuthorizationCompleted ( ) ;
239242 }
240243
244+ private static readonly string [ ] s_wellKnownPaths = [ ".well-known/openid-configuration" , ".well-known/oauth-authorization-server" ] ;
245+
241246 private async Task < AuthorizationServerMetadata > GetAuthServerMetadataAsync ( Uri authServerUri , CancellationToken cancellationToken )
242247 {
243- if ( ! authServerUri . OriginalString . EndsWith ( "/" ) )
248+ if ( authServerUri . OriginalString . Length == 0 ||
249+ authServerUri . OriginalString [ authServerUri . OriginalString . Length - 1 ] != '/' )
244250 {
245- authServerUri = new Uri ( authServerUri . OriginalString + " /") ;
251+ authServerUri = new Uri ( $ " { authServerUri . OriginalString } /") ;
246252 }
247253
248- foreach ( var path in new [ ] { ".well-known/openid-configuration" , ".well-known/oauth-authorization-server" } )
254+ foreach ( var path in s_wellKnownPaths )
249255 {
250256 try
251257 {
@@ -540,11 +546,7 @@ private static string NormalizeUri(Uri uri)
540546 Port = - 1 // Always remove port
541547 } ;
542548
543- if ( builder . Path == "/" )
544- {
545- builder . Path = string . Empty ;
546- }
547- else if ( builder . Path . Length > 1 && builder . Path . EndsWith ( "/" ) )
549+ if ( builder . Path . Length > 0 && builder . Path [ builder . Path . Length - 1 ] == '/' )
548550 {
549551 builder . Path = builder . Path . TrimEnd ( '/' ) ;
550552 }
@@ -633,18 +635,18 @@ private async Task<ProtectedResourceMetadata> ExtractProtectedResourceMetadata(H
633635 continue ;
634636 }
635637
636- string key = trimmedPart . Substring ( 0 , equalsIndex ) . Trim ( ) ;
638+ ReadOnlySpan < char > key = trimmedPart . AsSpan ( ) . Slice ( 0 , equalsIndex ) . Trim ( ) ;
637639
638- if ( string . Equals ( key , parameterName , StringComparison . OrdinalIgnoreCase ) )
640+ if ( key . Equals ( parameterName , StringComparison . OrdinalIgnoreCase ) )
639641 {
640- string value = trimmedPart . Substring ( equalsIndex + 1 ) . Trim ( ) ;
642+ ReadOnlySpan < char > value = trimmedPart . AsSpan ( equalsIndex + 1 ) . Trim ( ) ;
641643
642- if ( value . StartsWith ( " \" " ) && value . EndsWith ( " \" " ) )
644+ if ( value . Length > 0 && value [ 0 ] == '"' && value [ value . Length - 1 ] == '"' )
643645 {
644- value = value . Substring ( 1 , value . Length - 2 ) ;
646+ value = value . Slice ( 1 , value . Length - 2 ) ;
645647 }
646648
647- return value ;
649+ return value . ToString ( ) ;
648650 }
649651 }
650652
@@ -664,12 +666,18 @@ private static string GenerateCodeVerifier()
664666
665667 private static string GenerateCodeChallenge ( string codeVerifier )
666668 {
669+ #if NET9_0_OR_GREATER
670+ Span < byte > hash = stackalloc byte [ SHA256 . HashSizeInBytes ] ;
671+ SHA256 . HashData ( Encoding . UTF8 . GetBytes ( codeVerifier ) , hash ) ;
672+ return Base64Url . EncodeToString ( hash ) ;
673+ #else
667674 using var sha256 = SHA256 . Create ( ) ;
668675 var challengeBytes = sha256 . ComputeHash ( Encoding . UTF8 . GetBytes ( codeVerifier ) ) ;
669676 return Convert . ToBase64String ( challengeBytes )
670677 . TrimEnd ( '=' )
671678 . Replace ( '+' , '-' )
672679 . Replace ( '/' , '_' ) ;
680+ #endif
673681 }
674682
675683 private string GetClientIdOrThrow ( ) => _clientId ?? throw new InvalidOperationException ( "Client ID is not available. This may indicate an issue with dynamic client registration." ) ;
0 commit comments