ThreeMammals / Ocelot

.NET API Gateway
https://www.nuget.org/packages/Ocelot
MIT License
8.35k stars 1.63k forks source link

AllowedScopes not working as expected with integrating with OpenIddict Auth Server #2177

Open hosamyousof opened 2 days ago

hosamyousof commented 2 days ago

Expected Behavior

The quote from the documentation: Authentication | Allowed Scopes

If you add scopes to AllowedScopes, Ocelot will get all the user claims (from the token) of the type scope and make sure that the user has at least one of the scopes in the list.

Actual Behavior

Validating one scope is not working and return 403 Forbidden. The user access token has permission to two scopes 'InfraAPIs AdminAPIs' and I want to validate the InfraAPIs scope only in the rule in ocelot.json like:

{
  "DownstreamPathTemplate": "/log/{url}",
  "DownstreamScheme": "https",
  "DownstreamHostAndPorts": [
    {
      "Host": "localhost", "Port": 5004
    }
  ],
  "UpstreamPathTemplate": "/log/{url}",
  "UpstreamHttpMethod": [ "Get", "Post" ],
  "AuthenticationOptions": {
    "AuthenticationProviderKey": "OpenIddict.Validation.AspNetCore",
    "AllowedScopes": ["InfraAPIs"]
  }

Error log message from ocelot:

warn: Ocelot.Responder.Middleware.ResponderMiddleware[0]
      requestId: 0HN7E54RBBKV6:00000003, previousRequestId: No PreviousRequestId, message: 'Error Code: ScopeNotAuthorizedError Message: no one user scope: 'InfraAPIs AdminAPIs' match with some allowed scope: 'InfraAPIs' errors found in ResponderMiddleware. Setting error response for request path:/log/App/UpdateAPIAppLastConnectionDate, request method: POST'

OpenIddict validation handler configuration in program.cs:

// Add services to the container.
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
});

// Register the OpenIddict validation components.
builder.Services.AddOpenIddict()
    .AddValidation(options =>
    {
        // Note: the validation handler uses OpenID Connect discovery
        // to retrieve the address of the introspection endpoint.
        options.SetIssuer("https://localhost:5001/");
        //options.AddAudiences("rs_SubscriptionAPI");

        //either user clientid and client secret or AddEncryptionKey to be used for validation

        // Configure the validation handler to use introspection and register the client
        // credentials used when communicating with the remote introspection endpoint.
        //options.UseIntrospection()
        //        .SetClientId("rs_SubscriptionAPI")
        //        .SetClientSecret("SubscriptionAPISecret");

        // Register the encryption credentials. This sample uses a symmetric
        // encryption key that is shared between the server and the Api2 sample
        // (that performs local token validation instead of using introspection).
        //
        // Note: in a real world application, this encryption key should be
        // stored in a safe place (e.g in Azure KeyVault, stored as a secret).
        options.AddEncryptionKey(new SymmetricSecurityKey(
            Convert.FromBase64String("<EncryptionKey>")));

        // Register the System.Net.Http integration.
        options.UseSystemNetHttp();

        // Register the ASP.NET Core host.
        options.UseAspNetCore();
    });

If I set all the scopes it's working but I want only to set one scope for the rule in ocelot.json.

Steps to Reproduce the Problem

Use the provided configuration and make call to endpoint.

Specifications

hosamyousof commented 2 days ago

@raman-m can you please help resolve this?

raman-m commented 1 day ago

OpenIddict -> https://github.com/openiddict/openiddict-core

We do not use this Auth provider and have not tested it, so we cannot assist with its integration. Our core services are thoroughly tested with the IdentityServer4 provider only. It is possible that our core auth services do not support the models of your Auth provider.

no one user scope: 'InfraAPIs AdminAPIs' match with some allowed scope: 'InfraAPIs'

This error is generated by this line of code: https://github.com/ThreeMammals/Ocelot/blob/ce0227c059f220761acc2d880e554174bdb3c544/src/Ocelot/Authorization/ScopesAuthorizer.cs#L38 This implies that the matchesScopes collection is empty following the intersection. It would be beneficial to debug the following line accordingly: https://github.com/ThreeMammals/Ocelot/blob/ce0227c059f220761acc2d880e554174bdb3c544/src/Ocelot/Authorization/ScopesAuthorizer.cs#L24 It appears that the _claimsParser service is parsing the data from the OpenIddict token incorrectly. Could you debug it?

raman-m commented 20 hours ago

@hosamyousof Hosam, why have you been silent?

hosamyousof commented 20 hours ago

Thanks @raman-m, I will try to debug it and get back to you.