Skip to content

Commit

Permalink
Upgrade for ASP Core 2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
msmolka committed Aug 29, 2017
1 parent 7703a38 commit 6611a6d
Show file tree
Hide file tree
Showing 14 changed files with 280 additions and 367 deletions.
73 changes: 38 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,59 +19,62 @@ When you install the package, it should be added to your `.csproj`. Alternativel

```xml
<ItemGroup>
<PackageReference Include="ZNetCS.AspNetCore.Authentication.Basic" Version="1.0.0" />
<PackageReference Include="ZNetCS.AspNetCore.Authentication.Basic" Version="2.0.0" />
</ItemGroup>
```

In order to use the basic authentication middleware, you must configure the services in the `Configure` call of `Startup`. Because basic
In order to use the basic authentication middleware, you must configure the services in the `Configure` and `ConfigureServices` call of `Startup`. Because basic
authentication is manual process handled on each request, there is need to validate credentials manually (see below).

```csharp
using ZNetCS.AspNetCore.Authentication.Basic.DependencyInjection;
using ZNetCS.AspNetCore.Authentication.Basic;
using ZNetCS.AspNetCore.Authentication.Basic.Events;
```

```
...
```

```csharp

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var options = new BasicAuthenticationOptions
{
Realm = "My Application",
Events = new BasicAuthenticationEvents
{
OnValidatePrincipal = context =>

// default authentication initilaization
app.UseAuthentication();

// other middleware e.g. MVC etc
}

public void ConfigureServices(IServiceCollection services)
{
services
.AddAuthentication(BasicAuthenticationDefaults.AuthenticationScheme)
.AddBasicAuthentication(
options =>
{
// here validation comes
if ((context.UserName == "userName") && (context.Password == "password"))
options.Realm = "My Application";
options.Events = new BasicAuthenticationEvents
{
var claims = new List<Claim>
OnValidatePrincipal = context =>
{
new Claim(ClaimTypes.Name, context.UserName, context.Options.ClaimsIssuer)
};

var ticket = new AuthenticationTicket(
new ClaimsPrincipal(
new ClaimsIdentity(claims, context.Options.AuthenticationScheme)),
new AuthenticationProperties(),
context.Options.AuthenticationScheme);

// return success result with ticket
return Task.FromResult(AuthenticateResult.Success(ticket));
}

// return failed result
return Task.FromResult(AuthenticateResult.Fail("Authentication failed."));
}
}
};

app.UseBasicAuthentication(options);

// other middleware e.g. MVC etc
if ((context.UserName == "userName") && (context.Password == "password"))
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, context.UserName, context.Options.ClaimsIssuer)
};

var ticket = new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity(claims, BasicAuthenticationDefaults.AuthenticationScheme)),
new Microsoft.AspNetCore.Authentication.AuthenticationProperties(),
BasicAuthenticationDefaults.AuthenticationScheme);

return Task.FromResult(AuthenticateResult.Success(ticket));
}

return Task.FromResult(AuthenticateResult.Fail("Authentication failed."));
};
});
}
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BasicAuthenticationExtensions.cs" company="Marcin Smółka zNET Computer Solutions">
// Copyright (c) Marcin Smółka zNET Computer Solutions. All rights reserved.
// </copyright>
// <summary>
// The basic authentication extensions.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ZNetCS.AspNetCore.Authentication.Basic
{
#region Usings

using System;

using Microsoft.AspNetCore.Authentication;

#endregion

/// <summary>
/// The basic authentication extensions.
/// </summary>
public static class BasicAuthenticationExtensions
{
#region Public Methods

/// <summary>
/// Adds basic authentication.
/// </summary>
/// <param name="builder">
/// The authentication builder.
/// </param>
public static AuthenticationBuilder AddBasicAuthentication(this AuthenticationBuilder builder)
{
return builder.AddBasicAuthentication(BasicAuthenticationDefaults.AuthenticationScheme);
}

/// <summary>
/// Adds basic authentication.
/// </summary>
/// <param name="builder">
/// The authentication builder.
/// </param>
/// <param name="authenticationScheme">
/// The authentication scheme.
/// </param>
public static AuthenticationBuilder AddBasicAuthentication(this AuthenticationBuilder builder, string authenticationScheme)
{
return builder.AddBasicAuthentication(authenticationScheme, null);
}

/// <summary>
/// Adds basic authentication.
/// </summary>
/// <param name="builder">
/// The authentication builder.
/// </param>
/// <param name="configureOptions">
/// The configure options.
/// </param>
public static AuthenticationBuilder AddBasicAuthentication(this AuthenticationBuilder builder, Action<BasicAuthenticationOptions> configureOptions)
{
return builder.AddBasicAuthentication(BasicAuthenticationDefaults.AuthenticationScheme, configureOptions);
}

/// <summary>
/// Adds basic authentication.
/// </summary>
/// <param name="builder">
/// The builder.
/// </param>
/// <param name="authenticationScheme">
/// The authentication scheme.
/// </param>
/// <param name="configureOptions">
/// The configure options.
/// </param>
public static AuthenticationBuilder AddBasicAuthentication(
this AuthenticationBuilder builder,
string authenticationScheme,
Action<BasicAuthenticationOptions> configureOptions)
{
return builder.AddScheme<BasicAuthenticationOptions, BasicAuthenticationHandler>(authenticationScheme, configureOptions);
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ namespace ZNetCS.AspNetCore.Authentication.Basic
using System;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;

using ZNetCS.AspNetCore.Authentication.Basic.Events;
Expand All @@ -41,14 +42,45 @@ namespace ZNetCS.AspNetCore.Authentication.Basic
/// </remarks>
public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
#region Constants

/// <summary>
/// The scheme name is "Basic".
/// </summary>
private const string Scheme = "Basic";
private const string Basic = "Basic";

#endregion

#region Constructors and Destructors

/// <summary>
/// Initializes a new instance of the <see cref="BasicAuthenticationHandler"/> class.
/// </summary>
/// <param name="options">
/// The options.
/// </param>
/// <param name="logger">
/// The logger.
/// </param>
/// <param name="encoder">
/// The encoder.
/// </param>
/// <param name="clock">
/// The clock.
/// </param>
public BasicAuthenticationHandler(IOptionsMonitor<BasicAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(
options,
logger,
encoder,
clock)
{
}

#endregion

#region Methods

/// <inheritdoc />
/// <inheritdoc/>
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
// RFC 7230 section 3.2.2
Expand All @@ -58,19 +90,19 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
if ((authorizationHeaderValues == null) || (authorizationHeaderValues.Length == 0))
{
this.Logger.LogDebug("'Authorization' header is not present in the request.");
return AuthenticateResult.Skip();
return AuthenticateResult.NoResult();
}

var basicAuthorizationHeader = authorizationHeaderValues.FirstOrDefault(s => s.StartsWith(Scheme + ' ', StringComparison.OrdinalIgnoreCase));
string basicAuthorizationHeader = authorizationHeaderValues.FirstOrDefault(s => s.StartsWith(Basic + ' ', StringComparison.OrdinalIgnoreCase));

// Authorization header is not 'Basic' so there is nothing to do by this middleware
if (string.IsNullOrEmpty(basicAuthorizationHeader))
{
this.Logger.LogDebug("'Authorization' header is not in 'Basic' scheme in the request.");
return AuthenticateResult.Skip();
return AuthenticateResult.NoResult();
}

var credentials = basicAuthorizationHeader.Replace($"{Scheme} ", string.Empty).Trim();
string credentials = basicAuthorizationHeader.Replace($"{Basic} ", string.Empty).Trim();

if (string.IsNullOrEmpty(credentials))
{
Expand All @@ -95,35 +127,21 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
return AuthenticateResult.Fail("The credentials delimiter is not present in 'Basic' scheme.");
}

var userName = decodedCredentials.Substring(0, delimiterIndex);
var password = decodedCredentials.Substring(delimiterIndex + 1);
string userName = decodedCredentials.Substring(0, delimiterIndex);
string password = decodedCredentials.Substring(delimiterIndex + 1);

var context = new ValidatePrincipalContext(this.Context, this.Options, userName, password);
var context = new ValidatePrincipalContext(this.Context, this.Scheme, this.Options, userName, password);
return await this.Options.Events.ValidatePrincipal(context);
}

/// <inheritdoc />
protected override Task HandleSignInAsync(SignInContext context)
{
// Basic authentication have to be resolved on every request.
throw new NotSupportedException();
}

/// <inheritdoc />
protected override Task HandleSignOutAsync(SignOutContext context)
{
// Basic authentication have to be resolved on every request.
throw new NotSupportedException();
}

/// <inheritdoc />
protected override Task<bool> HandleUnauthorizedAsync(ChallengeContext context)
/// <inheritdoc/>
protected override Task HandleChallengeAsync(AuthenticationProperties context)
{
var realmHeader = new NameValueHeaderValue("realm", $"\"{this.Options.Realm}\"");
this.Response.StatusCode = StatusCodes.Status401Unauthorized;
this.Response.Headers.Append(HeaderNames.WWWAuthenticate, $"{Scheme} {realmHeader}");
this.Response.Headers.Append(HeaderNames.WWWAuthenticate, $"{Basic} {realmHeader}");

return Task.FromResult(true);
return Task.CompletedTask;
}

#endregion
Expand Down

This file was deleted.

Loading

0 comments on commit 6611a6d

Please sign in to comment.