mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-17 13:23:20 +08:00
rename authorisation to authorization
This commit is contained in:
parent
b2dd70f59c
commit
b46fedac24
@ -30,7 +30,7 @@ A quick list of Ocelot's capabilities for more information see the [documentatio
|
|||||||
* Kubernetes
|
* Kubernetes
|
||||||
* WebSockets
|
* WebSockets
|
||||||
* Authentication
|
* Authentication
|
||||||
* Authorisation
|
* Authorization
|
||||||
* Rate Limiting
|
* Rate Limiting
|
||||||
* Caching
|
* Caching
|
||||||
* Retry policies / QoS
|
* Retry policies / QoS
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Authentication
|
Authentication
|
||||||
==============
|
==============
|
||||||
|
|
||||||
In order to authenticate Routes and subsequently use any of Ocelot's claims based features such as authorisation or modifying the request with values from the token. Users must register authentication services in their Startup.cs as usual but they provide a scheme (authentication provider key) with each registration e.g.
|
In order to authenticate Routes and subsequently use any of Ocelot's claims based features such as authorization or modifying the request with values from the token. Users must register authentication services in their Startup.cs as usual but they provide a scheme (authentication provider key) with each registration e.g.
|
||||||
|
|
||||||
.. code-block:: csharp
|
.. code-block:: csharp
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Authorisation
|
Authorization
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Ocelot supports claims based authorisation which is run post authentication. This means if you have a route you want to authorise you can add the following to you Route configuration.
|
Ocelot supports claims based authorization which is run post authentication. This means if you have a route you want to authorize you can add the following to you Route configuration.
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ Ocelot supports claims based authorisation which is run post authentication. Thi
|
|||||||
"UserType": "registered"
|
"UserType": "registered"
|
||||||
}
|
}
|
||||||
|
|
||||||
In this example when the authorisation middleware is called Ocelot will check to seeif the user has the claim type UserType and if the value of that claim is registered. If it isn't then the user will not be authorised and the response will be 403 forbidden.
|
In this example when the authorization middleware is called Ocelot will check to seeif the user has the claim type UserType and if the value of that claim is registered. If it isn't then the user will not be authorized and the response will be 403 forbidden.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3,7 +3,7 @@ Claims Transformation
|
|||||||
|
|
||||||
Ocelot allows the user to access claims and transform them into headers, query string parameters, other claims and change downstream paths. This is only available once a user has been authenticated.
|
Ocelot allows the user to access claims and transform them into headers, query string parameters, other claims and change downstream paths. This is only available once a user has been authenticated.
|
||||||
|
|
||||||
After the user is authenticated we run the claims to claims transformation middleware. This allows the user to transform claims before the authorisation middleware is called. After the user is authorised first we call the claims to headers middleware, thenthe claims to query string parameters middleware, and Finally the claims to downstream pathmiddleware.
|
After the user is authenticated we run the claims to claims transformation middleware. This allows the user to transform claims before the authorization middleware is called. After the user is authorized first we call the claims to headers middleware, thenthe claims to query string parameters middleware, and Finally the claims to downstream pathmiddleware.
|
||||||
|
|
||||||
The syntax for performing the transforms is the same for each process. In the Route configuration a json dictionary is added with a specific name either AddClaimsToRequest, AddHeadersToRequest, AddQueriesToRequest, or ChangeDownstreamPathTemplate.
|
The syntax for performing the transforms is the same for each process. In the Route configuration a json dictionary is added with a specific name either AddClaimsToRequest, AddHeadersToRequest, AddQueriesToRequest, or ChangeDownstreamPathTemplate.
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ Http Error Status Codes
|
|||||||
|
|
||||||
Ocelot will return HTTP status error codes based on internal logic in certain siturations:
|
Ocelot will return HTTP status error codes based on internal logic in certain siturations:
|
||||||
- 401 if the authentication middleware runs and the user is not authenticated.
|
- 401 if the authentication middleware runs and the user is not authenticated.
|
||||||
- 403 if the authorisation middleware runs and the user is unauthenticated, claim value not authroised, scope not authorised, user doesnt have required claim or cannot find claim.
|
- 403 if the authorization middleware runs and the user is unauthenticated, claim value not authroised, scope not authorized, user doesnt have required claim or cannot find claim.
|
||||||
- 503 if the downstream request times out.
|
- 503 if the downstream request times out.
|
||||||
- 499 if the request is cancelled by the client.
|
- 499 if the request is cancelled by the client.
|
||||||
- 404 if unable to find a downstream route.
|
- 404 if unable to find a downstream route.
|
||||||
|
@ -31,9 +31,9 @@ The user can set functions against the following.
|
|||||||
|
|
||||||
* AuthenticationMiddleware - This overrides Ocelots authentication middleware.
|
* AuthenticationMiddleware - This overrides Ocelots authentication middleware.
|
||||||
|
|
||||||
* PreAuthorisationMiddleware - This allows the user to run pre authorisation logic and then call Ocelot's authorisation middleware.
|
* PreAuthorizationMiddleware - This allows the user to run pre authorization logic and then call Ocelot's authorization middleware.
|
||||||
|
|
||||||
* AuthorisationMiddleware - This overrides Ocelots authorisation middleware.
|
* AuthorizationMiddleware - This overrides Ocelots authorization middleware.
|
||||||
|
|
||||||
* PreQueryStringBuilderMiddleware - This allows the user to manipulate the query string on the http request before it is passed to Ocelots request creator.
|
* PreQueryStringBuilderMiddleware - This allows the user to manipulate the query string on the http request before it is passed to Ocelots request creator.
|
||||||
|
|
||||||
|
@ -44,8 +44,8 @@ Below is an example of the logging when set at Debug level for a normal request.
|
|||||||
requestId: asdf, previousRequestId: no previous request id, message: downstream template is {downstreamRoute.Data.Route.DownstreamPath},
|
requestId: asdf, previousRequestId: no previous request id, message: downstream template is {downstreamRoute.Data.Route.DownstreamPath},
|
||||||
dbug: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0]
|
dbug: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0]
|
||||||
requestId: asdf, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for Ocelot.Values.PathTemplate,
|
requestId: asdf, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for Ocelot.Values.PathTemplate,
|
||||||
dbug: Ocelot.Authorisation.Middleware.AuthorisationMiddleware[0]
|
dbug: Ocelot.Authorization.Middleware.AuthorizationMiddleware[0]
|
||||||
requestId: 1234, previousRequestId: asdf, message: /posts/{postId} route does not require user to be authorised,
|
requestId: 1234, previousRequestId: asdf, message: /posts/{postId} route does not require user to be authorized,
|
||||||
dbug: Ocelot.DownstreamUrlCreator.Middleware.DownstreamUrlCreatorMiddleware[0]
|
dbug: Ocelot.DownstreamUrlCreator.Middleware.DownstreamUrlCreatorMiddleware[0]
|
||||||
requestId: 1234, previousRequestId: asdf, message: downstream url is {downstreamUrl.Data.Value},
|
requestId: 1234, previousRequestId: asdf, message: downstream url is {downstreamUrl.Data.Value},
|
||||||
dbug: Ocelot.Request.Middleware.HttpRequestBuilderMiddleware[0]
|
dbug: Ocelot.Request.Middleware.HttpRequestBuilderMiddleware[0]
|
||||||
|
@ -102,7 +102,7 @@ Unfortunately a lot of Ocelot's features are non websocket specific such as head
|
|||||||
9. Claims Transformation
|
9. Claims Transformation
|
||||||
10. Caching
|
10. Caching
|
||||||
11. Authentication - If anyone requests it we might be able to do something with basic authentication.
|
11. Authentication - If anyone requests it we might be able to do something with basic authentication.
|
||||||
12. Authorisation
|
12. Authorization
|
||||||
|
|
||||||
I'm not 100% sure what will happen with this feature when it get's into the wild so please make sure you test thoroughly!
|
I'm not 100% sure what will happen with this feature when it get's into the wild so please make sure you test thoroughly!
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ Thanks for taking a look at the Ocelot documentation. Please use the left hand n
|
|||||||
features/servicefabric
|
features/servicefabric
|
||||||
features/kubernetes
|
features/kubernetes
|
||||||
features/authentication
|
features/authentication
|
||||||
features/authorisation
|
features/authorization
|
||||||
features/websockets
|
features/websockets
|
||||||
features/administration
|
features/administration
|
||||||
features/ratelimiting
|
features/ratelimiting
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Ocelot using GraphQL example
|
# Ocelot using GraphQL example
|
||||||
|
|
||||||
Loads of people keep asking me if Ocelot will every support GraphQL, in my mind Ocelot and GraphQL are two different things that can work together.
|
Loads of people keep asking me if Ocelot will every support GraphQL, in my mind Ocelot and GraphQL are two different things that can work together.
|
||||||
I would not try and implement GraphQL in Ocelot instead I would either have Ocelot in front of GraphQL to handle things like authorisation / authentication or I would
|
I would not try and implement GraphQL in Ocelot instead I would either have Ocelot in front of GraphQL to handle things like authorization / authentication or I would
|
||||||
bring in the awesome [graphql-dotnet](https://github.com/graphql-dotnet/graphql-dotnet) library and use it in a [DelegatingHandler](http://ocelot.readthedocs.io/en/latest/features/delegatinghandlers.html). This way you could have Ocelot and GraphQL without the extra hop to GraphQL. This same is an example of how to do that.
|
bring in the awesome [graphql-dotnet](https://github.com/graphql-dotnet/graphql-dotnet) library and use it in a [DelegatingHandler](http://ocelot.readthedocs.io/en/latest/features/delegatinghandlers.html). This way you could have Ocelot and GraphQL without the extra hop to GraphQL. This same is an example of how to do that.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
namespace Ocelot.Authorisation
|
|
||||||
{
|
|
||||||
using Ocelot.Errors;
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
public class ClaimValueNotAuthorisedError : Error
|
|
||||||
{
|
|
||||||
public ClaimValueNotAuthorisedError(string message)
|
|
||||||
: base(message, OcelotErrorCode.ClaimValueNotAuthorisedError, 403)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
namespace Ocelot.Authorisation.Middleware
|
|
||||||
{
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
|
|
||||||
public static class AuthorisationMiddlewareMiddlewareExtensions
|
|
||||||
{
|
|
||||||
public static IApplicationBuilder UseAuthorisationMiddleware(this IApplicationBuilder builder)
|
|
||||||
{
|
|
||||||
return builder.UseMiddleware<AuthorisationMiddleware>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
namespace Ocelot.Authorisation
|
|
||||||
{
|
|
||||||
using Ocelot.Errors;
|
|
||||||
|
|
||||||
public class ScopeNotAuthorisedError : Error
|
|
||||||
{
|
|
||||||
public ScopeNotAuthorisedError(string message)
|
|
||||||
: base(message, OcelotErrorCode.ScopeNotAuthorisedError, 403)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
13
src/Ocelot/Authorization/ClaimValueNotAuthorizedError.cs
Normal file
13
src/Ocelot/Authorization/ClaimValueNotAuthorizedError.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Ocelot.Authorization
|
||||||
|
{
|
||||||
|
using Ocelot.Errors;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
public class ClaimValueNotAuthorizedError : Error
|
||||||
|
{
|
||||||
|
public ClaimValueNotAuthorizedError(string message)
|
||||||
|
: base(message, OcelotErrorCode.ClaimValueNotAuthorizedError, 403)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorization
|
||||||
{
|
{
|
||||||
using Ocelot.Infrastructure.Claims.Parser;
|
using Ocelot.Infrastructure.Claims.Parser;
|
||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
@ -8,16 +8,16 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
public class ClaimsAuthoriser : IClaimsAuthoriser
|
public class ClaimsAuthorizer : IClaimsAuthorizer
|
||||||
{
|
{
|
||||||
private readonly IClaimsParser _claimsParser;
|
private readonly IClaimsParser _claimsParser;
|
||||||
|
|
||||||
public ClaimsAuthoriser(IClaimsParser claimsParser)
|
public ClaimsAuthorizer(IClaimsParser claimsParser)
|
||||||
{
|
{
|
||||||
_claimsParser = claimsParser;
|
_claimsParser = claimsParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response<bool> Authorise(
|
public Response<bool> Authorize(
|
||||||
ClaimsPrincipal claimsPrincipal,
|
ClaimsPrincipal claimsPrincipal,
|
||||||
Dictionary<string, string> routeClaimsRequirement,
|
Dictionary<string, string> routeClaimsRequirement,
|
||||||
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
|
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
|
||||||
@ -45,10 +45,10 @@
|
|||||||
{
|
{
|
||||||
// match
|
// match
|
||||||
var actualValue = matchingPlaceholders[0].Value;
|
var actualValue = matchingPlaceholders[0].Value;
|
||||||
var authorised = values.Data.Contains(actualValue);
|
var authorized = values.Data.Contains(actualValue);
|
||||||
if (!authorised)
|
if (!authorized)
|
||||||
{
|
{
|
||||||
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorizedError(
|
||||||
$"dynamic claim value for {variableName} of {string.Join(", ", values.Data)} is not the same as required value: {actualValue}"));
|
$"dynamic claim value for {variableName} of {string.Join(", ", values.Data)} is not the same as required value: {actualValue}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,12 +57,12 @@
|
|||||||
// config error
|
// config error
|
||||||
if (matchingPlaceholders.Length == 0)
|
if (matchingPlaceholders.Length == 0)
|
||||||
{
|
{
|
||||||
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorizedError(
|
||||||
$"config error: requires variable claim value: {variableName} placeholders does not contain that variable: {string.Join(", ", urlPathPlaceholderNameAndValues.Select(p => p.Name))}"));
|
$"config error: requires variable claim value: {variableName} placeholders does not contain that variable: {string.Join(", ", urlPathPlaceholderNameAndValues.Select(p => p.Name))}"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorizedError(
|
||||||
$"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))}"));
|
$"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))}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,10 +70,10 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// static claim
|
// static claim
|
||||||
var authorised = values.Data.Contains(required.Value);
|
var authorized = values.Data.Contains(required.Value);
|
||||||
if (!authorised)
|
if (!authorized)
|
||||||
{
|
{
|
||||||
return new ErrorResponse<bool>(new ClaimValueNotAuthorisedError(
|
return new ErrorResponse<bool>(new ClaimValueNotAuthorizedError(
|
||||||
$"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}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,16 +2,16 @@
|
|||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorization
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public interface IClaimsAuthoriser
|
public interface IClaimsAuthorizer
|
||||||
{
|
{
|
||||||
Response<bool> Authorise(
|
Response<bool> Authorize(
|
||||||
ClaimsPrincipal claimsPrincipal,
|
ClaimsPrincipal claimsPrincipal,
|
||||||
Dictionary<string, string> routeClaimsRequirement,
|
Dictionary<string, string> routeClaimsRequirement,
|
||||||
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
|
List<PlaceholderNameAndValue> urlPathPlaceholderNameAndValues
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,12 +1,12 @@
|
|||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorization
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public interface IScopesAuthoriser
|
public interface IScopesAuthorizer
|
||||||
{
|
{
|
||||||
Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, List<string> routeAllowedScopes);
|
Response<bool> Authorize(ClaimsPrincipal claimsPrincipal, List<string> routeAllowedScopes);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace Ocelot.Authorisation.Middleware
|
namespace Ocelot.Authorization.Middleware
|
||||||
{
|
{
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
@ -8,21 +8,21 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||||
|
|
||||||
public class AuthorisationMiddleware : OcelotMiddleware
|
public class AuthorizationMiddleware : OcelotMiddleware
|
||||||
{
|
{
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly IClaimsAuthoriser _claimsAuthoriser;
|
private readonly IClaimsAuthorizer _claimsAuthorizer;
|
||||||
private readonly IScopesAuthoriser _scopesAuthoriser;
|
private readonly IScopesAuthorizer _scopesAuthorizer;
|
||||||
|
|
||||||
public AuthorisationMiddleware(RequestDelegate next,
|
public AuthorizationMiddleware(RequestDelegate next,
|
||||||
IClaimsAuthoriser claimsAuthoriser,
|
IClaimsAuthorizer claimsAuthorizer,
|
||||||
IScopesAuthoriser scopesAuthoriser,
|
IScopesAuthorizer scopesAuthorizer,
|
||||||
IOcelotLoggerFactory loggerFactory)
|
IOcelotLoggerFactory loggerFactory)
|
||||||
: base(loggerFactory.CreateLogger<AuthorisationMiddleware>())
|
: base(loggerFactory.CreateLogger<AuthorizationMiddleware>())
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
_claimsAuthoriser = claimsAuthoriser;
|
_claimsAuthorizer = claimsAuthorizer;
|
||||||
_scopesAuthoriser = scopesAuthoriser;
|
_scopesAuthorizer = scopesAuthorizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
@ -33,65 +33,65 @@
|
|||||||
{
|
{
|
||||||
Logger.LogInformation("route is authenticated scopes must be checked");
|
Logger.LogInformation("route is authenticated scopes must be checked");
|
||||||
|
|
||||||
var authorised = _scopesAuthoriser.Authorise(httpContext.User, downstreamRoute.AuthenticationOptions.AllowedScopes);
|
var authorized = _scopesAuthorizer.Authorize(httpContext.User, downstreamRoute.AuthenticationOptions.AllowedScopes);
|
||||||
|
|
||||||
if (authorised.IsError)
|
if (authorized.IsError)
|
||||||
{
|
{
|
||||||
Logger.LogWarning("error authorising user scopes");
|
Logger.LogWarning("error authorizing user scopes");
|
||||||
|
|
||||||
httpContext.Items.UpsertErrors(authorised.Errors);
|
httpContext.Items.UpsertErrors(authorized.Errors);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAuthorised(authorised))
|
if (IsAuthorized(authorized))
|
||||||
{
|
{
|
||||||
Logger.LogInformation("user scopes is authorised calling next authorisation checks");
|
Logger.LogInformation("user scopes is authorized calling next authorization checks");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.LogWarning("user scopes is not authorised setting pipeline error");
|
Logger.LogWarning("user scopes is not authorized setting pipeline error");
|
||||||
|
|
||||||
httpContext.Items.SetError(new UnauthorisedError(
|
httpContext.Items.SetError(new UnauthorizedError(
|
||||||
$"{httpContext.User.Identity.Name} unable to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}"));
|
$"{httpContext.User.Identity.Name} unable to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsOptionsHttpMethod(httpContext) && IsAuthorisedRoute(downstreamRoute))
|
if (!IsOptionsHttpMethod(httpContext) && IsAuthorizedRoute(downstreamRoute))
|
||||||
{
|
{
|
||||||
Logger.LogInformation("route is authorised");
|
Logger.LogInformation("route is authorized");
|
||||||
|
|
||||||
var authorised = _claimsAuthoriser.Authorise(httpContext.User, downstreamRoute.RouteClaimsRequirement, httpContext.Items.TemplatePlaceholderNameAndValues());
|
var authorized = _claimsAuthorizer.Authorize(httpContext.User, downstreamRoute.RouteClaimsRequirement, httpContext.Items.TemplatePlaceholderNameAndValues());
|
||||||
|
|
||||||
if (authorised.IsError)
|
if (authorized.IsError)
|
||||||
{
|
{
|
||||||
Logger.LogWarning($"Error whilst authorising {httpContext.User.Identity.Name}. Setting pipeline error");
|
Logger.LogWarning($"Error whilst authorizing {httpContext.User.Identity.Name}. Setting pipeline error");
|
||||||
|
|
||||||
httpContext.Items.UpsertErrors(authorised.Errors);
|
httpContext.Items.UpsertErrors(authorized.Errors);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAuthorised(authorised))
|
if (IsAuthorized(authorized))
|
||||||
{
|
{
|
||||||
Logger.LogInformation($"{httpContext.User.Identity.Name} has succesfully been authorised for {downstreamRoute.UpstreamPathTemplate.OriginalValue}.");
|
Logger.LogInformation($"{httpContext.User.Identity.Name} has succesfully been authorized for {downstreamRoute.UpstreamPathTemplate.OriginalValue}.");
|
||||||
await _next.Invoke(httpContext);
|
await _next.Invoke(httpContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.LogWarning($"{httpContext.User.Identity.Name} is not authorised to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}. Setting pipeline error");
|
Logger.LogWarning($"{httpContext.User.Identity.Name} is not authorized to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}. Setting pipeline error");
|
||||||
|
|
||||||
httpContext.Items.SetError(new UnauthorisedError($"{httpContext.User.Identity.Name} is not authorised to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}"));
|
httpContext.Items.SetError(new UnauthorizedError($"{httpContext.User.Identity.Name} is not authorized to access {downstreamRoute.UpstreamPathTemplate.OriginalValue}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.LogInformation($"{downstreamRoute.DownstreamPathTemplate.Value} route does not require user to be authorised");
|
Logger.LogInformation($"{downstreamRoute.DownstreamPathTemplate.Value} route does not require user to be authorized");
|
||||||
await _next.Invoke(httpContext);
|
await _next.Invoke(httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsAuthorised(Response<bool> authorised)
|
private static bool IsAuthorized(Response<bool> authorized)
|
||||||
{
|
{
|
||||||
return authorised.Data;
|
return authorized.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsAuthenticatedRoute(DownstreamRoute route)
|
private static bool IsAuthenticatedRoute(DownstreamRoute route)
|
||||||
@ -99,9 +99,9 @@
|
|||||||
return route.IsAuthenticated;
|
return route.IsAuthenticated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsAuthorisedRoute(DownstreamRoute route)
|
private static bool IsAuthorizedRoute(DownstreamRoute route)
|
||||||
{
|
{
|
||||||
return route.IsAuthorised;
|
return route.IsAuthorized;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsOptionsHttpMethod(HttpContext httpContext)
|
private static bool IsOptionsHttpMethod(HttpContext httpContext)
|
@ -0,0 +1,12 @@
|
|||||||
|
namespace Ocelot.Authorization.Middleware
|
||||||
|
{
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
|
||||||
|
public static class AuthorizationMiddlewareMiddlewareExtensions
|
||||||
|
{
|
||||||
|
public static IApplicationBuilder UseAuthorizationMiddleware(this IApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
return builder.UseMiddleware<AuthorizationMiddleware>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/Ocelot/Authorization/ScopeNotAuthorizedError.cs
Normal file
12
src/Ocelot/Authorization/ScopeNotAuthorizedError.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace Ocelot.Authorization
|
||||||
|
{
|
||||||
|
using Ocelot.Errors;
|
||||||
|
|
||||||
|
public class ScopeNotAuthorizedError : Error
|
||||||
|
{
|
||||||
|
public ScopeNotAuthorizedError(string message)
|
||||||
|
: base(message, OcelotErrorCode.ScopeNotAuthorizedError, 403)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,47 +1,47 @@
|
|||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorization
|
||||||
{
|
{
|
||||||
using Infrastructure.Claims.Parser;
|
using Infrastructure.Claims.Parser;
|
||||||
|
|
||||||
public class ScopesAuthoriser : IScopesAuthoriser
|
public class ScopesAuthorizer : IScopesAuthorizer
|
||||||
{
|
{
|
||||||
private readonly IClaimsParser _claimsParser;
|
private readonly IClaimsParser _claimsParser;
|
||||||
private readonly string _scope = "scope";
|
private readonly string _scope = "scope";
|
||||||
|
|
||||||
public ScopesAuthoriser(IClaimsParser claimsParser)
|
public ScopesAuthorizer(IClaimsParser claimsParser)
|
||||||
{
|
{
|
||||||
_claimsParser = claimsParser;
|
_claimsParser = claimsParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response<bool> Authorise(ClaimsPrincipal claimsPrincipal, List<string> routeAllowedScopes)
|
public Response<bool> Authorize(ClaimsPrincipal claimsPrincipal, List<string> routeAllowedScopes)
|
||||||
{
|
{
|
||||||
if (routeAllowedScopes == null || routeAllowedScopes.Count == 0)
|
if (routeAllowedScopes == null || routeAllowedScopes.Count == 0)
|
||||||
{
|
{
|
||||||
return new OkResponse<bool>(true);
|
return new OkResponse<bool>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, _scope);
|
var values = _claimsParser.GetValuesByClaimType(claimsPrincipal.Claims, _scope);
|
||||||
|
|
||||||
if (values.IsError)
|
if (values.IsError)
|
||||||
{
|
{
|
||||||
return new ErrorResponse<bool>(values.Errors);
|
return new ErrorResponse<bool>(values.Errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
var userScopes = values.Data;
|
var userScopes = values.Data;
|
||||||
|
|
||||||
var matchesScopes = routeAllowedScopes.Intersect(userScopes).ToList();
|
var matchesScopes = routeAllowedScopes.Intersect(userScopes).ToList();
|
||||||
|
|
||||||
if (matchesScopes.Count == 0)
|
if (matchesScopes.Count == 0)
|
||||||
{
|
{
|
||||||
return new ErrorResponse<bool>(
|
return new ErrorResponse<bool>(
|
||||||
new ScopeNotAuthorisedError($"no one user scope: '{string.Join(",", userScopes)}' match with some allowed scope: '{string.Join(",", routeAllowedScopes)}'"));
|
new ScopeNotAuthorizedError($"no one user scope: '{string.Join(",", userScopes)}' match with some allowed scope: '{string.Join(",", routeAllowedScopes)}'"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OkResponse<bool>(true);
|
return new OkResponse<bool>(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorization
|
||||||
{
|
{
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
|
|
||||||
public class UnauthorisedError : Error
|
public class UnauthorizedError : Error
|
||||||
{
|
{
|
||||||
public UnauthorisedError(string message)
|
public UnauthorizedError(string message)
|
||||||
: base(message, OcelotErrorCode.UnauthorizedError, 403)
|
: base(message, OcelotErrorCode.UnauthorizedError, 403)
|
||||||
{
|
{
|
||||||
}
|
}
|
@ -1,12 +1,12 @@
|
|||||||
namespace Ocelot.Authorisation
|
namespace Ocelot.Authorization
|
||||||
{
|
{
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
|
|
||||||
public class UserDoesNotHaveClaimError : Error
|
public class UserDoesNotHaveClaimError : Error
|
||||||
{
|
{
|
||||||
public UserDoesNotHaveClaimError(string message)
|
public UserDoesNotHaveClaimError(string message)
|
||||||
: base(message, OcelotErrorCode.UserDoesNotHaveClaimError, 403)
|
: base(message, OcelotErrorCode.UserDoesNotHaveClaimError, 403)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ namespace Ocelot.Configuration.Builder
|
|||||||
private List<ClaimToThing> _claimsToHeaders;
|
private List<ClaimToThing> _claimsToHeaders;
|
||||||
private List<ClaimToThing> _claimToClaims;
|
private List<ClaimToThing> _claimToClaims;
|
||||||
private Dictionary<string, string> _routeClaimRequirement;
|
private Dictionary<string, string> _routeClaimRequirement;
|
||||||
private bool _isAuthorised;
|
private bool _isAuthorized;
|
||||||
private List<ClaimToThing> _claimToQueries;
|
private List<ClaimToThing> _claimToQueries;
|
||||||
private List<ClaimToThing> _claimToDownstreamPath;
|
private List<ClaimToThing> _claimToDownstreamPath;
|
||||||
private string _requestIdHeaderKey;
|
private string _requestIdHeaderKey;
|
||||||
@ -101,9 +101,9 @@ namespace Ocelot.Configuration.Builder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownstreamRouteBuilder WithIsAuthorised(bool input)
|
public DownstreamRouteBuilder WithIsAuthorized(bool input)
|
||||||
{
|
{
|
||||||
_isAuthorised = input;
|
_isAuthorized = input;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ namespace Ocelot.Configuration.Builder
|
|||||||
_claimToClaims,
|
_claimToClaims,
|
||||||
_claimToDownstreamPath,
|
_claimToDownstreamPath,
|
||||||
_isAuthenticated,
|
_isAuthenticated,
|
||||||
_isAuthorised,
|
_isAuthorized,
|
||||||
_authenticationOptions,
|
_authenticationOptions,
|
||||||
new DownstreamPathTemplate(_downstreamPathTemplate),
|
new DownstreamPathTemplate(_downstreamPathTemplate),
|
||||||
_loadBalancerKey,
|
_loadBalancerKey,
|
||||||
|
@ -3,7 +3,7 @@ namespace Ocelot.Configuration.Builder
|
|||||||
public class RouteOptionsBuilder
|
public class RouteOptionsBuilder
|
||||||
{
|
{
|
||||||
private bool _isAuthenticated;
|
private bool _isAuthenticated;
|
||||||
private bool _isAuthorised;
|
private bool _isAuthorized;
|
||||||
private bool _isCached;
|
private bool _isCached;
|
||||||
private bool _enableRateLimiting;
|
private bool _enableRateLimiting;
|
||||||
private bool _useServiceDiscovery;
|
private bool _useServiceDiscovery;
|
||||||
@ -20,9 +20,9 @@ namespace Ocelot.Configuration.Builder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RouteOptionsBuilder WithIsAuthorised(bool isAuthorised)
|
public RouteOptionsBuilder WithIsAuthorized(bool isAuthorized)
|
||||||
{
|
{
|
||||||
_isAuthorised = isAuthorised;
|
_isAuthorized = isAuthorized;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ namespace Ocelot.Configuration.Builder
|
|||||||
|
|
||||||
public RouteOptions Build()
|
public RouteOptions Build()
|
||||||
{
|
{
|
||||||
return new RouteOptions(_isAuthenticated, _isAuthorised, _isCached, _enableRateLimiting, _useServiceDiscovery);
|
return new RouteOptions(_isAuthenticated, _isAuthorized, _isCached, _enableRateLimiting, _useServiceDiscovery);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ocelot.Configuration.Creator
|
namespace Ocelot.Configuration.Creator
|
||||||
{
|
{
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.Configuration.File;
|
using Ocelot.Configuration.File;
|
||||||
|
|
||||||
public class RouteOptionsCreator : IRouteOptionsCreator
|
public class RouteOptionsCreator : IRouteOptionsCreator
|
||||||
@ -8,14 +8,14 @@ namespace Ocelot.Configuration.Creator
|
|||||||
public RouteOptions Create(FileRoute fileRoute)
|
public RouteOptions Create(FileRoute fileRoute)
|
||||||
{
|
{
|
||||||
var isAuthenticated = IsAuthenticated(fileRoute);
|
var isAuthenticated = IsAuthenticated(fileRoute);
|
||||||
var isAuthorised = IsAuthorised(fileRoute);
|
var isAuthorized = IsAuthorized(fileRoute);
|
||||||
var isCached = IsCached(fileRoute);
|
var isCached = IsCached(fileRoute);
|
||||||
var enableRateLimiting = IsEnableRateLimiting(fileRoute);
|
var enableRateLimiting = IsEnableRateLimiting(fileRoute);
|
||||||
var useServiceDiscovery = !string.IsNullOrEmpty(fileRoute.ServiceName);
|
var useServiceDiscovery = !string.IsNullOrEmpty(fileRoute.ServiceName);
|
||||||
|
|
||||||
var options = new RouteOptionsBuilder()
|
var options = new RouteOptionsBuilder()
|
||||||
.WithIsAuthenticated(isAuthenticated)
|
.WithIsAuthenticated(isAuthenticated)
|
||||||
.WithIsAuthorised(isAuthorised)
|
.WithIsAuthorized(isAuthorized)
|
||||||
.WithIsCached(isCached)
|
.WithIsCached(isCached)
|
||||||
.WithRateLimiting(enableRateLimiting)
|
.WithRateLimiting(enableRateLimiting)
|
||||||
.WithUseServiceDiscovery(useServiceDiscovery)
|
.WithUseServiceDiscovery(useServiceDiscovery)
|
||||||
@ -34,7 +34,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
return !string.IsNullOrEmpty(fileRoute.AuthenticationOptions?.AuthenticationProviderKey);
|
return !string.IsNullOrEmpty(fileRoute.AuthenticationOptions?.AuthenticationProviderKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsAuthorised(FileRoute fileRoute)
|
private bool IsAuthorized(FileRoute fileRoute)
|
||||||
{
|
{
|
||||||
return fileRoute.RouteClaimsRequirement?.Count > 0;
|
return fileRoute.RouteClaimsRequirement?.Count > 0;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ namespace Ocelot.Configuration.Creator
|
|||||||
.WithClaimsToHeaders(claimsToHeaders)
|
.WithClaimsToHeaders(claimsToHeaders)
|
||||||
.WithClaimsToClaims(claimsToClaims)
|
.WithClaimsToClaims(claimsToClaims)
|
||||||
.WithRouteClaimsRequirement(fileRoute.RouteClaimsRequirement)
|
.WithRouteClaimsRequirement(fileRoute.RouteClaimsRequirement)
|
||||||
.WithIsAuthorised(fileRouteOptions.IsAuthorised)
|
.WithIsAuthorized(fileRouteOptions.IsAuthorized)
|
||||||
.WithClaimsToQueries(claimsToQueries)
|
.WithClaimsToQueries(claimsToQueries)
|
||||||
.WithClaimsToDownstreamPath(claimsToDownstreamPath)
|
.WithClaimsToDownstreamPath(claimsToDownstreamPath)
|
||||||
.WithRequestIdKey(requestIdKey)
|
.WithRequestIdKey(requestIdKey)
|
||||||
|
@ -31,7 +31,7 @@ namespace Ocelot.Configuration
|
|||||||
List<ClaimToThing> claimsToClaims,
|
List<ClaimToThing> claimsToClaims,
|
||||||
List<ClaimToThing> claimsToPath,
|
List<ClaimToThing> claimsToPath,
|
||||||
bool isAuthenticated,
|
bool isAuthenticated,
|
||||||
bool isAuthorised,
|
bool isAuthorized,
|
||||||
AuthenticationOptions authenticationOptions,
|
AuthenticationOptions authenticationOptions,
|
||||||
DownstreamPathTemplate downstreamPathTemplate,
|
DownstreamPathTemplate downstreamPathTemplate,
|
||||||
string loadBalancerKey,
|
string loadBalancerKey,
|
||||||
@ -69,7 +69,7 @@ namespace Ocelot.Configuration
|
|||||||
ClaimsToClaims = claimsToClaims ?? new List<ClaimToThing>();
|
ClaimsToClaims = claimsToClaims ?? new List<ClaimToThing>();
|
||||||
ClaimsToPath = claimsToPath ?? new List<ClaimToThing>();
|
ClaimsToPath = claimsToPath ?? new List<ClaimToThing>();
|
||||||
IsAuthenticated = isAuthenticated;
|
IsAuthenticated = isAuthenticated;
|
||||||
IsAuthorised = isAuthorised;
|
IsAuthorized = isAuthorized;
|
||||||
AuthenticationOptions = authenticationOptions;
|
AuthenticationOptions = authenticationOptions;
|
||||||
DownstreamPathTemplate = downstreamPathTemplate;
|
DownstreamPathTemplate = downstreamPathTemplate;
|
||||||
LoadBalancerKey = loadBalancerKey;
|
LoadBalancerKey = loadBalancerKey;
|
||||||
@ -102,7 +102,7 @@ namespace Ocelot.Configuration
|
|||||||
public List<ClaimToThing> ClaimsToClaims { get; }
|
public List<ClaimToThing> ClaimsToClaims { get; }
|
||||||
public List<ClaimToThing> ClaimsToPath { get; }
|
public List<ClaimToThing> ClaimsToPath { get; }
|
||||||
public bool IsAuthenticated { get; }
|
public bool IsAuthenticated { get; }
|
||||||
public bool IsAuthorised { get; }
|
public bool IsAuthorized { get; }
|
||||||
public AuthenticationOptions AuthenticationOptions { get; }
|
public AuthenticationOptions AuthenticationOptions { get; }
|
||||||
public DownstreamPathTemplate DownstreamPathTemplate { get; }
|
public DownstreamPathTemplate DownstreamPathTemplate { get; }
|
||||||
public string LoadBalancerKey { get; }
|
public string LoadBalancerKey { get; }
|
||||||
|
@ -2,17 +2,17 @@ namespace Ocelot.Configuration
|
|||||||
{
|
{
|
||||||
public class RouteOptions
|
public class RouteOptions
|
||||||
{
|
{
|
||||||
public RouteOptions(bool isAuthenticated, bool isAuthorised, bool isCached, bool isEnableRateLimiting, bool useServiceDiscovery)
|
public RouteOptions(bool isAuthenticated, bool isAuthorized, bool isCached, bool isEnableRateLimiting, bool useServiceDiscovery)
|
||||||
{
|
{
|
||||||
IsAuthenticated = isAuthenticated;
|
IsAuthenticated = isAuthenticated;
|
||||||
IsAuthorised = isAuthorised;
|
IsAuthorized = isAuthorized;
|
||||||
IsCached = isCached;
|
IsCached = isCached;
|
||||||
EnableRateLimiting = isEnableRateLimiting;
|
EnableRateLimiting = isEnableRateLimiting;
|
||||||
UseServiceDiscovery = useServiceDiscovery;
|
UseServiceDiscovery = useServiceDiscovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsAuthenticated { get; private set; }
|
public bool IsAuthenticated { get; private set; }
|
||||||
public bool IsAuthorised { get; private set; }
|
public bool IsAuthorized { get; private set; }
|
||||||
public bool IsCached { get; private set; }
|
public bool IsCached { get; private set; }
|
||||||
public bool EnableRateLimiting { get; private set; }
|
public bool EnableRateLimiting { get; private set; }
|
||||||
public bool UseServiceDiscovery { get; private set; }
|
public bool UseServiceDiscovery { get; private set; }
|
||||||
|
@ -5,7 +5,7 @@ namespace Ocelot.DependencyInjection
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Ocelot.Authorisation;
|
using Ocelot.Authorization;
|
||||||
using Ocelot.Cache;
|
using Ocelot.Cache;
|
||||||
using Ocelot.Claims;
|
using Ocelot.Claims;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
@ -96,8 +96,8 @@ namespace Ocelot.DependencyInjection
|
|||||||
Services.TryAddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
Services.TryAddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
|
||||||
Services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
|
Services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
|
||||||
Services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
|
Services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
|
||||||
Services.TryAddSingleton<IClaimsAuthoriser, ClaimsAuthoriser>();
|
Services.TryAddSingleton<IClaimsAuthorizer, ClaimsAuthorizer>();
|
||||||
Services.TryAddSingleton<IScopesAuthoriser, ScopesAuthoriser>();
|
Services.TryAddSingleton<IScopesAuthorizer, ScopesAuthorizer>();
|
||||||
Services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
|
Services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
|
||||||
Services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
|
Services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
|
||||||
Services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
|
Services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
NoInstructionsError = 11,
|
NoInstructionsError = 11,
|
||||||
InstructionNotForClaimsError = 12,
|
InstructionNotForClaimsError = 12,
|
||||||
UnauthorizedError = 13,
|
UnauthorizedError = 13,
|
||||||
ClaimValueNotAuthorisedError = 14,
|
ClaimValueNotAuthorizedError = 14,
|
||||||
ScopeNotAuthorisedError = 15,
|
ScopeNotAuthorizedError = 15,
|
||||||
UserDoesNotHaveClaimError = 16,
|
UserDoesNotHaveClaimError = 16,
|
||||||
DownstreamPathTemplateContainsSchemeError = 17,
|
DownstreamPathTemplateContainsSchemeError = 17,
|
||||||
DownstreamPathNullOrEmptyError = 18,
|
DownstreamPathNullOrEmptyError = 18,
|
||||||
|
@ -39,22 +39,22 @@
|
|||||||
public Func<HttpContext, Func<Task>, Task> AuthenticationMiddleware { get; set; }
|
public Func<HttpContext, Func<Task>, Task> AuthenticationMiddleware { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is to allow the user to run any extra authorisation before the Ocelot authentication
|
/// This is to allow the user to run any extra authorization before the Ocelot authentication
|
||||||
/// kicks in
|
/// kicks in
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// <placeholder>This is to allow the user to run any extra authorisation before the Ocelot authentication
|
/// <placeholder>This is to allow the user to run any extra authorization before the Ocelot authentication
|
||||||
/// kicks in</placeholder>
|
/// kicks in</placeholder>
|
||||||
/// </value>
|
/// </value>
|
||||||
public Func<HttpContext, Func<Task>, Task> PreAuthorisationMiddleware { get; set; }
|
public Func<HttpContext, Func<Task>, Task> PreAuthorizationMiddleware { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This allows the user to completely override the ocelot authorisation middleware
|
/// This allows the user to completely override the ocelot authorization middleware
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// <placeholder>This allows the user to completely override the ocelot authorisation middleware</placeholder>
|
/// <placeholder>This allows the user to completely override the ocelot authorization middleware</placeholder>
|
||||||
/// </value>
|
/// </value>
|
||||||
public Func<HttpContext, Func<Task>, Task> AuthorisationMiddleware { get; set; }
|
public Func<HttpContext, Func<Task>, Task> AuthorizationMiddleware { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This allows the user to implement there own query string manipulation logic
|
/// This allows the user to implement there own query string manipulation logic
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
using Ocelot.Responder.Middleware;
|
using Ocelot.Responder.Middleware;
|
||||||
using Ocelot.Security.Middleware;
|
using Ocelot.Security.Middleware;
|
||||||
using Ocelot.Authentication.Middleware;
|
using Ocelot.Authentication.Middleware;
|
||||||
using Ocelot.Authorisation.Middleware;
|
using Ocelot.Authorization.Middleware;
|
||||||
using Ocelot.Cache.Middleware;
|
using Ocelot.Cache.Middleware;
|
||||||
using Ocelot.Claims.Middleware;
|
using Ocelot.Claims.Middleware;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||||
@ -102,23 +102,23 @@
|
|||||||
app.Use(pipelineConfiguration.AuthenticationMiddleware);
|
app.Use(pipelineConfiguration.AuthenticationMiddleware);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The next thing we do is look at any claims transforms in case this is important for authorisation
|
// The next thing we do is look at any claims transforms in case this is important for authorization
|
||||||
app.UseClaimsToClaimsMiddleware();
|
app.UseClaimsToClaimsMiddleware();
|
||||||
|
|
||||||
// Allow pre authorisation logic. The idea being people might want to run something custom before what is built in.
|
// Allow pre authorization logic. The idea being people might want to run something custom before what is built in.
|
||||||
app.UseIfNotNull(pipelineConfiguration.PreAuthorisationMiddleware);
|
app.UseIfNotNull(pipelineConfiguration.PreAuthorizationMiddleware);
|
||||||
|
|
||||||
// Now we have authenticated and done any claims transformation we
|
// Now we have authenticated and done any claims transformation we
|
||||||
// can authorise the request
|
// can authorize the request
|
||||||
// We allow the ocelot middleware to be overriden by whatever the
|
// We allow the ocelot middleware to be overriden by whatever the
|
||||||
// user wants
|
// user wants
|
||||||
if (pipelineConfiguration.AuthorisationMiddleware == null)
|
if (pipelineConfiguration.AuthorizationMiddleware == null)
|
||||||
{
|
{
|
||||||
app.UseAuthorisationMiddleware();
|
app.UseAuthorizationMiddleware();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
app.Use(pipelineConfiguration.AuthorisationMiddleware);
|
app.Use(pipelineConfiguration.AuthorizationMiddleware);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we can run the claims to headers transformation middleware
|
// Now we can run the claims to headers transformation middleware
|
||||||
|
@ -14,8 +14,8 @@ namespace Ocelot.Responder
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errors.Any(e => e.Code == OcelotErrorCode.UnauthorizedError
|
if (errors.Any(e => e.Code == OcelotErrorCode.UnauthorizedError
|
||||||
|| e.Code == OcelotErrorCode.ClaimValueNotAuthorisedError
|
|| e.Code == OcelotErrorCode.ClaimValueNotAuthorizedError
|
||||||
|| e.Code == OcelotErrorCode.ScopeNotAuthorisedError
|
|| e.Code == OcelotErrorCode.ScopeNotAuthorizedError
|
||||||
|| e.Code == OcelotErrorCode.UserDoesNotHaveClaimError
|
|| e.Code == OcelotErrorCode.UserDoesNotHaveClaimError
|
||||||
|| e.Code == OcelotErrorCode.CannotFindClaimError))
|
|| e.Code == OcelotErrorCode.CannotFindClaimError))
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
public class AuthorisationTests : IDisposable
|
public class AuthorizationTests : IDisposable
|
||||||
{
|
{
|
||||||
private IWebHost _identityServerBuilder;
|
private IWebHost _identityServerBuilder;
|
||||||
private readonly Steps _steps;
|
private readonly Steps _steps;
|
||||||
@ -24,7 +24,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
private string _identityServerRootUrl;
|
private string _identityServerRootUrl;
|
||||||
private readonly ServiceHandler _serviceHandler;
|
private readonly ServiceHandler _serviceHandler;
|
||||||
|
|
||||||
public AuthorisationTests()
|
public AuthorizationTests()
|
||||||
{
|
{
|
||||||
_serviceHandler = new ServiceHandler();
|
_serviceHandler = new ServiceHandler();
|
||||||
_steps = new Steps();
|
_steps = new Steps();
|
||||||
@ -41,7 +41,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_response_200_authorising_route()
|
public void should_return_response_200_authorizing_route()
|
||||||
{
|
{
|
||||||
int port = RandomPortFinder.GetRandomPort();
|
int port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_response_403_authorising_route()
|
public void should_return_response_403_authorizing_route()
|
||||||
{
|
{
|
||||||
int port = RandomPortFinder.GetRandomPort();
|
int port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
public class CustomMiddlewareTests : IDisposable
|
public class CustomMiddlewareTests : IDisposable
|
||||||
{
|
{
|
||||||
@ -32,13 +32,13 @@
|
|||||||
{
|
{
|
||||||
var configuration = new OcelotPipelineConfiguration
|
var configuration = new OcelotPipelineConfiguration
|
||||||
{
|
{
|
||||||
AuthorisationMiddleware = async (ctx, next) =>
|
AuthorizationMiddleware = async (ctx, next) =>
|
||||||
{
|
{
|
||||||
_counter++;
|
_counter++;
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var port = RandomPortFinder.GetRandomPort();
|
var port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
||||||
var fileConfiguration = new FileConfiguration
|
var fileConfiguration = new FileConfiguration
|
||||||
@ -73,17 +73,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_call_authorisation_middleware()
|
public void should_call_authorization_middleware()
|
||||||
{
|
{
|
||||||
var configuration = new OcelotPipelineConfiguration
|
var configuration = new OcelotPipelineConfiguration
|
||||||
{
|
{
|
||||||
AuthorisationMiddleware = async (ctx, next) =>
|
AuthorizationMiddleware = async (ctx, next) =>
|
||||||
{
|
{
|
||||||
_counter++;
|
_counter++;
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var port = RandomPortFinder.GetRandomPort();
|
var port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
||||||
var fileConfiguration = new FileConfiguration
|
var fileConfiguration = new FileConfiguration
|
||||||
@ -127,8 +127,8 @@
|
|||||||
_counter++;
|
_counter++;
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var port = RandomPortFinder.GetRandomPort();
|
var port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
||||||
var fileConfiguration = new FileConfiguration
|
var fileConfiguration = new FileConfiguration
|
||||||
@ -172,8 +172,8 @@
|
|||||||
_counter++;
|
_counter++;
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var port = RandomPortFinder.GetRandomPort();
|
var port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
||||||
var fileConfiguration = new FileConfiguration
|
var fileConfiguration = new FileConfiguration
|
||||||
@ -208,17 +208,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_call_pre_authorisation_middleware()
|
public void should_call_pre_authorization_middleware()
|
||||||
{
|
{
|
||||||
var configuration = new OcelotPipelineConfiguration
|
var configuration = new OcelotPipelineConfiguration
|
||||||
{
|
{
|
||||||
PreAuthorisationMiddleware = async (ctx, next) =>
|
PreAuthorizationMiddleware = async (ctx, next) =>
|
||||||
{
|
{
|
||||||
_counter++;
|
_counter++;
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var port = RandomPortFinder.GetRandomPort();
|
var port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
||||||
var fileConfiguration = new FileConfiguration
|
var fileConfiguration = new FileConfiguration
|
||||||
@ -262,8 +262,8 @@
|
|||||||
_counter++;
|
_counter++;
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var port = RandomPortFinder.GetRandomPort();
|
var port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
||||||
var fileConfiguration = new FileConfiguration
|
var fileConfiguration = new FileConfiguration
|
||||||
@ -295,8 +295,8 @@
|
|||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
.And(x => x.ThenTheCounterIs(1))
|
.And(x => x.ThenTheCounterIs(1))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact(Skip = "This is just an example to show how you could hook into Ocelot pipeline with your own middleware. At the moment you must use Response.OnCompleted callback and cannot change the response :( I will see if this can be changed one day!")]
|
[Fact(Skip = "This is just an example to show how you could hook into Ocelot pipeline with your own middleware. At the moment you must use Response.OnCompleted callback and cannot change the response :( I will see if this can be changed one day!")]
|
||||||
public void should_fix_issue_237()
|
public void should_fix_issue_237()
|
||||||
{
|
{
|
||||||
@ -305,14 +305,14 @@
|
|||||||
var httpContext = (HttpContext)state;
|
var httpContext = (HttpContext)state;
|
||||||
|
|
||||||
if (httpContext.Response.StatusCode > 400)
|
if (httpContext.Response.StatusCode > 400)
|
||||||
{
|
{
|
||||||
Debug.WriteLine("COUNT CALLED");
|
Debug.WriteLine("COUNT CALLED");
|
||||||
Console.WriteLine("COUNT CALLED");
|
Console.WriteLine("COUNT CALLED");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
var port = RandomPortFinder.GetRandomPort();
|
var port = RandomPortFinder.GetRandomPort();
|
||||||
|
|
||||||
var fileConfiguration = new FileConfiguration
|
var fileConfiguration = new FileConfiguration
|
||||||
@ -376,8 +376,8 @@
|
|||||||
public class FakeMiddleware
|
public class FakeMiddleware
|
||||||
{
|
{
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly Func<object, Task> _callback;
|
private readonly Func<object, Task> _callback;
|
||||||
|
|
||||||
public FakeMiddleware(RequestDelegate next, Func<object, Task> callback)
|
public FakeMiddleware(RequestDelegate next, Func<object, Task> callback)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
@ -386,10 +386,10 @@
|
|||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
await _next(context);
|
await _next(context);
|
||||||
|
|
||||||
context.Response.OnCompleted(_callback, context);
|
context.Response.OnCompleted(_callback, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
{
|
{
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Authorisation;
|
using Ocelot.Authorization;
|
||||||
using Ocelot.Authorisation.Middleware;
|
using Ocelot.Authorization.Middleware;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||||
@ -18,35 +18,35 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
public class AuthorisationMiddlewareTests
|
public class AuthorizationMiddlewareTests
|
||||||
{
|
{
|
||||||
private readonly Mock<IClaimsAuthoriser> _authService;
|
private readonly Mock<IClaimsAuthorizer> _authService;
|
||||||
private readonly Mock<IScopesAuthoriser> _authScopesService;
|
private readonly Mock<IScopesAuthorizer> _authScopesService;
|
||||||
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
private Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
private Mock<IOcelotLogger> _logger;
|
private Mock<IOcelotLogger> _logger;
|
||||||
private readonly AuthorisationMiddleware _middleware;
|
private readonly AuthorizationMiddleware _middleware;
|
||||||
private RequestDelegate _next;
|
private RequestDelegate _next;
|
||||||
private HttpContext _httpContext;
|
private HttpContext _httpContext;
|
||||||
|
|
||||||
public AuthorisationMiddlewareTests()
|
public AuthorizationMiddlewareTests()
|
||||||
{
|
{
|
||||||
_httpContext = new DefaultHttpContext();
|
_httpContext = new DefaultHttpContext();
|
||||||
_authService = new Mock<IClaimsAuthoriser>();
|
_authService = new Mock<IClaimsAuthorizer>();
|
||||||
_authScopesService = new Mock<IScopesAuthoriser>();
|
_authScopesService = new Mock<IScopesAuthorizer>();
|
||||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||||
_logger = new Mock<IOcelotLogger>();
|
_logger = new Mock<IOcelotLogger>();
|
||||||
_loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
|
_loggerFactory.Setup(x => x.CreateLogger<AuthorizationMiddleware>()).Returns(_logger.Object);
|
||||||
_next = context => Task.CompletedTask;
|
_next = context => Task.CompletedTask;
|
||||||
_middleware = new AuthorisationMiddleware(_next, _authService.Object, _authScopesService.Object, _loggerFactory.Object);
|
_middleware = new AuthorizationMiddleware(_next, _authService.Object, _authScopesService.Object, _loggerFactory.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_call_authorisation_service()
|
public void should_call_authorization_service()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenTheDownStreamRouteIs(new List<PlaceholderNameAndValue>(),
|
this.Given(x => x.GivenTheDownStreamRouteIs(new List<PlaceholderNameAndValue>(),
|
||||||
new DownstreamRouteBuilder()
|
new DownstreamRouteBuilder()
|
||||||
.WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().Build())
|
.WithUpstreamPathTemplate(new UpstreamPathTemplateBuilder().Build())
|
||||||
.WithIsAuthorised(true)
|
.WithIsAuthorized(true)
|
||||||
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
.WithUpstreamHttpMethod(new List<string> { "Get" })
|
||||||
.Build()))
|
.Build()))
|
||||||
.And(x => x.GivenTheAuthServiceReturns(new OkResponse<bool>(true)))
|
.And(x => x.GivenTheAuthServiceReturns(new OkResponse<bool>(true)))
|
||||||
@ -69,7 +69,7 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
private void GivenTheAuthServiceReturns(Response<bool> expected)
|
private void GivenTheAuthServiceReturns(Response<bool> expected)
|
||||||
{
|
{
|
||||||
_authService
|
_authService
|
||||||
.Setup(x => x.Authorise(
|
.Setup(x => x.Authorize(
|
||||||
It.IsAny<ClaimsPrincipal>(),
|
It.IsAny<ClaimsPrincipal>(),
|
||||||
It.IsAny<Dictionary<string, string>>(),
|
It.IsAny<Dictionary<string, string>>(),
|
||||||
It.IsAny<List<PlaceholderNameAndValue>>()))
|
It.IsAny<List<PlaceholderNameAndValue>>()))
|
||||||
@ -79,7 +79,7 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
private void ThenTheAuthServiceIsCalledCorrectly()
|
private void ThenTheAuthServiceIsCalledCorrectly()
|
||||||
{
|
{
|
||||||
_authService
|
_authService
|
||||||
.Verify(x => x.Authorise(
|
.Verify(x => x.Authorize(
|
||||||
It.IsAny<ClaimsPrincipal>(),
|
It.IsAny<ClaimsPrincipal>(),
|
||||||
It.IsAny<Dictionary<string, string>>(),
|
It.IsAny<Dictionary<string, string>>(),
|
||||||
It.IsAny<List<PlaceholderNameAndValue>>())
|
It.IsAny<List<PlaceholderNameAndValue>>())
|
@ -1,4 +1,4 @@
|
|||||||
using Ocelot.Authorisation;
|
using Ocelot.Authorization;
|
||||||
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
using Ocelot.DownstreamRouteFinder.UrlMatcher;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
@ -11,21 +11,21 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
{
|
{
|
||||||
using Ocelot.Infrastructure.Claims.Parser;
|
using Ocelot.Infrastructure.Claims.Parser;
|
||||||
|
|
||||||
public class ClaimsAuthoriserTests
|
public class ClaimsAuthorizerTests
|
||||||
{
|
{
|
||||||
private readonly ClaimsAuthoriser _claimsAuthoriser;
|
private readonly ClaimsAuthorizer _claimsAuthorizer;
|
||||||
private ClaimsPrincipal _claimsPrincipal;
|
private ClaimsPrincipal _claimsPrincipal;
|
||||||
private Dictionary<string, string> _requirement;
|
private Dictionary<string, string> _requirement;
|
||||||
private List<PlaceholderNameAndValue> _urlPathPlaceholderNameAndValues;
|
private List<PlaceholderNameAndValue> _urlPathPlaceholderNameAndValues;
|
||||||
private Response<bool> _result;
|
private Response<bool> _result;
|
||||||
|
|
||||||
public ClaimsAuthoriserTests()
|
public ClaimsAuthorizerTests()
|
||||||
{
|
{
|
||||||
_claimsAuthoriser = new ClaimsAuthoriser(new ClaimsParser());
|
_claimsAuthorizer = new ClaimsAuthorizer(new ClaimsParser());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_authorise_user()
|
public void should_authorize_user()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
||||||
{
|
{
|
||||||
@ -35,8 +35,8 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
{
|
{
|
||||||
{"UserType", "registered"}
|
{"UserType", "registered"}
|
||||||
}))
|
}))
|
||||||
.When(x => x.WhenICallTheAuthoriser())
|
.When(x => x.WhenICallTheAuthorizer())
|
||||||
.Then(x => x.ThenTheUserIsAuthorised())
|
.Then(x => x.ThenTheUserIsAuthorized())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +55,8 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
{
|
{
|
||||||
new PlaceholderNameAndValue("{userId}", "14")
|
new PlaceholderNameAndValue("{userId}", "14")
|
||||||
}))
|
}))
|
||||||
.When(x => x.WhenICallTheAuthoriser())
|
.When(x => x.WhenICallTheAuthorizer())
|
||||||
.Then(x => x.ThenTheUserIsAuthorised())
|
.Then(x => x.ThenTheUserIsAuthorized())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,13 +75,13 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
{
|
{
|
||||||
new PlaceholderNameAndValue("{userId}", "14")
|
new PlaceholderNameAndValue("{userId}", "14")
|
||||||
}))
|
}))
|
||||||
.When(x => x.WhenICallTheAuthoriser())
|
.When(x => x.WhenICallTheAuthorizer())
|
||||||
.Then(x => x.ThenTheUserIsntAuthorised())
|
.Then(x => x.ThenTheUserIsntAuthorized())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_authorise_user_multiple_claims_of_same_type()
|
public void should_authorize_user_multiple_claims_of_same_type()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
||||||
{
|
{
|
||||||
@ -92,21 +92,21 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
{
|
{
|
||||||
{"UserType", "registered"}
|
{"UserType", "registered"}
|
||||||
}))
|
}))
|
||||||
.When(x => x.WhenICallTheAuthoriser())
|
.When(x => x.WhenICallTheAuthorizer())
|
||||||
.Then(x => x.ThenTheUserIsAuthorised())
|
.Then(x => x.ThenTheUserIsAuthorized())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_not_authorise_user()
|
public void should_not_authorize_user()
|
||||||
{
|
{
|
||||||
this.Given(x => x.GivenAClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()))))
|
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", "registered" }
|
||||||
}))
|
}))
|
||||||
.When(x => x.WhenICallTheAuthoriser())
|
.When(x => x.WhenICallTheAuthorizer())
|
||||||
.Then(x => x.ThenTheUserIsntAuthorised())
|
.Then(x => x.ThenTheUserIsntAuthorized())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,19 +125,19 @@ namespace Ocelot.UnitTests.Authorization
|
|||||||
_urlPathPlaceholderNameAndValues = urlPathPlaceholderNameAndValues;
|
_urlPathPlaceholderNameAndValues = urlPathPlaceholderNameAndValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenICallTheAuthoriser()
|
private void WhenICallTheAuthorizer()
|
||||||
{
|
{
|
||||||
_result = _claimsAuthoriser.Authorise(_claimsPrincipal, _requirement, _urlPathPlaceholderNameAndValues);
|
_result = _claimsAuthorizer.Authorize(_claimsPrincipal, _requirement, _urlPathPlaceholderNameAndValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheUserIsAuthorised()
|
private void ThenTheUserIsAuthorized()
|
||||||
{
|
{
|
||||||
_result.Data.ShouldBe(true);
|
_result.Data.ShouldBe(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheUserIsntAuthorised()
|
private void ThenTheUserIsntAuthorized()
|
||||||
{
|
{
|
||||||
_result.Data.ShouldBe(false);
|
_result.Data.ShouldBe(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -46,7 +46,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
|
|
||||||
var expected = new RouteOptionsBuilder()
|
var expected = new RouteOptionsBuilder()
|
||||||
.WithIsAuthenticated(true)
|
.WithIsAuthenticated(true)
|
||||||
.WithIsAuthorised(true)
|
.WithIsAuthorized(true)
|
||||||
.WithIsCached(true)
|
.WithIsCached(true)
|
||||||
.WithRateLimiting(true)
|
.WithRateLimiting(true)
|
||||||
.WithUseServiceDiscovery(true)
|
.WithUseServiceDiscovery(true)
|
||||||
@ -71,7 +71,7 @@ namespace Ocelot.UnitTests.Configuration
|
|||||||
private void ThenTheFollowingIsReturned(RouteOptions expected)
|
private void ThenTheFollowingIsReturned(RouteOptions expected)
|
||||||
{
|
{
|
||||||
_result.IsAuthenticated.ShouldBe(expected.IsAuthenticated);
|
_result.IsAuthenticated.ShouldBe(expected.IsAuthenticated);
|
||||||
_result.IsAuthorised.ShouldBe(expected.IsAuthorised);
|
_result.IsAuthorized.ShouldBe(expected.IsAuthorized);
|
||||||
_result.IsCached.ShouldBe(expected.IsCached);
|
_result.IsCached.ShouldBe(expected.IsCached);
|
||||||
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
|
_result.EnableRateLimiting.ShouldBe(expected.EnableRateLimiting);
|
||||||
_result.UseServiceDiscovery.ShouldBe(expected.UseServiceDiscovery);
|
_result.UseServiceDiscovery.ShouldBe(expected.UseServiceDiscovery);
|
||||||
|
@ -218,7 +218,7 @@
|
|||||||
{
|
{
|
||||||
_result[routeIndex].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_expectedVersion);
|
_result[routeIndex].DownstreamRoute[0].DownstreamHttpVersion.ShouldBe(_expectedVersion);
|
||||||
_result[routeIndex].DownstreamRoute[0].IsAuthenticated.ShouldBe(_rro.IsAuthenticated);
|
_result[routeIndex].DownstreamRoute[0].IsAuthenticated.ShouldBe(_rro.IsAuthenticated);
|
||||||
_result[routeIndex].DownstreamRoute[0].IsAuthorised.ShouldBe(_rro.IsAuthorised);
|
_result[routeIndex].DownstreamRoute[0].IsAuthorized.ShouldBe(_rro.IsAuthorized);
|
||||||
_result[routeIndex].DownstreamRoute[0].IsCached.ShouldBe(_rro.IsCached);
|
_result[routeIndex].DownstreamRoute[0].IsCached.ShouldBe(_rro.IsCached);
|
||||||
_result[routeIndex].DownstreamRoute[0].EnableEndpointEndpointRateLimiting.ShouldBe(_rro.EnableRateLimiting);
|
_result[routeIndex].DownstreamRoute[0].EnableEndpointEndpointRateLimiting.ShouldBe(_rro.EnableRateLimiting);
|
||||||
_result[routeIndex].DownstreamRoute[0].RequestIdKey.ShouldBe(_requestId);
|
_result[routeIndex].DownstreamRoute[0].RequestIdKey.ShouldBe(_requestId);
|
||||||
|
@ -2,7 +2,7 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
{
|
{
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Authorisation.Middleware;
|
using Ocelot.Authorization.Middleware;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.DownstreamRouteFinder;
|
using Ocelot.DownstreamRouteFinder;
|
||||||
@ -38,7 +38,7 @@ namespace Ocelot.UnitTests.Headers
|
|||||||
_postReplacer = new Mock<IHttpResponseHeaderReplacer>();
|
_postReplacer = new Mock<IHttpResponseHeaderReplacer>();
|
||||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||||
_logger = new Mock<IOcelotLogger>();
|
_logger = new Mock<IOcelotLogger>();
|
||||||
_loggerFactory.Setup(x => x.CreateLogger<AuthorisationMiddleware>()).Returns(_logger.Object);
|
_loggerFactory.Setup(x => x.CreateLogger<AuthorizationMiddleware>()).Returns(_logger.Object);
|
||||||
_next = context => Task.CompletedTask;
|
_next = context => Task.CompletedTask;
|
||||||
_addHeadersToResponse = new Mock<IAddHeadersToResponse>();
|
_addHeadersToResponse = new Mock<IAddHeadersToResponse>();
|
||||||
_addHeadersToRequest = new Mock<IAddHeadersToRequest>();
|
_addHeadersToRequest = new Mock<IAddHeadersToRequest>();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using Moq;
|
using Moq;
|
||||||
using Ocelot.Authorisation;
|
using Ocelot.Authorization;
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
using Ocelot.Infrastructure.Claims.Parser;
|
using Ocelot.Infrastructure.Claims.Parser;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
@ -11,18 +11,18 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Ocelot.UnitTests.Infrastructure
|
namespace Ocelot.UnitTests.Infrastructure
|
||||||
{
|
{
|
||||||
public class ScopesAuthoriserTests
|
public class ScopesAuthorizerTests
|
||||||
{
|
{
|
||||||
private ScopesAuthoriser _authoriser;
|
private ScopesAuthorizer _authorizer;
|
||||||
public Mock<IClaimsParser> _parser;
|
public Mock<IClaimsParser> _parser;
|
||||||
private ClaimsPrincipal _principal;
|
private ClaimsPrincipal _principal;
|
||||||
private List<string> _allowedScopes;
|
private List<string> _allowedScopes;
|
||||||
private Response<bool> _result;
|
private Response<bool> _result;
|
||||||
|
|
||||||
public ScopesAuthoriserTests()
|
public ScopesAuthorizerTests()
|
||||||
{
|
{
|
||||||
_parser = new Mock<IClaimsParser>();
|
_parser = new Mock<IClaimsParser>();
|
||||||
_authoriser = new ScopesAuthoriser(_parser.Object);
|
_authorizer = new ScopesAuthorizer(_parser.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -30,7 +30,7 @@ namespace Ocelot.UnitTests.Infrastructure
|
|||||||
{
|
{
|
||||||
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
|
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
|
||||||
.And(_ => GivenTheFollowing(new List<string>()))
|
.And(_ => GivenTheFollowing(new List<string>()))
|
||||||
.When(_ => WhenIAuthorise())
|
.When(_ => WhenIAuthorize())
|
||||||
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
|
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ namespace Ocelot.UnitTests.Infrastructure
|
|||||||
{
|
{
|
||||||
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
|
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
|
||||||
.And(_ => GivenTheFollowing((List<string>)null))
|
.And(_ => GivenTheFollowing((List<string>)null))
|
||||||
.When(_ => WhenIAuthorise())
|
.When(_ => WhenIAuthorize())
|
||||||
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
|
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ namespace Ocelot.UnitTests.Infrastructure
|
|||||||
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
|
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
|
||||||
.And(_ => GivenTheParserReturns(new ErrorResponse<List<string>>(fakeError)))
|
.And(_ => GivenTheParserReturns(new ErrorResponse<List<string>>(fakeError)))
|
||||||
.And(_ => GivenTheFollowing(new List<string>() { "doesntmatter" }))
|
.And(_ => GivenTheFollowing(new List<string>() { "doesntmatter" }))
|
||||||
.When(_ => WhenIAuthorise())
|
.When(_ => WhenIAuthorize())
|
||||||
.Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
|
.Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ namespace Ocelot.UnitTests.Infrastructure
|
|||||||
this.Given(_ => GivenTheFollowing(claimsPrincipal))
|
this.Given(_ => GivenTheFollowing(claimsPrincipal))
|
||||||
.And(_ => GivenTheParserReturns(new OkResponse<List<string>>(allowedScopes)))
|
.And(_ => GivenTheParserReturns(new OkResponse<List<string>>(allowedScopes)))
|
||||||
.And(_ => GivenTheFollowing(allowedScopes))
|
.And(_ => GivenTheFollowing(allowedScopes))
|
||||||
.When(_ => WhenIAuthorise())
|
.When(_ => WhenIAuthorize())
|
||||||
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
|
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ namespace Ocelot.UnitTests.Infrastructure
|
|||||||
this.Given(_ => GivenTheFollowing(claimsPrincipal))
|
this.Given(_ => GivenTheFollowing(claimsPrincipal))
|
||||||
.And(_ => GivenTheParserReturns(new OkResponse<List<string>>(userScopes)))
|
.And(_ => GivenTheParserReturns(new OkResponse<List<string>>(userScopes)))
|
||||||
.And(_ => GivenTheFollowing(allowedScopes))
|
.And(_ => GivenTheFollowing(allowedScopes))
|
||||||
.When(_ => WhenIAuthorise())
|
.When(_ => WhenIAuthorize())
|
||||||
.Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
|
.Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
@ -102,9 +102,9 @@ namespace Ocelot.UnitTests.Infrastructure
|
|||||||
_allowedScopes = allowedScopes;
|
_allowedScopes = allowedScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WhenIAuthorise()
|
private void WhenIAuthorize()
|
||||||
{
|
{
|
||||||
_result = _authoriser.Authorise(_principal, _allowedScopes);
|
_result = _authorizer.Authorize(_principal, _allowedScopes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenTheFollowingIsReturned(Response<bool> expected)
|
private void ThenTheFollowingIsReturned(Response<bool> expected)
|
@ -29,10 +29,10 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(OcelotErrorCode.CannotFindClaimError)]
|
[InlineData(OcelotErrorCode.CannotFindClaimError)]
|
||||||
[InlineData(OcelotErrorCode.ClaimValueNotAuthorisedError)]
|
[InlineData(OcelotErrorCode.ClaimValueNotAuthorizedError)]
|
||||||
[InlineData(OcelotErrorCode.ScopeNotAuthorisedError)]
|
[InlineData(OcelotErrorCode.ScopeNotAuthorizedError)]
|
||||||
[InlineData(OcelotErrorCode.UnauthorizedError)]
|
[InlineData(OcelotErrorCode.UnauthorizedError)]
|
||||||
[InlineData(OcelotErrorCode.UserDoesNotHaveClaimError)]
|
[InlineData(OcelotErrorCode.UserDoesNotHaveClaimError)]
|
||||||
public void should_return_forbidden(OcelotErrorCode errorCode)
|
public void should_return_forbidden(OcelotErrorCode errorCode)
|
||||||
{
|
{
|
||||||
ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.Forbidden);
|
ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.Forbidden);
|
||||||
@ -52,8 +52,8 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
public void should_return_internal_server_error(OcelotErrorCode errorCode)
|
public void should_return_internal_server_error(OcelotErrorCode errorCode)
|
||||||
{
|
{
|
||||||
ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.InternalServerError);
|
ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.InternalServerError);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(OcelotErrorCode.ConnectionToDownstreamServiceError)]
|
[InlineData(OcelotErrorCode.ConnectionToDownstreamServiceError)]
|
||||||
public void should_return_bad_gateway_error(OcelotErrorCode errorCode)
|
public void should_return_bad_gateway_error(OcelotErrorCode errorCode)
|
||||||
@ -104,7 +104,7 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void AuthorisationErrorsHaveSecondHighestPriority()
|
public void AuthorizationErrorsHaveSecondHighestPriority()
|
||||||
{
|
{
|
||||||
var errors = new List<OcelotErrorCode>
|
var errors = new List<OcelotErrorCode>
|
||||||
{
|
{
|
||||||
@ -177,4 +177,4 @@ namespace Ocelot.UnitTests.Responder
|
|||||||
_result.ShouldBe((int)expectedCode);
|
_result.ShouldBe((int)expectedCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user