22// Licensed under the MIT License. See License.txt in the project root for license information.
33
44using Microsoft . AspNetCore . Authentication ;
5+ using Microsoft . AspNetCore . Http ;
56using Microsoft . Extensions . DependencyInjection ;
67using Microsoft . Extensions . Logging ;
78using Microsoft . Extensions . Options ;
@@ -26,7 +27,7 @@ internal class BasicHandler : AuthenticationHandler<BasicOptions>
2627 /// <param name="logger"></param>
2728 /// <param name="encoder"></param>
2829 /// <param name="clock"></param>
29- public BasicHandler ( IOptionsMonitor < BasicOptions > options , ILoggerFactory logger , UrlEncoder encoder , ISystemClock clock )
30+ public BasicHandler ( IOptionsMonitor < BasicOptions > options , ILoggerFactory logger , UrlEncoder encoder , ISystemClock clock )
3031 : base ( options , logger , encoder , clock )
3132 {
3233 }
@@ -36,7 +37,7 @@ public BasicHandler(IOptionsMonitor<BasicOptions> options, ILoggerFactory logger
3637 /// <summary>
3738 /// Get or set <see cref="BasicEvents"/>.
3839 /// </summary>
39- protected new BasicEvents Events { get => ( BasicEvents ) base . Events ; set => base . Events = value ; }
40+ protected new BasicEvents Events { get => ( BasicEvents ) base . Events ; set => base . Events = value ; }
4041
4142 /// <summary>
4243 /// Create an instance of <see cref="BasicEvents"/>.
@@ -50,6 +51,12 @@ public BasicHandler(IOptionsMonitor<BasicOptions> options, ILoggerFactory logger
5051 /// <returns><see cref="AuthenticateResult"/></returns>
5152 protected override async Task < AuthenticateResult > HandleAuthenticateAsync ( )
5253 {
54+ if ( IgnoreAuthenticationIfAllowAnonymous ( ) )
55+ {
56+ Logger . LogInformation ( "AllowAnonymous found on the endpoint so request was not authenticated." ) ;
57+ return AuthenticateResult . NoResult ( ) ;
58+ }
59+
5360 if ( ! Request . Headers . ContainsKey ( HeaderNames . Authorization ) )
5461 {
5562 Logger . LogInformation ( "No 'Authorization' header found in the request." ) ;
@@ -61,57 +68,57 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
6168 Logger . LogInformation ( "No valid 'Authorization' header found in the request." ) ;
6269 return AuthenticateResult . NoResult ( ) ;
6370 }
64-
71+
6572 if ( ! headerValue . Scheme . Equals ( BasicDefaults . AuthenticationScheme , StringComparison . OrdinalIgnoreCase ) )
6673 {
6774 Logger . LogInformation ( $ "'Authorization' header found but the scheme is not a '{ BasicDefaults . AuthenticationScheme } ' scheme.") ;
6875 return AuthenticateResult . NoResult ( ) ;
6976 }
7077
7178 BasicCredentials credentials ;
72- try
73- {
79+ try
80+ {
7481 credentials = DecodeBasicCredentials ( headerValue . Parameter ) ;
7582 }
76- catch ( Exception exception )
77- {
83+ catch ( Exception exception )
84+ {
7885 Logger . LogError ( exception , "Error decoding credentials from header value." ) ;
7986 return AuthenticateResult . Fail ( "Error decoding credentials from header value." + Environment . NewLine + exception . Message ) ;
8087
8188 }
82-
89+
8390 try
8491 {
8592 var validateCredentialsResult = await RaiseAndHandleEventValidateCredentialsAsync ( credentials ) . ConfigureAwait ( false ) ;
8693 if ( validateCredentialsResult != null )
87- {
94+ {
8895 // If result is set then return it.
8996 return validateCredentialsResult ;
90- }
97+ }
9198
9299 // Validate using the implementation of IBasicUserValidationService.
93100 var hasValidationSucceeded = await ValidateUsingBasicUserValidationServiceAsync ( credentials . Username , credentials . Password ) . ConfigureAwait ( false ) ;
94101 return hasValidationSucceeded
95102 ? await RaiseAndHandleAuthenticationSucceededAsync ( credentials ) . ConfigureAwait ( false )
96103 : AuthenticateResult . Fail ( "Invalid username or password." ) ;
97104 }
98- catch ( Exception exception )
99- {
105+ catch ( Exception exception )
106+ {
100107 var authenticationFailedContext = new BasicAuthenticationFailedContext ( Context , Scheme , Options , exception ) ;
101108 await Events . AuthenticationFailedAsync ( authenticationFailedContext ) . ConfigureAwait ( false ) ;
102-
109+
103110 if ( authenticationFailedContext . Result != null )
104111 {
105112 return authenticationFailedContext . Result ;
106113 }
107-
114+
108115 throw ;
109116 }
110117 }
111118
112119 /// <inheritdoc/>
113- protected override async Task HandleForbiddenAsync ( AuthenticationProperties properties )
114- {
120+ protected override async Task HandleForbiddenAsync ( AuthenticationProperties properties )
121+ {
115122 // Raise handle forbidden event.
116123 var handleForbiddenContext = new BasicHandleForbiddenContext ( Context , Scheme , Options , properties ) ;
117124 await Events . HandleForbiddenAsync ( handleForbiddenContext ) . ConfigureAwait ( false ) ;
@@ -121,7 +128,7 @@ protected override async Task HandleForbiddenAsync(AuthenticationProperties prop
121128 }
122129
123130 await base . HandleForbiddenAsync ( properties ) ;
124- }
131+ }
125132
126133 /// <summary>
127134 /// Handles the un-authenticated requests.
@@ -150,7 +157,7 @@ protected override async Task HandleChallengeAsync(AuthenticationProperties prop
150157 }
151158
152159 private async Task < AuthenticateResult > RaiseAndHandleEventValidateCredentialsAsync ( BasicCredentials credentials )
153- {
160+ {
154161 var validateCredentialsContext = new BasicValidateCredentialsContext ( Context , Scheme , Options , credentials . Username , credentials . Password ) ;
155162 await Events . ValidateCredentialsAsync ( validateCredentialsContext ) . ConfigureAwait ( false ) ;
156163
@@ -170,7 +177,7 @@ private async Task<AuthenticateResult> RaiseAndHandleEventValidateCredentialsAsy
170177 }
171178
172179 private async Task < AuthenticateResult > RaiseAndHandleAuthenticationSucceededAsync ( BasicCredentials credentials )
173- {
180+ {
174181 // ..create claims principal.
175182 var principal = BasicUtils . BuildClaimsPrincipal ( credentials . Username , Scheme . Name , ClaimsIssuer ) ;
176183
@@ -194,8 +201,18 @@ private async Task<AuthenticateResult> RaiseAndHandleAuthenticationSucceededAsyn
194201 return AuthenticateResult . Fail ( "No authenticated prinicipal set." ) ;
195202 }
196203
204+ private bool IgnoreAuthenticationIfAllowAnonymous ( )
205+ {
206+ #if ( NET461 || NETSTANDARD2_0 )
207+ return false ;
208+ #else
209+ return Options . IgnoreAuthenticationIfAllowAnonymous
210+ && Context . GetEndpoint ( ) ? . Metadata ? . GetMetadata < Microsoft . AspNetCore . Authorization . IAllowAnonymous > ( ) != null ;
211+ #endif
212+ }
213+
197214 private async Task < bool > ValidateUsingBasicUserValidationServiceAsync ( string username , string password )
198- {
215+ {
199216 IBasicUserValidationService basicUserValidationService = null ;
200217 if ( Options . BasicUserValidationServiceType != null )
201218 {
@@ -221,7 +238,7 @@ private async Task<bool> ValidateUsingBasicUserValidationServiceAsync(string use
221238 }
222239
223240 private BasicCredentials DecodeBasicCredentials ( string credentials )
224- {
241+ {
225242 string username ;
226243 string password ;
227244 try
@@ -245,25 +262,25 @@ private BasicCredentials DecodeBasicCredentials(string credentials)
245262 {
246263 throw new Exception ( "Username cannot be empty." ) ;
247264 }
248-
265+
249266 if ( password == null )
250267 {
251268 password = string . Empty ;
252269 }
253-
270+
254271 return new BasicCredentials ( username , password ) ;
255272 }
256273
257274 private struct BasicCredentials
258- {
259- public BasicCredentials ( string username , string password )
260- {
261- Username = username ;
262- Password = password ;
263- }
264-
265- public string Username { get ; }
266- public string Password { get ; }
267- }
275+ {
276+ public BasicCredentials ( string username , string password )
277+ {
278+ Username = username ;
279+ Password = password ;
280+ }
281+
282+ public string Username { get ; }
283+ public string Password { get ; }
284+ }
268285 }
269286}
0 commit comments