Getting Group Claims With ADFS 4.0 OAuth2 Token

2020-06-25 09:17发布

问题:

I successfully set up an ADFS 4.0 instance (Windows Server 2016) which I intend to use to authenticate and authorize the users of a single-page application towards a WebApi.

I pretty much followed this tutorial: https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/development/single-page-application-with-ad-fs .. which is modifying a sample that uses Azure Active Directory.

Now.. all seems to work fine, I can get a basic JWT token from the /oauth2/authorize endpoint:

{
  "aud": "d668d637-7fd4-45ef-9eab-46fee230dcbc",
  "iss": "https://fs.contoso.com/adfs",
  "iat": 1494341035,
  "exp": 1494344635,
  "auth_time": 1494341035,
  "nonce": "c91e3f78-c31a-402e-a685-8d1586915227",
  "sub": "Rl7sOj0nDbgh8BVWZegrkvgAKaB/SwNuEbmORcWcae4=",
  "upn": "john.doe@contoso.com",
  "unique_name": "CONTOSO\\JohnDoe"
}

The token from AzureAD contained more properties, particularly family_name and given_name. But I was also hoping to add explicit group claims to the token. I thought I should be able to make this happen by setting the 'Issuance Transform Rules' correctly in the Web application Properties ( Application Groups -> MyApp -> MyApp - WebApplication -> Properties). However, it seems no matter what I do, nothing seems to have any effect on the properties contained in the JWT returned from the endpoint. I always get exactly the same token structure.

I am not really sure how the 'Outgoing Claims' map to the token properties as nothing except the 'UPN' and the 'unique name' seems to be transferred. Any pointers what I may be doing wrong here?

回答1:

As indicated in nzpcmad's answer, it appears that custom claims in the id_token using the default URL-parameter-encoded GET redirect is simply not supported. The reason for this may be that there is an URL length limit, but I find that quite questionable.

Anyway, apparently this restriction does not apply when the token is returned in a POST redirect. That's also why people describe it working just fine for MVC applications.

So I was able to work around the problem by redirecting the response to a backend API endpoint (POST), which just redirects it to the frontend (SPA) again, but as a GET request with URL-endcoded parameters:

public class LoginController : ApiController
{
    [HttpPost]
    [Route("login")]
    public HttpResponseMessage Login(FormDataCollection formData)
    {
        var token = formData["id_token"];
        var state = formData["state"];
        var response = Request.CreateResponse(HttpStatusCode.Moved);
        var frontendUri = ConfigurationManager.AppSettings["ad:FrontendUri"];
        response.Headers.Location = new Uri($"{frontendUri}#id_token={token}&state={state}");
        return response;
    }
}

Note that to change the response method from GET to POST, one simply has to add &response_mode=form_post to the OAuth request URL.



回答2:

Windows Server 2016 is ADFS 4.0.

SPA uses OAuth implicit flow and there are a number of posts around this suggesting that this flow doesn't allow extra claims, especially if you are using ADAL.

e.g. ADFS 4.0, Adal JS - No claims.