User groups as claims through OpenID Connect over ADFS
Asked Answered
S

4

6

I need help in figuring out how I can get a user's assigned groups via OpenID Connect over ADFS (Windows Server 2016). I am currently able to authenticate a user and get the user info including the access_token. When I inspect the JWT-token I can see all of the default claims in there. What I want is to add all of the users' assigned system groups to the claims as an array of strings, but I have no idea of how to accomplish this. ADFS and Windows Server is a beast and all of the search results from Google is not leading me in the right direction. All of the articles I find is kinda useless since they're either incomplete in the steps or hard to follow if you're not educated in the whole ADFS-shebang.

I have been stuck at this problem for a couple of days now and need some help, hopefully there's someone out there with knowledge about this.

What I've done so far:

  1. I have added an application group to ADFS which contains a "Server Application" and a "Web API".
  2. I have added a user group called Admin and assigned that to a user called max.
  3. I can login through OpenID Connect over ADFS and get the user info from the userinfo-endpoint.
  4. I have been able to decode the access_token to access the claims.

I'm currently authenticating with the scopes "openid", "email" and "profile".

Shimmy answered 3/4, 2019 at 11:43 Comment(0)
S
20

We just got everything working so I just thought I'd share what we did if anyone else wants to do what we did.

Prerequisites

To be able to follow the steps below you'll need to have Windows Server 2016 or later with the "Active Directory Federation Services (ADFS)" feature enabled.

Add a OpenID Connect configuration to ADFS

  1. Open the "AD FS Management" tool located under the "Tools" menu at the top right of the Server Manager.
  2. Select the "Application Groups" folder item in the left sidebar.
  3. Click on "Add Application Group..." in the sidebar to the right.
  4. Give the application group a name, for example "OpenID Connect"
  5. Select the "Server application accessing a web API" list item and click next.
  6. Copy and paste the Client Identifier to a text file for later use.
  7. Enter the your authentication "Redirect URI" and Click next.
  8. Tick the "Generate a shared secret" box. Copy and paste the Secret to a text for use with your application. Click next.
  9. Paste and add the Client Identifier (from step 6) as the "Identifier". Click next.
  10. Select the access control policy you'd like to use and click next.
  11. Make sure the box next to "openid" is ticked.
  12. Click the "New scope..." button in the bottom and and give it the name "allatclaims", click OK. This scope is needed to provide additional information as claims, such as the the user's groups.
  13. Finish the wizard.

Configure OpenID Connect to provide user groups as claims

  1. Open the "AD FS Management" tool located under the "Tools" menu at the top right of the Server Manager.
  2. Select the "Application Groups" folder item in the left sidebar.
  3. Double click on the group added earlier, then double click on the "Web API" application.
  4. Select the tab named "Issuance Transform Rules".
  5. Click the "Add Rule..." button at the bottom.
  6. Select "Send LDAP Attributes as Claims" and click next.
  7. Give the rule a name, for example "Roles".
  8. Select "Active Directory" as the "Attribute Store".
  9. In the table below, select "Token-Groups Unqualified Names" in the first column and type "roles" into the second column.

Configure OpenID Connect to provide specific user groups as claims

  1. Open the "AD FS Management" tool located under the "Tools" menu at the top right of the Server Manager.
  2. Select the "Application Groups" folder item in the left sidebar.
  3. Double click on the group added earlier, then double click on the "Web API" application.
  4. Select the tab named "Issuance Transform Rules".
  5. Remove any rules you may have already added.
  6. Click the "Add Rule..." button at the bottom.
  7. Select "Send Claims Using a Custom Rule" and click next.
  8. Give the rule the name "StoreRoles" and paste the following into the "Custom rule" field:
  9. Click finish and add yet another rule.
  10. Again, select "Send Claims Using a Custom Rule" and click next.
  11. Give this rule the name "IssueRoles" and paste the following into the "Custom rule" field:
    • c:[Type == "roles", Value =~ "^Prefix.+"] => issue(claim = c);
  12. The part containing //"^Prefix.+"// is a regex expression used to filter the windows groups sent as part of the claims. In this case we only accept the windows groups starting with "Prefix". Adjust this to meet your needs.
  13. Click finish.
Shimmy answered 8/4, 2019 at 9:32 Comment(2)
Very helpful post!Bullet
@Max Fahl, Do you need to make any sepecific changes to the oAuth authentication flow? I tested with different flows, different setups but I never get anything different back in the ID token other then the default information.Evelunn
E
3

Ooh wow, after 4 weeks searching, testing and debugging I finally get the Groups back on ADFS4.0 (AD FS 2019 server);

The documentation is totally crap so, here you go guys. Big thanks to @Max Fahl

  1. Create a Server Application
  2. Create a Web API
  3. Add the Client ID from step 1 as 'Relying party identifier' in the Web API
  4. Create the 3 rules Max described (Web API)
  5. Check 'Allatclaims, openid, profile' in Claims Permissions (Web API)

Now you can use oAuth to authenticate the user through ADFS.

Make sure you use this;

        //Store state in session
        $state = uniqid("adfs-oauth");

        $params = [
            "client_id" => $this->adfs_config["client_id"],
            "response_type" => "code",
            "redirect_uri" => $this->adfs_config["redirect_uri"],
            "state" => $state,
            "response_mode" => "form_post",
        ];

Then exchange the code for an access token;

"client_id" => $this->adfs_config["client_id"],
            "client_secret" => $this->adfs_config["client_secret"],
            "redirect_uri" => $this->adfs_config["redirect_uri"],
            "grant_type" => "authorization_code",
            "code" => $request->get("code")

Now you receive the Access Token, Refresh Token and ID_Token.

Example: ABCDABCDABCDABCDABCDABCDABCDABCD.ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD.ABCDABCDABCDABCDABCDABCD

Split the Token by the '.' (DOT). You now have 3 parts. The second part holds the information (index 1). Base 64 decode this string and you get the JSON data.

    array (
  'aud' => '53a****-8a5e-415b-**e4-37****65edd5',
  'iss' => 'https://*******.northeurope.cloudapp.azure.com/adfs',
  'iat' => 1623407419,
  'nbf' => 1623407419,
  'exp' => 1623411019,
  'auth_time' => 1623397846,
  'sub' => '**********************',
  'upn' => '[email protected]',
  'unique_name' => 'ADFS_DOMAIN\\developer',
  'sid' => 'S-1-5-21-******-3146660372-******-1112',
  'Roles' =>
  array (
    0 => 'Legal',
    1 => 'Administrator',
    2 => 'Users',
  ),
  'apptype' => 'Confidential',
  'appid' => '53a****-8a5e-415b-**e4-37****65edd5',
  'authmethod' => 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport',
  'ver' => '1.0',
)
Evelunn answered 11/6, 2021 at 10:38 Comment(0)
D
0

You could use web browser accessing web application.

This gives you access to the claims rules - as does the web API in your example.

Then use a LDAP rule with one of the "Token-Groups" options e.g. "Unqualified" and map this to a type of "Role".

This will add all the groups to the token, one Role claim per group.

Director answered 3/4, 2019 at 18:51 Comment(2)
Thanks for your answer! I've added a mapping from "Token-Groups - Unqualified Names" to "Role" in the "Issuance Transform Rules" tab of my Web API Application. I can still not see the Role claim in the response. I guess it's supposed to be in the access_token data? What can I be missing here? Do I have to add any additional scopes? The thing is, I can't seem to get the user's email or anything at the moment.Shimmy
it seems I hadn't added the Server Application's Client ID correctly to the "Relying Party Trusts" in the Web API. Now it seems to be working :)Shimmy
S
0

Define a custom rule with this content to send all groups as role

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"] => issue(store = "Active Directory", types = ("role"), query = ";tokenGroups(domainQualifiedName);{0}", param = c.Value);

Sidoon answered 14/7, 2021 at 19:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.