Skip to content

Commit

Permalink
Multiple values in static claims
Browse files Browse the repository at this point in the history
removed redundant tests
  • Loading branch information
asrasya-kosha committed Jul 25, 2024
1 parent b4e21c4 commit 8204bbd
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 134 deletions.
6 changes: 3 additions & 3 deletions src/Ocelot/Authorization/ClaimsAuthorizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public ClaimsAuthorizer(IClaimsParser claimsParser)

public Response<bool> Authorize(
ClaimsPrincipal claimsPrincipal,
Dictionary<string, string> routeClaimsRequirement,
Dictionary<string, string[]> routeClaimsRequirement,
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
)
{
Expand All @@ -32,7 +32,7 @@ List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
if (values.Data != null)
{
// dynamic claim
var match = Regex.Match(required.Value, @"^{(?<variable>.+)}$");
var match = Regex.Match(required.Value!.FirstOrDefault() ?? string.Empty, "^{(?<variable>.+)}$");
if (match.Success)
{
var variableName = match.Captures[0].Value;
Expand Down Expand Up @@ -67,7 +67,7 @@ List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
else
{
// static claim
var authorized = values.Data.Contains(required.Value);
var authorized = required.Value.Any(x=> values.Data.Contains(x));
if (!authorized)
{
return new ErrorResponse<bool>(new ClaimValueNotAuthorizedError(
Expand Down
4 changes: 2 additions & 2 deletions src/Ocelot/Authorization/IClaimsAuthorizer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Responses;
using Ocelot.Responses;
using System.Security.Claims;

namespace Ocelot.Authorization
Expand All @@ -8,7 +8,7 @@ public interface IClaimsAuthorizer
{
Response<bool> Authorize(
ClaimsPrincipal claimsPrincipal,
Dictionary<string, string> routeClaimsRequirement,
Dictionary<string, string[]> routeClaimsRequirement,
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Ocelot/Configuration/Builder/DownstreamRouteBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class DownstreamRouteBuilder
private bool _isAuthenticated;
private List<ClaimToThing> _claimsToHeaders;
private List<ClaimToThing> _claimToClaims;
private Dictionary<string, string> _routeClaimRequirement;
private Dictionary<string, string[]> _routeClaimRequirement;
private bool _isAuthorized;
private List<ClaimToThing> _claimToQueries;
private List<ClaimToThing> _claimToDownstreamPath;
Expand Down Expand Up @@ -126,7 +126,7 @@ public DownstreamRouteBuilder WithClaimsToClaims(List<ClaimToThing> input)
return this;
}

public DownstreamRouteBuilder WithRouteClaimsRequirement(Dictionary<string, string> input)
public DownstreamRouteBuilder WithRouteClaimsRequirement(Dictionary<string, string[]> input)
{
_routeClaimRequirement = input;
return this;
Expand Down
6 changes: 3 additions & 3 deletions src/Ocelot/Configuration/DownstreamRoute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Ocelot.Configuration.Creator;
using Ocelot.Configuration.Creator;
using Ocelot.Values;

namespace Ocelot.Configuration
Expand All @@ -23,7 +23,7 @@ public DownstreamRoute(
CacheOptions cacheOptions,
LoadBalancerOptions loadBalancerOptions,
RateLimitOptions rateLimitOptions,
Dictionary<string, string> routeClaimsRequirement,
Dictionary<string, string[]> routeClaimsRequirement,
List<ClaimToThing> claimsToQueries,
List<ClaimToThing> claimsToHeaders,
List<ClaimToThing> claimsToClaims,
Expand Down Expand Up @@ -100,7 +100,7 @@ public DownstreamRoute(
public CacheOptions CacheOptions { get; }
public LoadBalancerOptions LoadBalancerOptions { get; }
public RateLimitOptions RateLimitOptions { get; }
public Dictionary<string, string> RouteClaimsRequirement { get; }
public Dictionary<string, string[]> RouteClaimsRequirement { get; }
public List<ClaimToThing> ClaimsToQueries { get; }
public List<ClaimToThing> ClaimsToHeaders { get; }
public List<ClaimToThing> ClaimsToClaims { get; }
Expand Down
90 changes: 45 additions & 45 deletions src/Ocelot/Configuration/File/FileRoute.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
using Ocelot.Configuration.Creator;

namespace Ocelot.Configuration.File
using Ocelot.Configuration.Creator;

namespace Ocelot.Configuration.File
{
public class FileRoute : IRoute, ICloneable
{
public FileRoute()
{
AddClaimsToRequest = new Dictionary<string, string>();
AddHeadersToRequest = new Dictionary<string, string>();
AddQueriesToRequest = new Dictionary<string, string>();
AuthenticationOptions = new FileAuthenticationOptions();
ChangeDownstreamPathTemplate = new Dictionary<string, string>();
DelegatingHandlers = new List<string>();
DownstreamHeaderTransform = new Dictionary<string, string>();
DownstreamHostAndPorts = new List<FileHostAndPort>();
FileCacheOptions = new FileCacheOptions();
HttpHandlerOptions = new FileHttpHandlerOptions();
LoadBalancerOptions = new FileLoadBalancerOptions();
Metadata = new Dictionary<string, string>();
Priority = 1;
QoSOptions = new FileQoSOptions();
RateLimitOptions = new FileRateLimitRule();
RouteClaimsRequirement = new Dictionary<string, string>();
SecurityOptions = new FileSecurityOptions();
public class FileRoute : IRoute, ICloneable
{
public FileRoute()
{
AddClaimsToRequest = new Dictionary<string, string>();
AddHeadersToRequest = new Dictionary<string, string>();
AddQueriesToRequest = new Dictionary<string, string>();
AuthenticationOptions = new FileAuthenticationOptions();
ChangeDownstreamPathTemplate = new Dictionary<string, string>();
DelegatingHandlers = new List<string>();
DownstreamHeaderTransform = new Dictionary<string, string>();
DownstreamHostAndPorts = new List<FileHostAndPort>();
FileCacheOptions = new FileCacheOptions();
HttpHandlerOptions = new FileHttpHandlerOptions();
LoadBalancerOptions = new FileLoadBalancerOptions();
Metadata = new Dictionary<string, string>();
Priority = 1;
QoSOptions = new FileQoSOptions();
RateLimitOptions = new FileRateLimitRule();
RouteClaimsRequirement = new Dictionary<string, string[]>();
SecurityOptions = new FileSecurityOptions();
UpstreamHeaderTemplates = new Dictionary<string, string>();
UpstreamHeaderTransform = new Dictionary<string, string>();
UpstreamHttpMethod = new List<string>();
UpstreamHeaderTransform = new Dictionary<string, string>();
UpstreamHttpMethod = new List<string>();
}

public FileRoute(FileRoute from)
Expand All @@ -44,30 +44,30 @@ public FileRoute(FileRoute from)
public List<FileHostAndPort> DownstreamHostAndPorts { get; set; }
public string DownstreamHttpMethod { get; set; }
public string DownstreamHttpVersion { get; set; }

/// <summary>The <see cref="HttpVersionPolicy"/> enum specifies behaviors for selecting and negotiating the HTTP version for a request.</summary>
/// <value>A <see langword="string" /> value of defined <see cref="VersionPolicies"/> constants.</value>
/// <remarks>
/// Related to the <see cref="DownstreamHttpVersion"/> property.
/// <list type="bullet">
/// <item><see href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpversionpolicy">HttpVersionPolicy Enum</see></item>
/// <item><see href="https://learn.microsoft.com/en-us/dotnet/api/system.net.httpversion">HttpVersion Class</see></item>
/// <item><see href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httprequestmessage.versionpolicy">HttpRequestMessage.VersionPolicy Property</see></item>
/// </list>
/// </remarks>

/// <summary>The <see cref="HttpVersionPolicy"/> enum specifies behaviors for selecting and negotiating the HTTP version for a request.</summary>
/// <value>A <see langword="string" /> value of defined <see cref="VersionPolicies"/> constants.</value>
/// <remarks>
/// Related to the <see cref="DownstreamHttpVersion"/> property.
/// <list type="bullet">
/// <item><see href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpversionpolicy">HttpVersionPolicy Enum</see></item>
/// <item><see href="https://learn.microsoft.com/en-us/dotnet/api/system.net.httpversion">HttpVersion Class</see></item>
/// <item><see href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httprequestmessage.versionpolicy">HttpRequestMessage.VersionPolicy Property</see></item>
/// </list>
/// </remarks>
public string DownstreamHttpVersionPolicy { get; set; }
public string DownstreamPathTemplate { get; set; }
public string DownstreamScheme { get; set; }
public string DownstreamScheme { get; set; }
public FileCacheOptions FileCacheOptions { get; set; }
public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
public string Key { get; set; }
public FileLoadBalancerOptions LoadBalancerOptions { get; set; }
public IDictionary<string, string> Metadata { get; set; }
public IDictionary<string, string> Metadata { get; set; }
public int Priority { get; set; }
public FileQoSOptions QoSOptions { get; set; }
public FileRateLimitRule RateLimitOptions { get; set; }
public string RequestIdKey { get; set; }
public Dictionary<string, string> RouteClaimsRequirement { get; set; }
public Dictionary<string, string[]> RouteClaimsRequirement { get; set; }
public bool RouteIsCaseSensitive { get; set; }
public FileSecurityOptions SecurityOptions { get; set; }
public string ServiceName { get; set; }
Expand Down Expand Up @@ -103,14 +103,14 @@ public static void DeepCopy(FileRoute from, FileRoute to)
to.DownstreamHostAndPorts = from.DownstreamHostAndPorts.Select(x => new FileHostAndPort(x)).ToList();
to.DownstreamHttpMethod = from.DownstreamHttpMethod;
to.DownstreamHttpVersion = from.DownstreamHttpVersion;
to.DownstreamHttpVersionPolicy = from.DownstreamHttpVersionPolicy;
to.DownstreamHttpVersionPolicy = from.DownstreamHttpVersionPolicy;
to.DownstreamPathTemplate = from.DownstreamPathTemplate;
to.DownstreamScheme = from.DownstreamScheme;
to.DownstreamScheme = from.DownstreamScheme;
to.FileCacheOptions = new(from.FileCacheOptions);
to.HttpHandlerOptions = new(from.HttpHandlerOptions);
to.Key = from.Key;
to.LoadBalancerOptions = new(from.LoadBalancerOptions);
to.Metadata = new Dictionary<string, string>(from.Metadata);
to.Metadata = new Dictionary<string, string>(from.Metadata);
to.Priority = from.Priority;
to.QoSOptions = new(from.QoSOptions);
to.RateLimitOptions = new(from.RateLimitOptions);
Expand All @@ -127,5 +127,5 @@ public static void DeepCopy(FileRoute from, FileRoute to)
to.UpstreamHttpMethod = new(from.UpstreamHttpMethod);
to.UpstreamPathTemplate = from.UpstreamPathTemplate;
}
}
}
}
}
6 changes: 3 additions & 3 deletions test/Ocelot.AcceptanceTests/AuthorizationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void should_return_response_200_authorizing_route()
},
RouteClaimsRequirement =
{
{"UserType", "registered"},
{"UserType",new []{ "registered" }},
},
},
},
Expand Down Expand Up @@ -134,7 +134,7 @@ public void should_return_response_403_authorizing_route()
},
RouteClaimsRequirement =
{
{"UserType", "registered"},
{"UserType",new []{ "registered" }},
},
},
},
Expand Down Expand Up @@ -266,7 +266,7 @@ public void should_fix_issue_240()
},
RouteClaimsRequirement =
{
{"Role", "User"},
{"Role",new []{ "User" }},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ private void GivenTheAuthServiceReturns(Response<bool> expected)
_authService
.Setup(x => x.Authorize(
It.IsAny<ClaimsPrincipal>(),
It.IsAny<Dictionary<string, string>>(),
It.IsAny<Dictionary<string, string[]>>(),
It.IsAny<List<PlaceholderNameAndValue>>()))
.Returns(expected);
}

private void ThenTheAuthServiceIsCalledCorrectly()
{
_authService.Verify(
x => x.Authorize(It.IsAny<ClaimsPrincipal>(), It.IsAny<Dictionary<string, string>>(), It.IsAny<List<PlaceholderNameAndValue>>()),
x => x.Authorize(It.IsAny<ClaimsPrincipal>(), It.IsAny<Dictionary<string, string[]>>(), It.IsAny<List<PlaceholderNameAndValue>>()),
Times.Once);
}
}
Expand Down
46 changes: 31 additions & 15 deletions test/Ocelot.UnitTests/Authorization/ClaimsAuthorizerTests.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using Ocelot.Authorization;
using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Infrastructure.Claims.Parser;
using Ocelot.Responses;
using System.Security.Claims;
using Ocelot.Responses;
using System.Security.Claims;

namespace Ocelot.UnitTests.Authorization
{
public class ClaimsAuthorizerTests : UnitTest
{
private readonly ClaimsAuthorizer _claimsAuthorizer;
private ClaimsPrincipal _claimsPrincipal;
private Dictionary<string, string> _requirement;
private Dictionary<string, string[]> _requirement;
private List<PlaceholderNameAndValue> _urlPathPlaceholderNameAndValues;
private Response<bool> _result;

Expand All @@ -26,9 +26,9 @@ public void should_authorize_user()
{
new("UserType", "registered"),
}))))
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string[]>
{
{"UserType", "registered"},
{"UserType",new []{ "registered" }},
}))
.When(x => x.WhenICallTheAuthorizer())
.Then(x => x.ThenTheUserIsAuthorized())
Expand All @@ -42,9 +42,9 @@ public void should_authorize_dynamic_user()
{
new("userid", "14"),
}))))
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string[]>
{
{"userid", "{userId}"},
{"userid",new []{ "{userId}" }},
}))
.And(x => x.GivenAPlaceHolderNameAndValueList(new List<PlaceholderNameAndValue>
{
Expand All @@ -62,9 +62,9 @@ public void should_not_authorize_dynamic_user()
{
new("userid", "15"),
}))))
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string[]>
{
{"userid", "{userId}"},
{"userid", new []{ "{userId}" }},
}))
.And(x => x.GivenAPlaceHolderNameAndValueList(new List<PlaceholderNameAndValue>
{
Expand All @@ -74,7 +74,7 @@ public void should_not_authorize_dynamic_user()
.Then(x => x.ThenTheUserIsntAuthorized())
.BDDfy();
}

[Fact]
public void should_authorize_user_multiple_claims_of_same_type()
{
Expand All @@ -83,9 +83,25 @@ public void should_authorize_user_multiple_claims_of_same_type()
new("UserType", "guest"),
new("UserType", "registered"),
}))))
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string[]>
{
{"UserType", new []{ "registered" }},
}))
.When(x => x.WhenICallTheAuthorizer())
.Then(x => x.ThenTheUserIsAuthorized())
.BDDfy();
}

[Fact]
public void should_authorize_user_with_route_having_multiple_claims_requirement()
{
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
{
new("UserType", "registered"),
}))))
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string[]>
{
{"UserType", "registered"},
{"UserType", new []{ "non-admin","registered" }},
}))
.When(x => x.WhenICallTheAuthorizer())
.Then(x => x.ThenTheUserIsAuthorized())
Expand All @@ -96,9 +112,9 @@ public void should_authorize_user_multiple_claims_of_same_type()
public void should_not_authorize_user()
{
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()))))
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string>
.And(x => x.GivenARouteClaimsRequirement(new Dictionary<string, string[]>
{
{ "UserType", "registered" },
{ "UserType",new []{ "registered" }},
}))
.When(x => x.WhenICallTheAuthorizer())
.Then(x => x.ThenTheUserIsntAuthorized())
Expand All @@ -110,7 +126,7 @@ private void GivenAClaimsPrincipal(ClaimsPrincipal claimsPrincipal)
_claimsPrincipal = claimsPrincipal;
}

private void GivenARouteClaimsRequirement(Dictionary<string, string> requirement)
private void GivenARouteClaimsRequirement(Dictionary<string, string[]> requirement)
{
_requirement = requirement;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public DownstreamRouteExtensionsTests()
new CacheOptions(0, null, null, null),
new LoadBalancerOptions(null, null, 0),
new RateLimitOptions(false, null, null, false, null, null, null, 0),
new Dictionary<string, string>(),
new Dictionary<string, string[]>(),
new List<ClaimToThing>(),
new List<ClaimToThing>(),
new List<ClaimToThing>(),
Expand Down
Loading

0 comments on commit 8204bbd

Please sign in to comment.