1

I am currently implementing an Identity Server solution and I needed some help with the IProfileService and how it works exactly.

It exposes a method called "GetProfileDataAsync". I understand that this is called when IS4 returns a token. So that means the person gets to the login screen, inputs his details, and then before IS4 returns an Identity token and an Access token, this method will get called to add additional claims.

I am currently trying to figure out the best way to implement roles and permissions based authorization. Currently I need to have access to both the permissions and roles that the user has assigned as that is what our existing code does and we are just switching our authentication model to IS4 but keeping the User Management to be as it currently is.

Questions then...

  1. How best do I implement it? I currently have an ApplicationUser class which implements IIdentity. So should I add a list of roles in there and then a list of permissions, and then populate it when I go get it from the DB when the user does a LogIn?

E.G. In this method ApplicationUser user = await _userRepo.FindByUsername(model.Username);

The alternative is to add each role and each permission as a claim in my UserProfileService, specifically in the method below
public virtual async Task GetProfileDataAsync(ProfileDataRequestContext context)

  1. I read the following

    Often IdentityServer requires identity information about users when creating tokens or when handling requests to the userinfo or introspection endpoints. By default, IdentityServer only has the claims in the authentication cookie to draw upon for this identity data. It is impractical to put all of the possible claims needed for users into the cookie, so IdentityServer defines an extensibility point for allowing claims to be dynamically loaded as needed for a user. This extensibility point is the IProfileService and it is common for a developer to implement this interface to access a custom database or API that contains the identity data for users.

With the above situation, as I have implement the IProfileService, does that mean that all claims that are loaded will be automatically returned and put into the Identity/Access token? Does that mean that for every request that is made to the API, my application will be sending in a token (in the cookie) which could get quite big with these claims that include roles and permissions? What is the alternative as the above statement from the IS4 website mentions it is impractical

Kan
  • 25
  • 6

1 Answers1

2

How best do I implement it? I currently have an ApplicationUser class which implements IIdentity. So should I add a list of roles in there and then a list of permissions, and then populate it when I go get it from the DB when the user does a LogIn?

There is two kind of things here, Roles and Permissions. Roles are data and you can add them to the token and pass to clients and APIs. you can save the Roles in DB any how which fits your design. To have the roles in the token you need to fetch them in ProfileService and add to token. Sth like this:

public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        context.IssuedClaims.AddRange(context.Subject.Claims);

        var user = await _userManager.GetUserAsync(context.Subject);

        var roles = await _userManager.GetRolesAsync(user);

        foreach (var role in roles)
        {
            context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role, role));
        }
    }

After doing this your token should contains the roles. make sure to verify the token on https://jwt.ms/

But Permissions are more of real time calculation things.We need to decide about permissions on API based on the user info, user's role or any other data available. For example a user may have the role as delete (means user can delete things). If this user call order API and tries to delete some one else's order it has to be declined. Means delete permission MUST be calculated based on user's ID + user's role + Order's owner ID.

With the above situation, as I have implement the IProfileService, does that mean that all claims that are loaded will be automatically returned and put into the Identity/Access token? Does that mean that for every request that is made to the API, my application will be sending in a token (in the cookie) which could get quite big with these claims that include roles and permissions? What is the alternative as the above statement from the IS4 website mentions it is impractical

Yes the profile service is called whenever IDS4 needs to return claims about a user to a client applications. If you request an identity and access token - it will get called twice (since you might be putting different claims into each token type).

What is the alternative as the above statement from the IS4 website mentions it is impractical

You should just fetch the data that you need - not extra. As I mentioned above permissions should be calculated on the fly and not be in the token. Also you can use cache in the ProfileService. But if you use cache you are the one responsible to manage in your code.

nahidf
  • 2,260
  • 1
  • 15
  • 22
  • So does that mean we wouldn't be able to process Permissions in an "Authorize" tag? And when it coms to Roles, if it is to be cached, then is there any use of it being in a token as that would make the token a bit bigger? When the user is loaded in the ProfileService, could I just get the Roles (and maybe even Permissions) and then cache them? – Kan Dec 10 '20 at 09:19
  • And another question, how would the caching work in a load balanced environment? I can imagine if Server1 was hit, then the roles/permissions would be cached over there, but then hitting Server2 would need to cache them again I assume? Or would you try to setup a cache on the load balancer? – Kan Dec 10 '20 at 09:19
  • We add roles in token in favour of: 1. having a unified user management system which is responsible to fetch user's data 2. Fetch roles once and use it in all clients and apis - (But if you can achieve these goals by any other way that would be fine too) - you can use cache like any other solutions just to optimize - As I mentioned permissions are to be calculated unless you mean claims which are ok to be added to token – nahidf Dec 10 '20 at 16:10
  • you can process some of permissions in Authorize attribute, like the role, and if user is authenticated or have a certain claim. But actual permission check which may depends to each API input must be calculated on the API itself – nahidf Dec 10 '20 at 16:12
  • you can use distributed caching solutions in load balanced environments, read more here https://learn.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-5.0 – nahidf Dec 10 '20 at 16:13