Skip to content
Browse files

Merge pull request #682 from somedave/master

Adds Support For Any Specified Claim
  • Loading branch information...
2 parents 9a52cd6 + c94f096 commit 63b7a9c878681993334a603877cbce89bae774fe @thecodejunkie thecodejunkie committed Oct 3, 2012
Showing with 108 additions and 1 deletion.
  1. +76 −0 src/Nancy.Tests/Unit/Security/ModuleSecurityFixture.cs
  2. +32 −1 src/Nancy/Security/ModuleSecurity.cs
View
76 src/Nancy.Tests/Unit/Security/ModuleSecurityFixture.cs
@@ -117,6 +117,34 @@ public void Should_return_unauthorized_response_with_RequiresClaims_enabled_and_
}
[Fact]
+ public void Should_return_unauthorized_response_with_RequiresAnyClaim_enabled_and_no_username()
+ {
+ var module = new FakeHookedModule(new BeforePipeline());
+ module.RequiresAnyClaim(new[] { string.Empty });
+
+ var result = module.Before.Invoke(new NancyContext());
+
+ result.ShouldNotBeNull();
+ result.StatusCode.ShouldEqual(HttpStatusCode.Unauthorized);
+ }
+
+ [Fact]
+ public void Should_return_unauthorized_response_with_RequiresAnyClaim_enabled_and_blank_username()
+ {
+ var module = new FakeHookedModule(new BeforePipeline());
+ module.RequiresAnyClaim(new[] { string.Empty });
+ var context = new NancyContext
+ {
+ CurrentUser = GetFakeUser(String.Empty)
+ };
+
+ var result = module.Before.Invoke(context);
+
+ result.ShouldNotBeNull();
+ result.StatusCode.ShouldEqual(HttpStatusCode.Unauthorized);
+ }
+
+ [Fact]
public void Should_return_unauthorized_response_with_RequiresValidatedClaims_enabled_and_no_username()
{
var module = new FakeHookedModule(new BeforePipeline());
@@ -207,6 +235,54 @@ public void Should_return_null_with_RequiresClaims_and_all_claims_met()
result.ShouldBeNull();
}
+
+ [Fact]
+ public void Should_return_forbidden_response_with_RequiresAnyClaim_enabled_but_nonmatching_claims()
+ {
+ var module = new FakeHookedModule(new BeforePipeline());
+ module.RequiresAnyClaim(new[] { "Claim1" });
+ var context = new NancyContext
+ {
+ CurrentUser = GetFakeUser("username", new string[] { "Claim2", "Claim3" })
+ };
+
+ var result = module.Before.Invoke(context);
+
+ result.ShouldNotBeNull();
+ result.StatusCode.ShouldEqual(HttpStatusCode.Forbidden);
+ }
+
+ [Fact]
+ public void Should_return_forbidden_response_with_RequiresAnyClaim_enabled_but_claims_key_missing()
+ {
+ var module = new FakeHookedModule(new BeforePipeline());
+ module.RequiresAnyClaim(new[] { "Claim1" });
+ var context = new NancyContext
+ {
+ CurrentUser = GetFakeUser("username")
+ };
+
+ var result = module.Before.Invoke(context);
+
+ result.ShouldNotBeNull();
+ result.StatusCode.ShouldEqual(HttpStatusCode.Forbidden);
+ }
+
+ [Fact]
+ public void Should_return_null_with_RequiresAnyClaim_and_any_claim_met()
+ {
+ var module = new FakeHookedModule(new BeforePipeline());
+ module.RequiresAnyClaim(new[] { "Claim1", "Claim4" });
+ var context = new NancyContext
+ {
+ CurrentUser = GetFakeUser("username", new[] { "Claim1", "Claim2", "Claim3" })
+ };
+
+ var result = module.Before.Invoke(context);
+
+ result.ShouldBeNull();
+ }
+
[Fact]
public void Should_return_forbidden_response_with_RequiresValidatedClaims_enabled_but_claims_missing()
{
View
33 src/Nancy/Security/ModuleSecurity.cs
@@ -31,6 +31,17 @@ public static void RequiresClaims(this NancyModule module, IEnumerable<string> r
}
/// <summary>
+ /// This module requires authentication and any one of certain claims to be present.
+ /// </summary>
+ /// <param name="module">Module to enable</param>
+ /// <param name="requiredClaims">Claim(s) required</param>
+ public static void RequiresAnyClaim(this NancyModule module, IEnumerable<string> requiredClaims)
+ {
+ module.Before.AddItemToEndOfPipeline(RequiresAuthentication);
+ module.Before.AddItemToEndOfPipeline(RequiresAnyClaim(requiredClaims));
+ }
+
+ /// <summary>
/// This module requires claims to be validated
/// </summary>
/// <param name="module">Module to enable</param>
@@ -99,6 +110,27 @@ private static Response RequiresAuthentication(NancyContext context)
}
/// <summary>
+ /// Gets a request hook for checking claims
+ /// </summary>
+ /// <param name="claims">Required claims</param>
+ /// <returns>Before hook delegate</returns>
+ private static Func<NancyContext, Response> RequiresAnyClaim(IEnumerable<string> claims)
+ {
+ return (ctx) =>
+ {
+ Response response = null;
+ if (ctx.CurrentUser == null
+ || ctx.CurrentUser.Claims == null
+ || !claims.Any(c => ctx.CurrentUser.Claims.Contains(c)))
+ {
+ response = new Response { StatusCode = HttpStatusCode.Forbidden };
+ }
+
+ return response;
+ };
+ }
+
+ /// <summary>
/// Gets a pipeline item for validating user claims
/// </summary>
/// <param name="isValid">Is valid delegate</param>
@@ -108,7 +140,6 @@ private static Response RequiresAuthentication(NancyContext context)
return (ctx) =>
{
Response response = null;
- var userClaims = ctx.CurrentUser.Claims;
if (ctx.CurrentUser == null
|| ctx.CurrentUser.Claims == null
|| !isValid(ctx.CurrentUser.Claims))

0 comments on commit 63b7a9c

Please sign in to comment.
Something went wrong with that request. Please try again.