javaspringspring-securitykeycloakjdbcrealm

How to read/import the roles from an external IDP into Keycloak


I have a spring boot application secured with Keycloak 11.0.2, and my Keycloak setup is as follows:

The second realm is an IDP of the first. So to login a user goes to the Central login page and selects the IDP SpringAppIDP.

The IDP configuration is as follows:

On the Spring side, I have the following properties worth mentioning:

server.port                         = 8000
keycloak.realm                      = Central
keycloak.auth-server-url            = http://localhost:8080/auth
keycloak.ssl-required               = external
keycloak.resource                   = SpringWeb
keycloak.public-client=true

keycloak.security-constraints[0].authRoles[0]=WebUser
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/services/*

When I access http://127.0.0.1:8080/services I got redirected to the Keycloak Central Realm Login page, then I click the SpringAppIDP and enter the username springuser and its password. The login is successful, but I got an access denied, which means that the user springuser does not have the role WebUser. However, that role was assigned to that user within the second realm (i.e., SpringApp).

Interestingly, if in the first Realm I create an identity provider Mapper External Role to Role (in the IDP SpringAppIDP configuration) mapping the external role of WebUser to the CentralWebUser and change the spring properties to :

keycloak.security-constraints[0].authRoles[0]=CentralWebUser
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/services/*

I am able to login, which means that Keycloak knew that the user had the WebUser role, hence mapping that role to the CentralWebUser role.

I would like to know if it is possible to explicitly import the roles from an external IDP into an internal one? Or if (and how) can I request a token on behalf of the user that would have that users' roles from both the Central and SpringWeb Realm in the that token, without having to explicitly create a Role Mapper for each user role.


Solution

  • I would like to know if it is possible to explicitly import the roles from an external IDP into an internal one? Or if (and how) can I request a token in behalf to the user that would have that users' roles from both the Central and SpringWeb Realm in the that token, without having to explicitly creating a Role Mapper for each user role.

    Without explicitly creating a Role Mapper for each user role, the only solution that I have found was to extend the Keycloak code; which comes with obvious downsides.

    In retrospect, it actually makes sense that Keycloak does not offer out-of-the-box a way of automatically importing all the roles from the external IDP. For instance, if I am using Google as an external IDP why should my internal IDP (i.e., Keycloak) care about the exact name of the roles used by Google?!. Most-likely, either those roles are meaningless for the internal IDP, and when they are meaningful they might have a different name. Regardless, for those exceptions, one can use the Role Mapper feature.

    Nevertheless, to automatize a bit the process, I have created a file that maps the roles of the internal IDP to external IDP, for instance:

    ROLE A | ROLE B
    ....
    

    I also have a JSON file with a template of a Role Mapper example with some tags to be replaced afterwards (e.g., the fields role and external.role).

    With scripts, I read the file that has the mapping between roles, and use Keycloak Admin REST API to create the roles, the mappers and so on.

    The logic that I have used is as follows:

    The rationale for not creating the Realm Role in the external IDP is that all the roles from the external IDP should have been loaded already from the LDAP anyway. For the internal IDP, I do create because it is expectable that for mappings 1 to 1 that the roles from the LDAP (loaded into the external IDP) are not yet created on the internal IDP.