Skip to content

Commit

Permalink
Claim based instead of role
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-barry-gmo authored and jabbera committed Jan 3, 2019
1 parent 4f75d86 commit 0eeb95a
Show file tree
Hide file tree
Showing 21 changed files with 160 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace AspNetCore.Testing.Site.Controllers
namespace AspNetCore.Testing.Authentication.ClaimInjector.Site.Controllers
{
[Route("api/[controller]")]
[ApiController]
Expand All @@ -27,5 +27,9 @@ public class ValuesController : ControllerBase

[HttpGet("[action]")]
public ActionResult<string> ReturnsName() => HttpContext.User.Identity.Name;

[HttpGet("[action]/{claimType}")]
public ActionResult<string> ReturnsCustomClaim(string claimType) =>
HttpContext.User.Claims.FirstOrDefault(x => x.Type == claimType)?.Value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace AspNetCore.Testing.Site
namespace AspNetCore.Testing.Authentication.ClaimInjector.Site
{
public class Program
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace AspNetCore.Testing.Site
namespace AspNetCore.Testing.Authentication.ClaimInjector.Site
{
public class Startup
{
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>AspNetCore.Testing.RoleHandler.Test</RootNamespace>
<RootNamespace>AspNetCore.Testing.Authentication.ClaimInjector.Test</RootNamespace>

<PreserveCompilationContext>true</PreserveCompilationContext>
<IsPackable>false</IsPackable>
Expand All @@ -23,8 +23,8 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AspNetCore.Testing.Site\AspNetCore.Testing.Site.csproj" />
<ProjectReference Include="..\AspNetCore.Testing.RoleHandler\AspNetCore.Testing.RoleHandler.csproj" />
<ProjectReference Include="..\AspNetCore.Testing.Authentication.ClaimInjector.Site\AspNetCore.Testing.Authentication.ClaimInjector.Site.csproj" />
<ProjectReference Include="..\AspNetCore.Testing.Authentication.ClaimInjector\AspNetCore.Testing.Authentication.ClaimInjector.csproj" />
</ItemGroup>

<Target Name="CopyAditionalFiles" AfterTargets="Build">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
using System;
using System.Net;
using System.Threading.Tasks;
using AspNetCore.Testing.RoleHandler;
using AspNetCore.Testing.Site;
using AspNetCore.Testing.Authentication.ClaimInjector;
using AspNetCore.Testing.Authentication.ClaimInjector.Site;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.IdentityModel.Tokens;
using Xunit;

namespace role_handler_test
namespace AspNetCore.Testing.Authentication.ClaimInjector.Test
{
public class UnitTests : IClassFixture<CustomRoleWebApplicationFactory<Startup>>
public class UnitTests : IClassFixture<ClaimInjectorWebApplicationFactory<Startup>>
{
private readonly CustomRoleWebApplicationFactory<Startup> _factory;
private readonly ClaimInjectorWebApplicationFactory<Startup> _factory;

public UnitTests(CustomRoleWebApplicationFactory<Startup> factory)
public UnitTests(ClaimInjectorWebApplicationFactory<Startup> factory)
{
this._factory = factory;
this._factory.RoleConfig.Reset();
Expand Down Expand Up @@ -83,6 +83,25 @@ public async Task NameIsInHttpContextTest()
Assert.Equal(expectedName, actual);
}

[Fact]
public async Task CustomClaimsWorkTest()
{
string expectedValue = "Hello World";
string expectedClaimType = "CustomClaimType";

this._factory.RoleConfig.AddClaim(expectedClaimType, expectedValue);

var client = _factory.CreateClient();

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

response.EnsureSuccessStatusCode();

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

Assert.Equal(expectedValue, actual);
}

[Fact]
public void NullNameThrowsTest() => Assert.Throws<ArgumentNullException>(() => _factory.RoleConfig.Name = null);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>AspNetCore.Testing.Authentication.ClaimInjector</RootNamespace>
<IsPackable>True</IsPackable>
<Authors>jabbera</Authors>
<PackageDescription>Easy testing of role based authentication during integration testing for ASP.NET core applications.</PackageDescription>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/jabbera/aspnetcore-testing-role-handler</PackageProjectUrl>
<PackageIconUrl></PackageIconUrl>
<PackageTags>aspnetcore;aspnetcoremvc;aspnetcoremvctesting;role;authentication;jwt;bearer</PackageTags>

<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />

<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All"/>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
using Microsoft.Extensions.Options;
using Newtonsoft.Json;

namespace AspNetCore.Testing.RoleHandler
namespace AspNetCore.Testing.Authentication.ClaimInjector
{
public class CustomRoleHandler : AuthenticationHandler<CustomRoleHandlerOptions>
public class ClaimInjectorHandler : AuthenticationHandler<ClaimInjectorHandlerOptions>
{
public const string AuthenticationScheme = "Bypass";

public CustomRoleHandler(IOptionsMonitor<CustomRoleHandlerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
public ClaimInjectorHandler(IOptionsMonitor<ClaimInjectorHandlerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
Expand All @@ -31,11 +31,9 @@ protected override Task<AuthenticateResult> HandleAuthenticateAsync()
string base64Json = this.Request.Headers["Authorization"].ToString().Replace(AuthenticationScheme, "").Trim();
string json = Encoding.UTF8.GetString(Convert.FromBase64String(base64Json));

var customRoleHandlerHeaderConfig = JsonConvert.DeserializeObject<CustomRoleHandlerHeaderConfig>(json);
Claim name = new Claim(ClaimTypes.Name, customRoleHandlerHeaderConfig.Name);
IEnumerable<Claim> roles = customRoleHandlerHeaderConfig.Roles.Select(x => new Claim(ClaimTypes.Role, x));
var claimInjectorHandlerHeaderConfig = JsonConvert.DeserializeObject<ClaimInjectorHandlerHeaderConfig>(json);

ClaimsIdentity identity = new ClaimsIdentity(roles.Append(name), AuthenticationScheme);
ClaimsIdentity identity = new ClaimsIdentity(claimInjectorHandlerHeaderConfig.Claims, AuthenticationScheme);
return Task.FromResult(
AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(identity), AuthenticationScheme)));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using Newtonsoft.Json;

namespace AspNetCore.Testing.Authentication.ClaimInjector
{
public class ClaimInjectorHandlerHeaderConfig
{
[JsonProperty] private Dictionary<string, List<string>> _claims = new Dictionary<string, List<string>>();

public ClaimInjectorHandlerHeaderConfig() => Reset();

[JsonProperty]
public bool AnonymousRequest { get; set; }

public string Name
{
set
{
if (value == null) throw new ArgumentNullException(nameof(value));

_claims.Remove(ClaimTypes.Name);

_claims.Add(ClaimTypes.Name, new List<string> {value});
}
}

public string[] Roles
{
set
{
if (value == null || value.Any(x => x == null)) {
throw new ArgumentNullException(nameof(value));
}

_claims.Remove(ClaimTypes.Role);

foreach(var role in value) {
AddClaim(ClaimTypes.Role, role);
}
}
}

public void AddClaim(string claimType, string value)
{
if (!this._claims.TryGetValue(claimType, out var values))
{
values = new List<string>();
this._claims.Add(claimType, values);
}

values.Add(value);
}

public void AddClaim(Claim claim) => AddClaim(claim.Type, claim.Value);

internal IEnumerable<Claim> Claims => _claims.SelectMany(x => x.Value.Select(y => new Claim(x.Key, y)));

public void Reset()
{
this._claims.Clear();
this.AnonymousRequest = false;
this.Name = "Authenticated User";
this.Roles = new string[0];
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.AspNetCore.Authentication;

namespace AspNetCore.Testing.Authentication.ClaimInjector
{
public class ClaimInjectorHandlerOptions : AuthenticationSchemeOptions
{

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;

namespace AspNetCore.Testing.RoleHandler
namespace AspNetCore.Testing.Authentication.ClaimInjector
{
public class CustomRoleWebApplicationFactory<T> : WebApplicationFactory<T> where T : class
public class ClaimInjectorWebApplicationFactory<T> : WebApplicationFactory<T> where T : class
{
public CustomRoleHandlerHeaderConfig RoleConfig { get; } = new CustomRoleHandlerHeaderConfig();
public ClaimInjectorHandlerHeaderConfig RoleConfig { get; } = new ClaimInjectorHandlerHeaderConfig();

protected override void ConfigureClient(HttpClient client)
{
Expand All @@ -37,8 +37,8 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)

builder.ConfigureTestServices(services =>
{
services.AddAuthentication(x => x.DefaultScheme = CustomRoleHandler.AuthenticationScheme)
.AddScheme<CustomRoleHandlerOptions, CustomRoleHandler>(CustomRoleHandler.AuthenticationScheme,
services.AddAuthentication(x => x.DefaultScheme = ClaimInjectorHandler.AuthenticationScheme)
.AddScheme<ClaimInjectorHandlerOptions, ClaimInjectorHandler>(ClaimInjectorHandler.AuthenticationScheme,
x => { });
});
}
Expand Down

This file was deleted.

44 changes: 0 additions & 44 deletions AspNetCore.Testing.RoleHandler/CustomRoleHandlerHeaderConfig.cs

This file was deleted.

9 changes: 0 additions & 9 deletions AspNetCore.Testing.RoleHandler/CustomRoleHandlerOptions.cs

This file was deleted.

6 changes: 3 additions & 3 deletions aspnetcore-testing-role-handler.sln → ClaimInjector.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Testing.RoleHandler", "AspNetCore.Testing.RoleHandler\AspNetCore.Testing.RoleHandler.csproj", "{D6034548-71E2-42D4-9907-229DBF026B2A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Testing.Authentication.ClaimInjector", "AspNetCore.Testing.Authentication.ClaimInjector\AspNetCore.Testing.Authentication.ClaimInjector.csproj", "{D6034548-71E2-42D4-9907-229DBF026B2A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Testing.RoleHandler.Test", "AspNetCore.Testing.RoleHandler.Test\AspNetCore.Testing.RoleHandler.Test.csproj", "{A12FD240-CF0C-4784-ADB9-60E7E5FCBCBA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Testing.Authentication.ClaimInjector.Test", "AspNetCore.Testing.Authentication.ClaimInjector.Test\AspNetCore.Testing.Authentication.ClaimInjector.Test.csproj", "{A12FD240-CF0C-4784-ADB9-60E7E5FCBCBA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Testing.Site", "AspNetCore.Testing.Site\AspNetCore.Testing.Site.csproj", "{99D27BB3-ED44-4779-AE5F-FAC0830E9519}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.Testing.Authentication.ClaimInjector.Site", "AspNetCore.Testing.Authentication.ClaimInjector.Site\AspNetCore.Testing.Authentication.ClaimInjector.Site.csproj", "{99D27BB3-ED44-4779-AE5F-FAC0830E9519}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
5 changes: 5 additions & 0 deletions Directory.build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# AspNetCore.Testing.RoleHandler
# AspNetCore.Testing.Authentication.ClaimInjector

Excercising claim based logic using Microsoft.AspNetCore.Mvc.Testing is now as simple as:

Expand Down
2 changes: 1 addition & 1 deletion build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ steps:
inputs:
command: 'pack'
configuration: 'release'
packagesToPack: '**/AspNetCore.Testing.RoleHandler.csproj'
packagesToPack: '**/AspNetCore.Testing.Authentication.ClaimInjector.csproj'
nobuild: true

- task: PublishCodeCoverageResults@1
Expand Down

0 comments on commit 0eeb95a

Please sign in to comment.