2

I have a client that has access to 2 scopes from 2 different resources. Each scope has it's own claims. However, I'm noticing that ALL claims from both scopes are being returned to each resource. How can I ensure that only claims related to correct scope are returned to the resource?

Here's what I have in my Resource on Startup:

//I use IdentityServer3.AccessTokenRequest since my resource is a .net app

public void Configuration(IAppBuilder app)
{
    app.UseIdentityServerBearerTokenAuthentication(new identityServerBearerTokenAuthenticationOptions
    {
        Authority = URLToIdentityServer,
        RequiredScopes = new[] { "SomeAPI.read" } //Notice this is scope we want claims for.
    });  

    //Some other stuff
}

And Here's what I have in identity server:

public static IEnumerable<Client> GetClients()
{
        return new List<Client>
        {
            new Client
            {
                ClientId = "ClientId",
                ClientName = "Client Name",
                ClientSecrets = new List<Secret> {new Secret("SuperSecret".Sha256())}, 
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                AllowedScopes = new List<string> {"SomeAPI.read", "OtherAPI.write"},  //Notice client has access to 2 scopes from 2 resources.
                Claims = claims
            }
        };
}

private static ICollection<Claim> claims = new List<Claim>
{
        new Claim("Claim1", "Value1"), //Belongs to scope "SomeAPI.read"
        new Claim("Claim2", "Value2"), //Belongs to scope "SomeAPI.read"
        new Claim("Claim3", "Value3"), //Belongs to scope "OtherAPI.write"
        new Claim("Claim4", "Value4"), //Belongs to scope "OtherAPI.write"
};

Just in case you're wondering how the resources & scopes are declared:

public static IEnumerable<ApiResource> GetApiResources()
{
        return new List<ApiResource>
        {
            new ApiResource
            {
                Name = "SomeAPI",
                DisplayName = "Some API",
                Description = "This is the resource which we expect 2 claims for, but get 4",
                ApiSecrets = new List<Secret> {new Secret("ScopeSecret".Sha256())},
                Scopes = new List<Scope>
                {
                    new Scope("SomeAPI.read", readClaimTypes),
                },
                Enabled = true,
            },

            new ApiResource
            {
                Name = "OtherAPI",
                DisplayName = "Other API",
                Description = "Another API that also has a scope with 2 claims and we don't want to get these claims back in the resource they don't belong to",
                ApiSecrets = new List<Secret> {new Secret("SomeOtherSecret".Sha256())},
                Scopes = new List<Scope>
                {
                        new Scope("OtherAPI.write", writeClaimTypes)
                },
                Enabled = true,
            }
        };
}

private static IEnumerable<string> readClaimTypes = new List<string> {"claim1", "claim2"};
private static IEnumerable<string> writeClaimTypes = new List<string> {"claim3", "claim4"}; 
}

With this configuration, I would expect my resource to only get the first 2 claims. But it gets all 4. Any help would be appreciated.

ArdAtak
  • 239
  • 2
  • 4
  • 17
  • When you say the resource is getting all claims. Do you mean that each API is seeing all of the claims when you access an API call? – aaronR Mar 08 '18 at 21:34
  • Correct. When I examine the User (Prinicipal) claims in protected resource / web api (in this case "SomeAPI"), I see that all 4 claims are present. I had assumed that when the api calls identity service to validate the client's access token, that the claims coming back would get filtered by the scope that they belong to. – ArdAtak Mar 08 '18 at 22:05
  • Os that really an issue seeing all of the users claims? – aaronR Mar 08 '18 at 22:06
  • No it's personally not an issue for me although it represents potential scale issues in the long run (if your id server is being used by many resources, which is not realistic for us). I'm mainly trying to accomplish this to prove it can be done to avoid a complete revamp of our authentication process. I also realize I'm fudging the lines between authorization and authentication here. – ArdAtak Mar 08 '18 at 22:10
  • The users claims would only include those claims for the resources the client requested access to. Make sure you are not including claims in the access token. That way they are only in the id token. – aaronR Mar 08 '18 at 22:13

1 Answers1

2

It seems that this behaviour is by design. If you take a look at the documentation:

Claims: Allows settings claims for the client (will be included in the access token).

I've tried to vary with the configuration, but that didn't fix it. I've also tried the following with the ProfileService. But this is not the way!

public class ProfileService : IProfileService
{
    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        // DO NOT USE!!!
        if (context.Caller == "ClaimsProviderAccessToken")
        {
            var claims = context.Client.Claims
                         .Where(c => context.RequestedClaimTypes.Contains(c.Type)).ToList();

            // Replace the list. This overwrites the in memory collection!
            // This will eventually result in an empty list for all tokens.
            // The collection may not be altered!
            context.Client.Claims = claims;
        }
    }
}

The only way to change the behaviour is to dive into the code and add a filter there, without changing the collection.

  • 1
    Thanks. In the end I decided to do the right thing and let identity server only worry about authentication. Each protected app / resource will make a separate ping to the DB to the get the relevant claims based on the users client id. It was the right thing to do but I wanted to see if I could be lazy and do both in one call. – ArdAtak Apr 16 '18 at 16:40