Search code examples
single-sign-onidentityserver3claims

SSO with application specific claim roles and authorization


Here's the situation: I'm trying to integrate SSO into an existing .NET Webform/MVC/WebApi environment using IdentiyServer3. Because there's no centralized role management, SSO is for identity only. Each application handles its own role and authorization. Also can't demand too much changes, so all the IsInrole, Authorize(Role="") and Web.Config role stuff have to work.

The question is: where do I stuff the claim/role? I tried add it like the following, but then two applications start seeing each other's roles. Doesn't sound right.

Notifications = new OpenIdConnectAuthenticationNotifications {
SecurityTokenValidated = async n =>  {
    var id = n.AuthenticationTicket.Identity;
    var nid = new ClaimsIdentity(id.AuthenticationType,
        ClaimTypes.Email, ClaimTypes.Role);

    nid.AddClaim(id.FindFirst(ClaimTypes.Email));
    nid.AddClaim(new Claim(ClaimTypes.Role, "admin"));

Did I miss something important? Sorry if it sounds too stupid. I'm too new to know better, and there's not enough good keywords to narrow it down on the web.

In summary, I need a SSO solution where each client handles its own role claim and authorization. Thanks


Solution

  • Wait a second, I think this earlier version of IdentityModel.Owin.ClaimsTransformation is exactly what I did. Mine is not as polished of course.

    I just wasn't sure replacing Authentication.User like this is safe.

    var transformedPrincipal = await _options.ClaimsTransformation(context.Authentication.User);
    context.Authentication.User = new ClaimsPrincipal(transformedPrincipal);
    

    Update:

    Ended up customize the ClaimsTransformation middleware above from

     public Func<ClaimsPrincipal, Task<ClaimsPrincipal>> ClaimsTransformation { get; set; }
    

    to

     public Func<string, Task<List<Claim>> ClaimsTransformation { get; set; }
    

    feed a ICustomClaimProvider to it, which return a list of user claims by id from database. Then instead of

    context.Authentication.User = new ClaimsPrincipal(transformedPrincipal);
    

    this

    context.Authentication.User.AddIdentity(new ClaimsIdentity(claims, "appid"));
    

    Now User has two identities, one original, one contains application specific claims. Seems working well if I understand it correctly.