Map groups from SAML IDP into Keycloak

I’m trying to test SAML 2.0 functionality in Keycloak using one Keycloak as SP and one Keycloak as a SAML IDP. I have configured the SP and IDP by importing the respective SAML descriptors and I am able to trigger a login using the SAML IDP via the login screen. I have been trying to map properties from the IDP into Keycloak and I have managed to map “email”, “firstName” and “lastName” correctly, but I’m out of ideas on how to map group memberships.

The SAML Response xml contains attributes like below. I’ve tried both with “full path” groups and without. After hours of attempts I also tried to track down something resembling urn:oid values related to group memberships and the best match I found was from https://ldapwiki.com/wiki/1.2.840.113556.1.2.102 but I also made several attempts with only FriendlyName set.

    <saml:AttributeStatement>
      <saml:Attribute FriendlyName="memberOf" Name="urn:oid:1.2.840.113556.1.2.102" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">/MyApp Users</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute FriendlyName="givenName" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Sam</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute FriendlyName="surname" Name="urn:oid:2.5.4.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Luser</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute FriendlyName="email" Name="urn:oid:1.2.840.113549.1.9.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
        <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">samluser@example.com</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>

On the IDP I have created a saml client (which was configured by importing the SAML descriptor from the SP) and I configured the following mappers:

  • “X500 email” (built-in) that maps urn:oid:1.2.840.113549.1.9.1 (“email” as friendly name) to “email” property
  • “X500 givenName” (built-in) that maps urn:oid:2.5.4.42 (givenName) to “firstName” property
  • “X500 surname” (built-in) that maps urn:oid:2.5.4.4 (surname) to “lastName” property
  • “groups”, a Group Mapper using urn:oid:1.2.840.113556.1.2.102 and friendly name “memberOf”

On the SP side the SAML Identity Provider has the following mappers:

  • Attribute Importer for urn:oid:2.5.4.42 (givenName as friendly name) to “firstName” user attribute
  • Attribute Importer for urn:oid:2.5.4.4 (surname as friendly name) to “lastName” user attribute
  • Attribute Importer for urn:oid:1.2.840.113549.1.9.1 (email as friendly name) to “email” user attribute

Those 3 seem to work fine since the user that gets created on-the-fly in the SP Keycloak has those properties set. Finally we have “memberOf” mapper, which is where I’m stuck. This is what I have currently:

  • “memberOf” Attribute Importer for urn:oid:1.2.840.113556.1.2.102 (memberOf as friendly name) to “keycloak.session.realm.users.query.groups” user attribute (I found this magic string by reading Keycloak source code, more specifically UserModel.java)

EXPECTED RESULT
The user that gets created on-the-fly in the Keycloak SP is correctly linked to the groups specified in the SAML response.

ACTUAL RESULT
The on-the-fly created user has no group memberships. The keycloak.session.realm.users.query.groups does shows up under “Attributes” when looking at the details for the user in the Keycloak SP admin console, with values like “MyApp Users##Some Other Group”

This later leads to my application granting 0 permissions to the user since permissions are tied to groups, and the user is then logged out by the application.

QUESTIONS

  • What is the correct way to configure SAML group mapping?
  • Are you aware of some place in Keycloak documentation that documents things like supported urn:oid values and special attribute names like “keycloak.session.realm.users.query.groups”?

Some additional findings:

[KEYCLOAK-19283] Idp: Advanced claim to group mapper - Red Hat Issue Tracker and corresponding pull request KEYCLOAK-19283 Implemented new "Advanced claim to group" idp mapper by artur-baltabayev · Pull Request #8467 · keycloak/keycloak · GitHub very recently added some group mapping capabilities for OIDC IdPs, but this does not cover SAML IdPs.

I have found a dirty and somewhat painful way to deal with this problem but it would be very nice to have something better than the workaround below:

  • As mentioned in the original post the SAML group memberships end up being saved as a “user attribute” in the Keycloak SP
  • It is possible to create a mapper for each relevant client in Keycloak so that it takes that particular custom attribute and maps it to a new JWT claim, e.g. a “groups_saml” claim.
  • Then you’d need to fix all surrounding applications to support aggregating group memberships from multiple JWT claims (i.e. “groups” and “groups_saml” claims rather than a single “groups” claim).

I could not map the user attribute to the existing “groups” claim I had because the User Attribute mapper and the normal “Group Membership” mapper would overwrite each other rather than appending to the same JWT claim array.

I have encountered a similar thing, although the groups presented in the SAML was different than the claims in your example. I found that in order to map directly to Keycloak groups, I had to build a custom mapper. It was fairly simple to extend AbstractIdentityProviderMapper and then sync the groups in the importNewUser and updateBrokeredUser methods.