I have simple spring boot app which use keycloak SSO with custom user storage provider. Authentication is work fine without user roles. But i need to know how to map existing user roles with custom user storage provider. Does anyone know how to map existing user roles with keycloak user storage provider?
2 Answers
Finally found a way to map roles.
Add roles to realm and override the AbstractUserAdapterFederatedStorage.getRoleMappingsgetRoleMappings() method.
public Set<RoleModel> getRoleMappings() {
Set<RoleModel> roles = new HashSet();
Iterator rolesItr = userEntity.getRoles().iterator();
while(rolesItr.hasNext()) {
roles.add(realm.getRole(((Role)rolesItr.next()).getName()));
}
return roles;
}
If you are using a user storage SPI you'll most likely need to implement the UserLookupProvider interface (org.keycloak.storage.user.UserLookupProvider
).
For instance one of the method in that interface is UserModel getUserByUsername(String username, RealmModel realm)
As you can see, the methods in that interface return a UserModel
object.
UserModel
implements the RoleMapperModel
interface. You just have to call the UserModel::grantRole method and pass the roles you want.
Example:
Assuming you have a class MyUserDao {...}
that retrieves users from your database as a class MyUserModel {...}
instance.
public UserModel getUserByUsername(String username, RealmModel realm) {
Optional<MyUserModel> myUserOpt = myUserDao.getUserByUsername(username);
if (!myUserOpt.isPresent())
throw new AccessDeniedException();
MyUserModel myUser = myUserOpt .get();
UserModel keycloakUser = mapToKeycloakUserModel(myUser);
for (String roleName: myUser.getRoles())
userModel.grantRole(KeycloakModelUtils.getRoleFromString(realm, roleName));
return keycloakUser;
}
private UserModel mapToKeycloakUserModel(MyUserModel myUser) {...}
Note you have to load roles with org.keycloak.models.utils.KeycloakModelUtils::getRoleFromString otherwise UserModel::grantRole will try to re-create them and you'll end up with an exception.