mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 18:32:51 +08:00
parent
340d0de233
commit
639011bc62
@ -1,6 +1,13 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
|
using Ocelot.Middleware;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
using Ocelot.Values;
|
||||||
|
|
||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorisation
|
||||||
{
|
{
|
||||||
@ -15,8 +22,11 @@ namespace Ocelot.Authorisation
|
|||||||
_claimsParser = claimsParser;
|
_claimsParser = claimsParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, Dictionary<string, string> routeClaimsRequirement)
|
public Response<bool> Authorise(
|
||||||
{
|
ClaimsPrincipal claimsPrincipal,
|
||||||
|
Dictionary<string, string> routeClaimsRequirement,
|
||||||
|
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
|
||||||
|
){
|
||||||
foreach (var required in routeClaimsRequirement)
|
foreach (var required in routeClaimsRequirement)
|
||||||
{
|
{
|
||||||
var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, required.Key);
|
var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, required.Key);
|
||||||
@ -28,6 +38,43 @@ namespace Ocelot.Authorisation
|
|||||||
|
|
||||||
if (values.Data != null)
|
if (values.Data != null)
|
||||||
{
|
{
|
||||||
|
// dynamic claim
|
||||||
|
var match = Regex.Match(required.Value, @"^{(?<variable>.+)}$");
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
var variableName = match.Captures[0].Value;
|
||||||
|
|
||||||
|
var matchingPlaceholders = urlPathPlaceholderNameAndValues.Where(p => p.Name.Equals(variableName)).Take(2).ToArray();
|
||||||
|
if (matchingPlaceholders.Length == 1)
|
||||||
|
{
|
||||||
|
// match
|
||||||
|
var actualValue = matchingPlaceholders[0].Value;
|
||||||
|
var authorised = values.Data.Contains(actualValue);
|
||||||
|
if (!authorised)
|
||||||
|
{
|
||||||
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
||||||
|
$"dynamic claim value for {variableName} of {string.Join(", ", values.Data)} is not the same as required value: {actualValue}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// config error
|
||||||
|
if (matchingPlaceholders.Length == 0)
|
||||||
|
{
|
||||||
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
||||||
|
$"config error: requires variable claim value: {variableName} placeholders does not contain that variable: {string.Join(", ", urlPathPlaceholderNameAndValues.Select(p=>p.Name))}"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
||||||
|
$"config error: requires variable claim value: {required.Value} but placeholders are ambiguous: {string.Join(", ", urlPathPlaceholderNameAndValues.Where(p=>p.Name.Equals(variableName)).Select(p => p.Value))}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// static claim
|
||||||
var authorised = values.Data.Contains(required.Value);
|
var authorised = values.Data.Contains(required.Value);
|
||||||
if (!authorised)
|
if (!authorised)
|
||||||
{
|
{
|
||||||
@ -35,6 +82,7 @@ namespace Ocelot.Authorisation
|
|||||||
$"claim value: {string.Join(", ", values.Data)} is not the same as required value: {required.Value} for type: {required.Key}"));
|
$"claim value: {string.Join(", ", values.Data)} is not the same as required value: {required.Value} for type: {required.Key}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new ErrorResponse<bool>(new UserDoesNotHaveClaimError($"user does not have claim {required.Key}"));
|
return new ErrorResponse<bool>(new UserDoesNotHaveClaimError($"user does not have claim {required.Key}"));
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
using Ocelot.Values;
|
||||||
|
|
||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorisation
|
||||||
{
|
{
|
||||||
@ -7,6 +11,10 @@ namespace Ocelot.Authorisation
|
|||||||
|
|
||||||
public interface IClaimsAuthoriser
|
public interface IClaimsAuthoriser
|
||||||
{
|
{
|
||||||
Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, Dictionary<string, string> routeClaimsRequirement);
|
Response<bool> Authorise(
|
||||||
|
ClaimsPrincipal claimsPrincipal,
|
||||||
|
Dictionary<string, string> routeClaimsRequirement,
|
||||||
|
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
{
|
{
|
||||||
Logger.LogInformation("route is authorised");
|
Logger.LogInformation("route is authorised");
|
||||||
|
|
||||||
var authorised = _claimsAuthoriser.Authorise(context.HttpContext.User, context.DownstreamReRoute.RouteClaimsRequirement);
|
var authorised = _claimsAuthoriser.Authorise(context.HttpContext.User, context.DownstreamReRoute.RouteClaimsRequirement, context.TemplatePlaceholderNameAndValues);
|
||||||
|
|
||||||
if (authorised.IsError)
|
if (authorised.IsError)
|
||||||
{
|
{
|
||||||
|
@ -69,15 +69,21 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
private void GivenTheAuthServiceReturns(Response<bool> expected)
|
private void GivenTheAuthServiceReturns(Response<bool> expected)
|
||||||
{
|
{
|
||||||
_authService
|
_authService
|
||||||
.Setup(x => x.Authorise(It.IsAny<ClaimsPrincipal>(), It.IsAny<Dictionary<string, string>>()))
|
.Setup(x => x.Authorise(
|
||||||
|
It.IsAny<ClaimsPrincipal>(),
|
||||||
|
It.IsAny<Dictionary<string, string>>(),
|
||||||
|
It.IsAny<List<PlaceholderNameAndValue>>()))
|
||||||
.Returns(expected);
|
.Returns(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheAuthServiceIsCalledCorrectly()
|
private void ThenTheAuthServiceIsCalledCorrectly()
|
||||||
{
|
{
|
||||||
_authService
|
_authService
|
||||||
.Verify(x => x.Authorise(It.IsAny<ClaimsPrincipal>(),
|
.Verify(x => x.Authorise(
|
||||||
It.IsAny<Dictionary<string, string>>()), Times.Once);
|
It.IsAny<ClaimsPrincipal>(),
|
||||||
|
It.IsAny<Dictionary<string, string>>(),
|
||||||
|
It.IsAny<List<PlaceholderNameAndValue>>())
|
||||||
|
, Times.Once);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Ocelot.Authorisation;
|
using Ocelot.Authorisation;
|
||||||
|
using Ocelot.Configuration;
|
||||||
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
using Ocelot.Values;
|
||||||
|
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -15,6 +19,7 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
private readonly ClaimsAuthoriser _claimsAuthoriser;
|
private readonly ClaimsAuthoriser _claimsAuthoriser;
|
||||||
private ClaimsPrincipal _claimsPrincipal;
|
private ClaimsPrincipal _claimsPrincipal;
|
||||||
private Dictionary<string, string> _requirement;
|
private Dictionary<string, string> _requirement;
|
||||||
|
private List<PlaceholderNameAndValue> _urlPathPlaceholderNameAndValues;
|
||||||
private Response<bool> _result;
|
private Response<bool> _result;
|
||||||
|
|
||||||
public ClaimsAuthoriserTests()
|
public ClaimsAuthoriserTests()
|
||||||
@ -38,6 +43,46 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_authorize_dynamic_user()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("userid", "14"),
|
||||||
|
}))))
|
||||||
|
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{"userid", "{userId}"}
|
||||||
|
}))
|
||||||
|
.And(x => x.GivenAPlaceHolderNameAndValueList(new List<PlaceholderNameAndValue>
|
||||||
|
{
|
||||||
|
new PlaceholderNameAndValue("{userId}", "14")
|
||||||
|
}))
|
||||||
|
.When(x => x.WhenICallTheAuthoriser())
|
||||||
|
.Then(x => x.ThenTheUserIsAuthorised())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_not_authorize_dynamic_user()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim("userid", "15"),
|
||||||
|
}))))
|
||||||
|
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{"userid", "{userId}"}
|
||||||
|
}))
|
||||||
|
.And(x => x.GivenAPlaceHolderNameAndValueList(new List<PlaceholderNameAndValue>
|
||||||
|
{
|
||||||
|
new PlaceholderNameAndValue("{userId}", "14")
|
||||||
|
}))
|
||||||
|
.When(x => x.WhenICallTheAuthoriser())
|
||||||
|
.Then(x => x.ThenTheUserIsntAuthorised())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_authorise_user_multiple_claims_of_same_type()
|
public void should_authorise_user_multiple_claims_of_same_type()
|
||||||
{
|
{
|
||||||
@ -78,9 +123,14 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
_requirement = requirement;
|
_requirement = requirement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GivenAPlaceHolderNameAndValueList(List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues)
|
||||||
|
{
|
||||||
|
_urlPathPlaceholderNameAndValues = urlPathPlaceholderNameAndValues;
|
||||||
|
}
|
||||||
|
|
||||||
private void WhenICallTheAuthoriser()
|
private void WhenICallTheAuthoriser()
|
||||||
{
|
{
|
||||||
_result = _claimsAuthoriser.Authorise(_claimsPrincipal, _requirement);
|
_result = _claimsAuthoriser.Authorise(_claimsPrincipal, _requirement, _urlPathPlaceholderNameAndValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheUserIsAuthorised()
|
private void ThenTheUserIsAuthorised()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user