Ocelot
Ocelot copied to clipboard
Add list of authorization policies to route configuration
New Feature
"ReRoutes": [
{
"AuthorizationPolicies": [ "MyAuthorizationPolicy" ]
The policy would be injected in DI as a standard asp.net service and would only expose a single method called during the PreAuthorizationMiddleware phase:
public interface IAuthorizationPolicy
{
Task<bool> IsAuthorized(DownstreamContext ctx);
}
The pipeline calls all registered policies for the ReRoute and stops if any returns false.
Motivation for New Feature
Provide an easier way to configure additional authorization checks.
Today there is a workaround based on ReRoute Key, but it is far from ideal.
For instance, let's imagine this route:
DELETE http://localhost:7000/users/123/items/456
And this configuration:
{
"ReRoutes": [
{
"Key": "UsersItemsDelete",
"UpstreamPathTemplate": "/users/{userId}/items/{itemId}",
"UpstreamHttpMethod": [ "Delete" ],
"DownstreamPathTemplate": "/items/{itemId}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [ { "Host": "localhost", "Port": 5000 } ],
"RouteClaimsRequirement": { "sub": "{userId}" },
"AuthenticationOptions": {
"AuthenticationProviderKey": "api-key",
"AllowedScopes": [ "openid" ]
}
}
]
}
Notice that /users and /items are located in separate microservices. Still the UI have both userId and itemId and I can expose in the gateway a route mixing both. I first use RouteClaimsRequirement to check that the user accessed in the route is the one calling the api. Then I have this code in Startup to check that he is allowed to acces the item:
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSerilogRequestLogging();
app.UseCors(CorsPolicy);
app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
Func<DownstreamContext, Task<bool>> usersItemsAuthorizationMiddleware = async ctx =>
{
var userId = ctx.TemplatePlaceholderNameAndValues.First(p => p.Name == "{userId}").Value;
var itemId = ctx.TemplatePlaceholderNameAndValues.First(p => p.Name == "{itemId}").Value;
var usersService = app.ApplicationServices.GetService<UsersService>();
// this call the /users microservice to know if given userId can delete itemId
var result = await usersService.IsUserAuthorizedForItem(userId, itemId);
if (!result)
{
ctx.Errors.Add(new UnauthorisedError($"User {userId} does not have access to item {itemId}"));
}
return result;
};
// Configure which route is protected by which policy
// Not ideal... Would be better suited in the ReReoute config in Ocelot.json
var dic = new Dictionary<string, Func<DownstreamContext, Task<bool>>>()
{
{ "UsersItemsDelete" , usersItemsAuthorizationMiddleware },
{ "UsersItemsPut" , usersItemsAuthorizationMiddleware }
};
var conf = new OcelotPipelineConfiguration()
{
PreAuthorisationMiddleware = async (ctx, next) =>
{
if (dic.ContainsKey(ctx.DownstreamReRoute.Key))
{
var result = await dic[ctx.DownstreamReRoute.Key](ctx);
if (!result)
return;
}
await next();
}
};
await app.UseOcelot(conf);
}
Let me know if you need more details or if anything need clarification. Cheers, Romain.
Hi, do you have any feedback on the relevance of this feature request? Should I try a PR, or do you think it would not be worth it? Would consider including and supporting it in Ocelot? Best regards.
@TomPallister any thoughts/opinion on the relevance of this feature request would be appreciated! 😃
Hi Romain! What do you think about #740 #1580 and #1870 ?
@RomainHautefeuille commented on Jun 11, 2020
Tom doesn't develop, he doesn't merge PRs, he doesn't answer in discussion threads, and he doesn't manage this repo anymore since 2020... You need to ask me (repo maintainer) and other team members, see top 3 plz. We might accept your feature request if we are confident it will finally be delivered. But the current team capacity is very low to develop your idea for you.
Will you contribute? Will you create a PR? Will you provide high quality in PRs to make code complete?
Sure we will provide you all required support!
@michaellperry Welcome!
@michaellperry Where are you? Has your intention ended?