Skip to content

#146 Update Basic Auth handler and Options to enable overriding SuppressWWWAuthenticateHeader #147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 28 additions & 17 deletions src/idunno.Authentication.Basic/BasicAuthenticationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Text.Encodings.Web;
using System.Text;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
Expand All @@ -27,7 +26,8 @@ internal class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthentic
#pragma warning restore IDE0090
#pragma warning restore IDE0079

private readonly Encoding _iso88591ValidatingEncoding = Encoding.GetEncoding("ISO-8859-1",new EncoderExceptionFallback(), new DecoderExceptionFallback());
private readonly Encoding _iso88591ValidatingEncoding =
Encoding.GetEncoding("ISO-8859-1", new EncoderExceptionFallback(), new DecoderExceptionFallback());

#if NET8_0_OR_GREATER
public BasicAuthenticationHandler(
Expand All @@ -41,9 +41,9 @@ public BasicAuthenticationHandler(
#endif
public BasicAuthenticationHandler(
IOptionsMonitor<BasicAuthenticationOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) : base(options, logger, encoder, clock)
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock) : base(options, logger, encoder, clock)
{
}

Expand Down Expand Up @@ -131,7 +131,8 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
}
catch (Exception ex)
{
const string failedToDecodeCredentials = "Cannot build credentials from decoded base64 value, exception {ex.Message} encountered.";
const string failedToDecodeCredentials =
"Cannot build credentials from decoded base64 value, exception {ex.Message} encountered.";
Logger.LogInformation(failedToDecodeCredentials, ex.Message);
return AuthenticateResult.Fail(ex.Message);
}
Expand All @@ -148,10 +149,10 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
var password = decodedCredentials.Substring(delimiterIndex + 1);

var validateCredentialsContext = new ValidateCredentialsContext(Context, Scheme, Options)
{
Username = username,
Password = password
};
{
Username = username,
Password = password
};

await Events.ValidateCredentials(validateCredentialsContext);

Expand All @@ -162,7 +163,7 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
return AuthenticateResult.Success(ticket);
}

if (validateCredentialsContext.Result != null &&
if (validateCredentialsContext.Result != null &&
validateCredentialsContext.Result.Failure != null)
{
return AuthenticateResult.Fail(validateCredentialsContext.Result.Failure);
Expand All @@ -173,9 +174,9 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
catch (Exception ex)
{
var authenticationFailedContext = new BasicAuthenticationFailedContext(Context, Scheme, Options)
{
Exception = ex
};
{
Exception = ex
};

await Events.AuthenticationFailed(authenticationFailedContext).ConfigureAwait(true);

Expand All @@ -202,7 +203,17 @@ protected override Task HandleChallengeAsync(AuthenticationProperties properties
else
{
Response.StatusCode = 401;
if (!Options.SuppressWWWAuthenticateHeader)

var suppressWWWAuthenticateHeader = Options.SuppressWWWAuthenticateHeader;

if (Options.SuppressWWWAuthenticateHeaderPathOverride.Any(x => Request.Path.StartsWithSegments(x,
StringComparison
.InvariantCultureIgnoreCase)))
{
suppressWWWAuthenticateHeader = !suppressWWWAuthenticateHeader;
}

if (!suppressWWWAuthenticateHeader)
{
var headerValue = _Scheme + $" realm=\"{Options.Realm}\"";
if (Options.AdvertiseEncodingPreference)
Expand All @@ -211,16 +222,16 @@ protected override Task HandleChallengeAsync(AuthenticationProperties properties
{
case EncodingPreference.Utf8:
case EncodingPreference.PreferUtf8:
headerValue+= ", charset=\"UTF-8\"";
headerValue += ", charset=\"UTF-8\"";
break;
case EncodingPreference.Latin1:
headerValue += ", charset=\"ISO-8859-1\"";
break;
default:
break;

}
}

Response.Headers.Append(HeaderNames.WWWAuthenticate, headerValue);
}
}
Expand Down
22 changes: 17 additions & 5 deletions src/idunno.Authentication.Basic/BasicAuthenticationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ public BasicAuthenticationOptions()
/// </remarks>
public string Realm
{
get
{
return _realm;
}
get { return _realm; }

set
{
Expand All @@ -64,6 +61,21 @@ public string Realm
/// </remarks>
public bool SuppressWWWAuthenticateHeader { get; set; } = false;


/// <summary>
/// Reverses the SuppressWWWAuthenticateHeader for specific paths.
/// </summary>
/// /// <remarks>
/// The authentication scheme controls the browser UI and allows the browser to
/// authenticate in the correct manner, popping up a UI to allow for user name and password.
/// Some users may want to suppress this behaviour for JavaScript XMLHttpRequest requests while
/// also having www.example.com/libraryUi use basic auth while returning the WWW-Authenticate header to force a browser login prompt.
/// The switch happens based on Path StartsWith.
/// If SuppressWWWAuthenticateHeader is set to false, any path here will set the value to true.
/// If SuppressWWWAuthenticateHeader is set to true, any path here will set the value to false.
/// </remarks>
public string[] SuppressWWWAuthenticateHeaderPathOverride { get; set; } = new string[0];

/// <summary>
/// Gets or sets a flag indicating if the handler will prompt for authentication on HTTP requests.
/// </summary>
Expand Down Expand Up @@ -116,4 +128,4 @@ private static bool IsAscii(string input)
return true;
}
}
}
}
Loading