Ocelot icon indicating copy to clipboard operation
Ocelot copied to clipboard

Add list of authorization policies to route configuration

Open RomainHautefeuille opened this issue 4 years ago • 6 comments

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.

RomainHautefeuille avatar Mar 20 '20 14:03 RomainHautefeuille

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.

RomainHautefeuille avatar Apr 20 '20 16:04 RomainHautefeuille

@TomPallister any thoughts/opinion on the relevance of this feature request would be appreciated! 😃

RomainHautefeuille avatar Jun 11 '20 13:06 RomainHautefeuille

Hi Romain! What do you think about #740 #1580 and #1870 ?

raman-m avatar Jan 26 '24 12:01 raman-m

@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!

raman-m avatar Jan 26 '24 12:01 raman-m

@michaellperry Welcome!

raman-m avatar Feb 22 '24 16:02 raman-m

@michaellperry Where are you? Has your intention ended?

raman-m avatar Mar 23 '24 12:03 raman-m

You have the right to reopen this issue in the future if you come with a PR ready

raman-m avatar Jun 15 '24 11:06 raman-m