Skip to content
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

Add options for custom name and role claim types #26

Open
wants to merge 1 commit into
base: master
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Linq;

namespace AspNetCore.Testing.Authentication.ClaimInjector.Site.Controllers
{
Expand All @@ -28,6 +25,9 @@ public class ValuesController : ControllerBase
[HttpGet("[action]")]
public ActionResult<string> ReturnsName() => HttpContext.User.Identity.Name;

[HttpGet("[action]/{role}")]
public ActionResult<bool> ReturnsIsInRole(string role) => HttpContext.User.IsInRole(role);

[HttpGet("[action]/{claimType}")]
public ActionResult<string> ReturnsCustomClaim(string claimType) =>
HttpContext.User.Claims.FirstOrDefault(x => x.Type == claimType)?.Value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using AspNetCore.Testing.Authentication.ClaimInjector.Site;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Xunit;

namespace AspNetCore.Testing.Authentication.ClaimInjector.Test
{
public class CustomClaimTypesUnitTests : IClassFixture<ClaimInjectorWebApplicationFactory<Startup>>
{
private readonly ClaimInjectorWebApplicationFactory<Startup> _factory;
private const string _nameClaimType = "CustomNameClaimType";
private const string _roleClaimType = "CustomRoleClaimType";

public CustomClaimTypesUnitTests(ClaimInjectorWebApplicationFactory<Startup> factory)
{
_factory = factory;
_factory.NameClaimType = _nameClaimType;
_factory.RoleClaimType = _roleClaimType;
_factory.RoleConfig.Reset();
}

/// <summary>
/// Make an authenticated call with a custom claim and ensure it's accessible.
/// </summary>
/// <returns></returns>
[Fact]
public async Task NameIsInHttpContextWhenCustomClaimTypeIsUsedTest()
{
var expectedValue = "John Doe";

_factory.RoleConfig.AddClaim(new Claim(_nameClaimType, expectedValue));

var client = _factory.CreateClient();

var response = await client.GetAsync($"api/Values/ReturnsName");

response.EnsureSuccessStatusCode();

var actual = await response.Content.ReadAsStringAsync();

Assert.Equal(expectedValue, actual);
}

/// <summary>
/// Make an authenticated call with a custom claim and ensure it's accessible.
/// </summary>
/// <returns></returns>
[Fact]
public async Task RoleIsInHttpContextWhenCustomClaimTypeIsUsedTest()
{
var expectedValue = "Reader";

_factory.RoleConfig.AddClaim(new Claim(_roleClaimType, expectedValue));

var client = _factory.CreateClient();

var response = await client.GetAsync($"api/Values/ReturnsIsInRole/{expectedValue}");

response.EnsureSuccessStatusCode();

var actual = await response.Content.ReadAsAsync<bool>();

Assert.True(actual);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;

namespace AspNetCore.Testing.Authentication.ClaimInjector
{
Expand All @@ -21,24 +21,25 @@ internal class ClaimInjectorHandler : AuthenticationHandler<ClaimInjectorHandler
/// <param name="logger"></param>
/// <param name="encoder"></param>
/// <param name="clock"></param>
public ClaimInjectorHandler(IOptionsMonitor<ClaimInjectorHandlerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
public ClaimInjectorHandler(IOptionsMonitor<ClaimInjectorHandlerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}

protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!this.Request.Headers.ContainsKey("Authorization"))
if (!Request.Headers.ContainsKey("Authorization"))
{
return Task.FromResult(AuthenticateResult.Fail("No authentication header"));
}

string base64Json = this.Request.Headers["Authorization"].ToString().Replace(AuthenticationScheme, "").Trim();
string base64Json = Request.Headers["Authorization"].ToString().Replace(AuthenticationScheme, "").Trim();
string json = Encoding.UTF8.GetString(Convert.FromBase64String(base64Json));

var claimInjectorHandlerHeaderConfig = JsonConvert.DeserializeObject<ClaimInjectorHandlerHeaderConfig>(json);

ClaimsIdentity identity = new ClaimsIdentity(claimInjectorHandlerHeaderConfig.Claims, AuthenticationScheme);
var identity = new ClaimsIdentity(claimInjectorHandlerHeaderConfig.Claims, AuthenticationScheme,
Options.NameClaimType, Options.RoleClaimType);
return Task.FromResult(
AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(identity), AuthenticationScheme)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ namespace AspNetCore.Testing.Authentication.ClaimInjector
{
internal class ClaimInjectorHandlerOptions : AuthenticationSchemeOptions
{
public string RoleClaimType { get; set; }

public string NameClaimType { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;

namespace AspNetCore.Testing.Authentication.ClaimInjector
{
Expand All @@ -25,6 +25,10 @@ public class ClaimInjectorWebApplicationFactory<T> : WebApplicationFactory<T> wh
/// </summary>
public ClaimInjectorHandlerHeaderConfig RoleConfig { get; } = new ClaimInjectorHandlerHeaderConfig();

public string RoleClaimType { get; set; } = ClaimTypes.Role;

public string NameClaimType { get; set; } = ClaimTypes.Name;

protected override void ConfigureClient(HttpClient client)
{
base.ConfigureClient(client);
Expand Down Expand Up @@ -54,7 +58,11 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
x.DefaultChallengeScheme = ClaimInjectorHandler.AuthenticationScheme;
})
.AddScheme<ClaimInjectorHandlerOptions, ClaimInjectorHandler>(ClaimInjectorHandler.AuthenticationScheme,
x => { });
x =>
{
x.RoleClaimType = RoleClaimType;
x.NameClaimType = NameClaimType;
});
});
}
}
Expand Down