Merge pull request #1963 from mposolda/master
KEYCLOAK-1899 Added HardcodedLDAPRoleMapper
This commit is contained in:
commit
6752a4f9b0
18 changed files with 290 additions and 63 deletions
|
@ -1,14 +1,11 @@
|
||||||
package org.keycloak.broker.provider;
|
package org.keycloak.broker.provider;
|
||||||
|
|
||||||
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
|
|
||||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
|
||||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
|
||||||
import org.keycloak.models.ClientModel;
|
|
||||||
import org.keycloak.models.IdentityProviderMapperModel;
|
import org.keycloak.models.IdentityProviderMapperModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -20,7 +17,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class HardcodedRoleMapper extends AbstractIdentityProviderMapper {
|
public class HardcodedRoleMapper extends AbstractIdentityProviderMapper {
|
||||||
public static final String ROLE = "role";
|
public static final String ROLE = "role";
|
||||||
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ProviderConfigProperty property;
|
ProviderConfigProperty property;
|
||||||
|
@ -32,34 +29,6 @@ public class HardcodedRoleMapper extends AbstractIdentityProviderMapper {
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static String[] parseRole(String role) {
|
|
||||||
int scopeIndex = role.lastIndexOf('.');
|
|
||||||
if (scopeIndex > -1) {
|
|
||||||
String appName = role.substring(0, scopeIndex);
|
|
||||||
role = role.substring(scopeIndex + 1);
|
|
||||||
String[] rtn = {appName, role};
|
|
||||||
return rtn;
|
|
||||||
} else {
|
|
||||||
String[] rtn = {null, role};
|
|
||||||
return rtn;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RoleModel getRoleFromString(RealmModel realm, String roleName) {
|
|
||||||
String[] parsedRole = parseRole(roleName);
|
|
||||||
RoleModel role = null;
|
|
||||||
if (parsedRole[0] == null) {
|
|
||||||
role = realm.getRole(parsedRole[1]);
|
|
||||||
} else {
|
|
||||||
ClientModel client = realm.getClientByClientId(parsedRole[0]);
|
|
||||||
role = client.getRole(parsedRole[1]);
|
|
||||||
}
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
return configProperties;
|
return configProperties;
|
||||||
|
@ -93,7 +62,7 @@ public class HardcodedRoleMapper extends AbstractIdentityProviderMapper {
|
||||||
@Override
|
@Override
|
||||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(ROLE);
|
String roleName = mapperModel.getConfig().get(ROLE);
|
||||||
RoleModel role = getRoleFromString(realm, roleName);
|
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.grantRole(role);
|
user.grantRole(role);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -80,7 +81,7 @@ public class ClaimToRoleMapper extends AbstractClaimMapper {
|
||||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
if (hasClaimValue(mapperModel, context)) {
|
if (hasClaimValue(mapperModel, context)) {
|
||||||
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.grantRole(role);
|
user.grantRole(role);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +91,7 @@ public class ClaimToRoleMapper extends AbstractClaimMapper {
|
||||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
if (!hasClaimValue(mapperModel, context)) {
|
if (!hasClaimValue(mapperModel, context)) {
|
||||||
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.deleteRoleMapping(role);
|
user.deleteRoleMapping(role);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
|
|
||||||
|
@ -85,7 +86,7 @@ public class ExternalKeycloakRoleToRoleMapper extends AbstractClaimMapper {
|
||||||
JsonWebToken token = (JsonWebToken)context.getContextData().get(KeycloakOIDCIdentityProvider.VALIDATED_ACCESS_TOKEN);
|
JsonWebToken token = (JsonWebToken)context.getContextData().get(KeycloakOIDCIdentityProvider.VALIDATED_ACCESS_TOKEN);
|
||||||
//if (token == null) return;
|
//if (token == null) return;
|
||||||
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
String[] parseRole = HardcodedRoleMapper.parseRole(mapperModel.getConfig().get(EXTERNAL_ROLE));
|
String[] parseRole = KeycloakModelUtils.parseRole(mapperModel.getConfig().get(EXTERNAL_ROLE));
|
||||||
String externalRoleName = parseRole[1];
|
String externalRoleName = parseRole[1];
|
||||||
String claimName = null;
|
String claimName = null;
|
||||||
if (parseRole[0] == null) {
|
if (parseRole[0] == null) {
|
||||||
|
@ -95,7 +96,7 @@ public class ExternalKeycloakRoleToRoleMapper extends AbstractClaimMapper {
|
||||||
}
|
}
|
||||||
Object claim = getClaimValue(token, claimName);
|
Object claim = getClaimValue(token, claimName);
|
||||||
if (valueEquals(externalRoleName, claim)) {
|
if (valueEquals(externalRoleName, claim)) {
|
||||||
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.representations.JsonWebToken;
|
import org.keycloak.representations.JsonWebToken;
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ public class AttributeToRoleMapper extends AbstractIdentityProviderMapper {
|
||||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
if (isAttributePresent(mapperModel, context)) {
|
if (isAttributePresent(mapperModel, context)) {
|
||||||
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.grantRole(role);
|
user.grantRole(role);
|
||||||
}
|
}
|
||||||
|
@ -125,7 +126,7 @@ public class AttributeToRoleMapper extends AbstractIdentityProviderMapper {
|
||||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
if (!isAttributePresent(mapperModel, context)) {
|
if (!isAttributePresent(mapperModel, context)) {
|
||||||
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.deleteRoleMapping(role);
|
user.deleteRoleMapping(role);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class FullNameLDAPFederationMapperFactory extends AbstractLDAPFederationM
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
public void validateConfig(RealmModel realm, UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
checkMandatoryConfigAttribute(FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, "LDAP Full Name Attribute", mapperModel);
|
checkMandatoryConfigAttribute(FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, "LDAP Full Name Attribute", mapperModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package org.keycloak.federation.ldap.mappers;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.federation.ldap.LDAPFederationProvider;
|
||||||
|
import org.keycloak.federation.ldap.idm.model.LDAPObject;
|
||||||
|
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.ModelException;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.models.utils.UserModelDelegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class HardcodedLDAPRoleMapper extends AbstractLDAPFederationMapper {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(HardcodedLDAPRoleMapper.class);
|
||||||
|
|
||||||
|
public static final String ROLE = "role";
|
||||||
|
|
||||||
|
public HardcodedLDAPRoleMapper(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, RealmModel realm) {
|
||||||
|
super(mapperModel, ldapProvider, realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeLDAPQuery(LDAPQuery query) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserModel proxy(LDAPObject ldapUser, UserModel delegate) {
|
||||||
|
return new UserModelDelegate(delegate) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<RoleModel> getRealmRoleMappings() {
|
||||||
|
Set<RoleModel> roles = super.getRealmRoleMappings();
|
||||||
|
|
||||||
|
RoleModel role = getRole();
|
||||||
|
if (role != null && role.getContainer().equals(realm)) {
|
||||||
|
roles.add(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<RoleModel> getClientRoleMappings(ClientModel app) {
|
||||||
|
Set<RoleModel> roles = super.getClientRoleMappings(app);
|
||||||
|
|
||||||
|
RoleModel role = getRole();
|
||||||
|
if (role != null && role.getContainer().equals(app)) {
|
||||||
|
roles.add(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasRole(RoleModel role) {
|
||||||
|
return super.hasRole(role) || role.equals(getRole());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<RoleModel> getRoleMappings() {
|
||||||
|
Set<RoleModel> roles = super.getRoleMappings();
|
||||||
|
|
||||||
|
RoleModel role = getRole();
|
||||||
|
if (role != null) {
|
||||||
|
roles.add(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteRoleMapping(RoleModel role) {
|
||||||
|
if (role.equals(getRole())) {
|
||||||
|
throw new ModelException("Not possible to delete role. It's hardcoded by LDAP mapper");
|
||||||
|
} else {
|
||||||
|
super.deleteRoleMapping(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegisterUserToLDAP(LDAPObject ldapUser, UserModel localUser) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onImportUserFromLDAP(LDAPObject ldapUser, UserModel user, boolean isCreate) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private RoleModel getRole() {
|
||||||
|
String roleName = mapperModel.getConfig().get(HardcodedLDAPRoleMapper.ROLE);
|
||||||
|
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||||
|
if (role == null) {
|
||||||
|
logger.warnf("Hardcoded role '%s' configured in mapper '%s' is not available anymore");
|
||||||
|
}
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package org.keycloak.federation.ldap.mappers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.keycloak.federation.ldap.LDAPFederationProvider;
|
||||||
|
import org.keycloak.mappers.MapperConfigValidationException;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class HardcodedLDAPRoleMapperFactory extends AbstractLDAPFederationMapperFactory {
|
||||||
|
|
||||||
|
public static final String PROVIDER_ID = "hardcoded-ldap-role-mapper";
|
||||||
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
ProviderConfigProperty roleAttr = createConfigProperty(HardcodedLDAPRoleMapper.ROLE, "Role",
|
||||||
|
"Role to grant to user. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole",
|
||||||
|
ProviderConfigProperty.ROLE_TYPE, null);
|
||||||
|
configProperties.add(roleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHelpText() {
|
||||||
|
return "When user is imported from LDAP, he will be automatically added into this configured role.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayCategory() {
|
||||||
|
return ROLE_MAPPER_CATEGORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayType() {
|
||||||
|
return "Hardcoded Role";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return configProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getDefaultConfig(UserFederationProviderModel providerModel) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return PROVIDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateConfig(RealmModel realm, UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
|
String roleName = mapperModel.getConfig().get(HardcodedLDAPRoleMapper.ROLE);
|
||||||
|
if (roleName == null) {
|
||||||
|
throw new MapperConfigValidationException("Role can't be null");
|
||||||
|
}
|
||||||
|
RoleModel role = KeycloakModelUtils.getRoleFromString(realm, roleName);
|
||||||
|
if (role == null) {
|
||||||
|
throw new MapperConfigValidationException("There is no role corresponding to configured value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AbstractLDAPFederationMapper createMapper(UserFederationMapperModel mapperModel, LDAPFederationProvider federationProvider, RealmModel realm) {
|
||||||
|
return new HardcodedLDAPRoleMapper(mapperModel, federationProvider, realm);
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ public class UserAttributeLDAPFederationMapperFactory extends AbstractLDAPFedera
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
public void validateConfig(RealmModel realm, UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
checkMandatoryConfigAttribute(UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "User Model Attribute", mapperModel);
|
checkMandatoryConfigAttribute(UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "User Model Attribute", mapperModel);
|
||||||
checkMandatoryConfigAttribute(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "LDAP Attribute", mapperModel);
|
checkMandatoryConfigAttribute(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "LDAP Attribute", mapperModel);
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ public class GroupLDAPFederationMapperFactory extends AbstractLDAPFederationMapp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
public void validateConfig(RealmModel realm, UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
checkMandatoryConfigAttribute(GroupMapperConfig.GROUPS_DN, "LDAP Groups DN", mapperModel);
|
checkMandatoryConfigAttribute(GroupMapperConfig.GROUPS_DN, "LDAP Groups DN", mapperModel);
|
||||||
checkMandatoryConfigAttribute(GroupMapperConfig.MODE, "Mode", mapperModel);
|
checkMandatoryConfigAttribute(GroupMapperConfig.MODE, "Mode", mapperModel);
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
public void validateConfig(RealmModel realm, UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
|
||||||
checkMandatoryConfigAttribute(RoleMapperConfig.ROLES_DN, "LDAP Roles DN", mapperModel);
|
checkMandatoryConfigAttribute(RoleMapperConfig.ROLES_DN, "LDAP Roles DN", mapperModel);
|
||||||
checkMandatoryConfigAttribute(RoleMapperConfig.MODE, "Mode", mapperModel);
|
checkMandatoryConfigAttribute(RoleMapperConfig.MODE, "Mode", mapperModel);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapperFactory
|
org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapperFactory
|
||||||
org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapperFactory
|
org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapperFactory
|
||||||
|
org.keycloak.federation.ldap.mappers.HardcodedLDAPRoleMapperFactory
|
||||||
org.keycloak.federation.ldap.mappers.membership.role.RoleLDAPFederationMapperFactory
|
org.keycloak.federation.ldap.mappers.membership.role.RoleLDAPFederationMapperFactory
|
||||||
org.keycloak.federation.ldap.mappers.membership.group.GroupLDAPFederationMapperFactory
|
org.keycloak.federation.ldap.mappers.membership.group.GroupLDAPFederationMapperFactory
|
|
@ -2,6 +2,7 @@ package org.keycloak.mappers;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.provider.ConfiguredProvider;
|
import org.keycloak.provider.ConfiguredProvider;
|
||||||
|
@ -37,7 +38,7 @@ public interface UserFederationMapperFactory extends ProviderFactory<UserFederat
|
||||||
* @param mapperModel
|
* @param mapperModel
|
||||||
* @throws MapperConfigValidationException if configuration provided in mapperModel is not valid
|
* @throws MapperConfigValidationException if configuration provided in mapperModel is not valid
|
||||||
*/
|
*/
|
||||||
void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException;
|
void validateConfig(RealmModel realm, UserFederationMapperModel mapperModel) throws MapperConfigValidationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to detect what are default values for ProviderConfigProperties specified during mapper creation
|
* Used to detect what are default values for ProviderConfigProperties specified during mapper creation
|
||||||
|
|
|
@ -540,4 +540,34 @@ public final class KeycloakModelUtils {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used in various role mappers
|
||||||
|
public static RoleModel getRoleFromString(RealmModel realm, String roleName) {
|
||||||
|
String[] parsedRole = parseRole(roleName);
|
||||||
|
RoleModel role = null;
|
||||||
|
if (parsedRole[0] == null) {
|
||||||
|
role = realm.getRole(parsedRole[1]);
|
||||||
|
} else {
|
||||||
|
ClientModel client = realm.getClientByClientId(parsedRole[0]);
|
||||||
|
if (client != null) {
|
||||||
|
role = client.getRole(parsedRole[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for hardcoded role mappers
|
||||||
|
public static String[] parseRole(String role) {
|
||||||
|
int scopeIndex = role.lastIndexOf('.');
|
||||||
|
if (scopeIndex > -1) {
|
||||||
|
String appName = role.substring(0, scopeIndex);
|
||||||
|
role = role.substring(scopeIndex + 1);
|
||||||
|
String[] rtn = {appName, role};
|
||||||
|
return rtn;
|
||||||
|
} else {
|
||||||
|
String[] rtn = {null, role};
|
||||||
|
return rtn;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,20 +47,6 @@ public class ProtocolMapperUtils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String[] parseRole(String role) {
|
|
||||||
int scopeIndex = role.lastIndexOf('.');
|
|
||||||
if (scopeIndex > -1) {
|
|
||||||
String appName = role.substring(0, scopeIndex);
|
|
||||||
role = role.substring(scopeIndex + 1);
|
|
||||||
String[] rtn = {appName, role};
|
|
||||||
return rtn;
|
|
||||||
} else {
|
|
||||||
String[] rtn = {null, role};
|
|
||||||
return rtn;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the builtin locale mapper.
|
* Find the builtin locale mapper.
|
||||||
*
|
*
|
||||||
|
|
|
@ -4,6 +4,7 @@ import org.keycloak.models.ClientSessionModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
@ -67,7 +68,7 @@ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAcc
|
||||||
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
String role = mappingModel.getConfig().get(ROLE_CONFIG);
|
String role = mappingModel.getConfig().get(ROLE_CONFIG);
|
||||||
String[] scopedRole = ProtocolMapperUtils.parseRole(role);
|
String[] scopedRole = KeycloakModelUtils.parseRole(role);
|
||||||
String appName = scopedRole[0];
|
String appName = scopedRole[0];
|
||||||
String roleName = scopedRole[1];
|
String roleName = scopedRole[1];
|
||||||
if (appName != null) {
|
if (appName != null) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
@ -78,8 +79,8 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc
|
||||||
String role = mappingModel.getConfig().get(ROLE_CONFIG);
|
String role = mappingModel.getConfig().get(ROLE_CONFIG);
|
||||||
String newName = mappingModel.getConfig().get(NEW_ROLE_NAME);
|
String newName = mappingModel.getConfig().get(NEW_ROLE_NAME);
|
||||||
|
|
||||||
String[] scopedRole = ProtocolMapperUtils.parseRole(role);
|
String[] scopedRole = KeycloakModelUtils.parseRole(role);
|
||||||
String[] newScopedRole = ProtocolMapperUtils.parseRole(newName);
|
String[] newScopedRole = KeycloakModelUtils.parseRole(newName);
|
||||||
String appName = scopedRole[0];
|
String appName = scopedRole[0];
|
||||||
String roleName = scopedRole[1];
|
String roleName = scopedRole[1];
|
||||||
if (appName != null) {
|
if (appName != null) {
|
||||||
|
|
|
@ -353,7 +353,7 @@ public class UserFederationProviderResource {
|
||||||
private void validateModel(UserFederationMapperModel model) {
|
private void validateModel(UserFederationMapperModel model) {
|
||||||
try {
|
try {
|
||||||
UserFederationMapperFactory mapperFactory = (UserFederationMapperFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationMapper.class, model.getFederationMapperType());
|
UserFederationMapperFactory mapperFactory = (UserFederationMapperFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationMapper.class, model.getFederationMapperType());
|
||||||
mapperFactory.validateConfig(model);
|
mapperFactory.validateConfig(realm, model);
|
||||||
} catch (MapperConfigValidationException ex) {
|
} catch (MapperConfigValidationException ex) {
|
||||||
throw new ErrorResponseException("Validation error", ex.getMessage(), Response.Status.BAD_REQUEST);
|
throw new ErrorResponseException("Validation error", ex.getMessage(), Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,15 @@ import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
|
||||||
import org.keycloak.federation.ldap.idm.model.LDAPObject;
|
import org.keycloak.federation.ldap.idm.model.LDAPObject;
|
||||||
import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapper;
|
import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapper;
|
||||||
import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapperFactory;
|
import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapperFactory;
|
||||||
|
import org.keycloak.federation.ldap.mappers.HardcodedLDAPRoleMapper;
|
||||||
|
import org.keycloak.federation.ldap.mappers.HardcodedLDAPRoleMapperFactory;
|
||||||
import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapper;
|
import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapper;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.LDAPConstants;
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.models.ModelException;
|
||||||
import org.keycloak.models.ModelReadOnlyException;
|
import org.keycloak.models.ModelReadOnlyException;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserCredentialValueModel;
|
import org.keycloak.models.UserCredentialValueModel;
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
|
@ -524,6 +528,50 @@ public class FederationProvidersIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHardcodedRoleMapper() {
|
||||||
|
KeycloakSession session = keycloakRule.startSession();
|
||||||
|
UserFederationMapperModel firstNameMapper = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
RealmModel appRealm = new RealmManager(session).getRealmByName("test");
|
||||||
|
RoleModel hardcodedRole = appRealm.addRole("hardcoded-role");
|
||||||
|
|
||||||
|
// assert that user "johnkeycloak" doesn't have hardcoded role
|
||||||
|
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
|
||||||
|
Assert.assertFalse(john.hasRole(hardcodedRole));
|
||||||
|
|
||||||
|
UserFederationMapperModel hardcodedMapperModel = KeycloakModelUtils.createUserFederationMapperModel("hardcoded role", ldapModel.getId(), HardcodedLDAPRoleMapperFactory.PROVIDER_ID,
|
||||||
|
HardcodedLDAPRoleMapper.ROLE, "hardcoded-role");
|
||||||
|
appRealm.addUserFederationMapper(hardcodedMapperModel);
|
||||||
|
} finally {
|
||||||
|
keycloakRule.stopSession(session, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
session = keycloakRule.startSession();
|
||||||
|
try {
|
||||||
|
RealmModel appRealm = new RealmManager(session).getRealmByName("test");
|
||||||
|
RoleModel hardcodedRole = appRealm.getRole("hardcoded-role");
|
||||||
|
|
||||||
|
// Assert user is successfully imported in Keycloak DB now with correct firstName and lastName
|
||||||
|
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
|
||||||
|
Assert.assertTrue(john.hasRole(hardcodedRole));
|
||||||
|
|
||||||
|
// Can't remove user from hardcoded role
|
||||||
|
try {
|
||||||
|
john.deleteRoleMapping(hardcodedRole);
|
||||||
|
Assert.fail("Didn't expected to remove role mapping");
|
||||||
|
} catch (ModelException expected) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revert mappers
|
||||||
|
UserFederationMapperModel hardcodedMapperModel = appRealm.getUserFederationMapperByName(ldapModel.getId(), "hardcoded role");
|
||||||
|
appRealm.removeUserFederationMapper(hardcodedMapperModel);
|
||||||
|
} finally {
|
||||||
|
keycloakRule.stopSession(session, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testImportExistingUserFromLDAP() throws Exception {
|
public void testImportExistingUserFromLDAP() throws Exception {
|
||||||
// Add LDAP user with same email like existing model user
|
// Add LDAP user with same email like existing model user
|
||||||
|
|
Loading…
Reference in a new issue