keycloak-aplcache
Changes
federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java 77(+71 -6)
federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java 14(+0 -14)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java 4(+2 -2)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java 44(+43 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java 47(+13 -34)
Details
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPConfig.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPConfig.java
index 65181e1..acd2182 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPConfig.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPConfig.java
@@ -11,6 +11,7 @@ import java.util.Set;
import javax.naming.directory.SearchControls;
import org.keycloak.models.LDAPConstants;
+import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
/**
@@ -62,7 +63,7 @@ public class LDAPConfig {
return dns.iterator().next();
}
- public Collection<String> getObjectClasses() {
+ public Collection<String> getUserObjectClasses() {
String objClassesCfg = config.get(LDAPConstants.USER_OBJECT_CLASSES);
String objClassesStr = (objClassesCfg != null && objClassesCfg.length() > 0) ? objClassesCfg.trim() : "inetOrgPerson,organizationalPerson";
@@ -162,4 +163,13 @@ public class LDAPConfig {
}
return rdn;
}
+
+ public UserFederationProvider.EditMode getEditMode() {
+ String editModeString = config.get(LDAPConstants.EDIT_MODE);
+ if (editModeString == null) {
+ return UserFederationProvider.EditMode.READ_ONLY;
+ } else {
+ return UserFederationProvider.EditMode.valueOf(editModeString);
+ }
+ }
}
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
index fcdc11c..2168282 100755
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
@@ -59,12 +59,7 @@ public class LDAPFederationProvider implements UserFederationProvider {
this.model = model;
this.ldapIdentityStore = ldapIdentityStore;
this.kerberosConfig = new LDAPProviderKerberosConfig(model);
- String editModeString = model.getConfig().get(LDAPConstants.EDIT_MODE);
- if (editModeString == null) {
- editMode = EditMode.READ_ONLY;
- } else {
- editMode = EditMode.valueOf(editModeString);
- }
+ this.editMode = ldapIdentityStore.getConfig().getEditMode();
supportedCredentialTypes.add(UserCredentialModel.PASSWORD);
if (kerberosConfig.isAllowKerberosAuthentication()) {
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java
index 54d7609..166c5bf 100755
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProviderFactory.java
@@ -12,15 +12,22 @@ import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.LDAPIdentityQuery;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder;
import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore;
+import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapper;
+import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapperFactory;
+import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapper;
+import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapperFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserFederationEventAwareProviderFactory;
+import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderFactory;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserFederationSyncResult;
+import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.Collections;
@@ -33,7 +40,7 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class LDAPFederationProviderFactory implements UserFederationProviderFactory {
+public class LDAPFederationProviderFactory extends UserFederationEventAwareProviderFactory {
private static final Logger logger = Logger.getLogger(LDAPFederationProviderFactory.class);
public static final String PROVIDER_NAME = "ldap";
@@ -56,11 +63,6 @@ public class LDAPFederationProviderFactory implements UserFederationProviderFact
}
@Override
- public void postInit(KeycloakSessionFactory factory) {
-
- }
-
- @Override
public void close() {
this.ldapStoreRegistry = null;
}
@@ -75,6 +77,69 @@ public class LDAPFederationProviderFactory implements UserFederationProviderFact
return Collections.emptySet();
}
+
+ // Best effort to create appropriate mappers according to our LDAP config
+ @Override
+ protected void onProviderModelCreated(RealmModel realm, UserFederationProviderModel newProviderModel) {
+ LDAPConfig ldapConfig = new LDAPConfig(newProviderModel.getConfig());
+
+ boolean activeDirectory = ldapConfig.isActiveDirectory();
+ UserFederationProvider.EditMode editMode = ldapConfig.getEditMode();
+ String readOnly = String.valueOf(editMode==UserFederationProvider.EditMode.READ_ONLY || editMode== UserFederationProvider.EditMode.UNSYNCED);
+ String usernameLdapAttribute = ldapConfig.getUsernameLdapAttribute();
+
+ UserFederationMapperModel mapperModel;
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("usernameMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
+ UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.USERNAME,
+ UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, usernameLdapAttribute,
+ UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+ realm.addUserFederationMapper(mapperModel);
+
+ // For AD deployments with sAMAccountName is probably more common to map "cn" to full name of user
+ if (activeDirectory && usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("fullNameMapper", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.ID,
+ FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
+ UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+ realm.addUserFederationMapper(mapperModel);
+ } else {
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("firstNameMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
+ UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
+ UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.CN,
+ UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+ realm.addUserFederationMapper(mapperModel);
+ }
+
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("lastNameMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
+ UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.LAST_NAME,
+ UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.SN,
+ UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+ realm.addUserFederationMapper(mapperModel);
+
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("emailMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
+ UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.EMAIL,
+ UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.EMAIL,
+ UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
+ realm.addUserFederationMapper(mapperModel);
+
+ String createTimestampLdapAttrName = activeDirectory ? "whenCreated" : LDAPConstants.CREATE_TIMESTAMP;
+ String modifyTimestampLdapAttrName = activeDirectory ? "whenChanged" : LDAPConstants.MODIFY_TIMESTAMP;
+
+ // map createTimeStamp as read-only
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("creationDateMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
+ UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, LDAPConstants.CREATE_TIMESTAMP,
+ UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, createTimestampLdapAttrName,
+ UserAttributeLDAPFederationMapper.READ_ONLY, "true");
+ realm.addUserFederationMapper(mapperModel);
+
+ // map modifyTimeStamp as read-only
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("modifyDateMapper", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
+ UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, LDAPConstants.MODIFY_TIMESTAMP,
+ UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, modifyTimestampLdapAttrName,
+ UserAttributeLDAPFederationMapper.READ_ONLY, "true");
+ realm.addUserFederationMapper(mapperModel);
+ }
+
+
@Override
public UserFederationSyncResult syncAllUsers(KeycloakSessionFactory sessionFactory, final String realmId, final UserFederationProviderModel model) {
logger.infof("Sync all users from LDAP to local store: realm: %s, federation provider: %s", realmId, model.getDisplayName());
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java
index 5cd42c0..97f347b 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPIdentityStoreRegistry.java
@@ -81,20 +81,6 @@ public class LDAPIdentityStoreRegistry {
}
}
- // Parse array of strings like [ "inetOrgPerson", "organizationalPerson" ] from the string like: "inetOrgPerson, organizationalPerson"
- /*private static String[] getUserObjectClasses(Map<String,String> ldapConfig) {
- String objClassesCfg = ldapConfig.get(LDAPConstants.USER_OBJECT_CLASSES);
- String objClassesStr = (objClassesCfg != null && objClassesCfg.length() > 0) ? objClassesCfg.trim() : "inetOrgPerson, organizationalPerson";
-
- String[] addObjectClasses = objClassesStr.split(",");
-
- // Trim them
- String[] userObjectClasses = new String[addObjectClasses.length];
- for (int i=0 ; i<addObjectClasses.length ; i++) {
- userObjectClasses[i] = addObjectClasses[i].trim();
- }
- return userObjectClasses;
- } */
private class LDAPIdentityStoreContext {
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java
index 1e9a9e3..37e110c 100755
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPUtils.java
@@ -15,7 +15,6 @@ import org.keycloak.models.UserModel;
/**
* Allow to directly call some operations against LDAPIdentityStore.
- * TODO: Is this class still needed?
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -28,92 +27,24 @@ public class LDAPUtils {
* @return newly created LDAPObject with all the attributes, uuid and DN properly set
*/
public static LDAPObject addUserToLDAP(LDAPFederationProvider ldapProvider, RealmModel realm, UserModel user) {
- LDAPObject ldapObject = new LDAPObject();
+ LDAPObject ldapUser = new LDAPObject();
LDAPIdentityStore ldapStore = ldapProvider.getLdapIdentityStore();
LDAPConfig ldapConfig = ldapStore.getConfig();
- ldapObject.setRdnAttributeName(ldapConfig.getRdnLdapAttribute());
- ldapObject.setObjectClasses(ldapConfig.getObjectClasses());
+ ldapUser.setRdnAttributeName(ldapConfig.getRdnLdapAttribute());
+ ldapUser.setObjectClasses(ldapConfig.getUserObjectClasses());
Set<UserFederationMapperModel> federationMappers = realm.getUserFederationMappers();
for (UserFederationMapperModel mapperModel : federationMappers) {
LDAPFederationMapper ldapMapper = ldapProvider.getMapper(mapperModel);
- ldapMapper.onRegisterUserToLDAP(mapperModel, ldapProvider, ldapObject, user, realm);
+ ldapMapper.onRegisterUserToLDAP(mapperModel, ldapProvider, ldapUser, user, realm);
}
- LDAPUtils.computeAndSetDn(ldapConfig, ldapObject);
- ldapStore.add(ldapObject);
- return ldapObject;
- }
-
- /*public static LDAPUser updateUser(LDAPIdentityStore ldapIdentityStore, String username, String firstName, String lastName, String email) {
- LDAPUser ldapUser = getUser(ldapIdentityStore, username);
- ldapUser.setFirstName(firstName);
- ldapUser.setLastName(lastName);
- ldapUser.setEmail(email);
- ldapIdentityStore.update(ldapUser);
- return ldapUser;
- }
-
- public static void updatePassword(LDAPIdentityStore ldapIdentityStore, UserModel user, String password) {
- LDAPUser ldapUser = convertUserForPasswordUpdate(user);
-
- ldapIdentityStore.updatePassword(ldapUser, password);
- }
-
- public static void updatePassword(LDAPIdentityStore ldapIdentityStore, LDAPUser user, String password) {
- ldapIdentityStore.updatePassword(user, password);
- }
-
- public static boolean validatePassword(LDAPIdentityStore ldapIdentityStore, UserModel user, String password) {
- LDAPUser ldapUser = convertUserForPasswordUpdate(user);
-
- return ldapIdentityStore.validatePassword(ldapUser, password);
- }
-
- public static boolean validatePassword(LDAPIdentityStore ldapIdentityStore, LDAPUser user, String password) {
- return ldapIdentityStore.validatePassword(user, password);
- }
-
- public static LDAPUser getUser(LDAPIdentityStore ldapIdentityStore, String username) {
- return ldapIdentityStore.getUser(username);
- }
-
- // Put just username and entryDN as these are needed by LDAPIdentityStore for passwordUpdate
- private static LDAPUser convertUserForPasswordUpdate(UserModel kcUser) {
- LDAPUser ldapUser = new LDAPUser(kcUser.getUsername());
- String ldapEntryDN = kcUser.getAttribute(LDAPConstants.LDAP_ENTRY_DN);
- if (ldapEntryDN != null) {
- ldapUser.setEntryDN(ldapEntryDN);
- }
+ LDAPUtils.computeAndSetDn(ldapConfig, ldapUser);
+ ldapStore.add(ldapUser);
return ldapUser;
}
-
- public static LDAPUser getUserByEmail(LDAPIdentityStore ldapIdentityStore, String email) {
- IdentityQueryBuilder queryBuilder = ldapIdentityStore.createQueryBuilder();
- LDAPIdentityQuery<LDAPUser> query = queryBuilder.createIdentityQuery(LDAPUser.class)
- .where(queryBuilder.equal(LDAPUser.EMAIL, email));
- List<LDAPUser> users = query.getResultList();
-
- if (users.isEmpty()) {
- return null;
- } else if (users.size() == 1) {
- return users.get(0);
- } else {
- throw new ModelDuplicateException("Error - multiple users found with same email " + email);
- }
- }
-
- public static boolean removeUser(LDAPIdentityStore ldapIdentityStore, String username) {
- LDAPUser ldapUser = getUser(ldapIdentityStore, username);
- if (ldapUser == null) {
- return false;
- }
- ldapIdentityStore.remove(ldapUser);
- return true;
- } */
-
public static void removeAllUsers(LDAPFederationProvider ldapProvider, RealmModel realm) {
LDAPIdentityStore ldapStore = ldapProvider.getLdapIdentityStore();
LDAPIdentityQuery ldapQuery = LDAPUtils.createQueryForUserSearch(ldapProvider, realm);
@@ -129,7 +60,7 @@ public class LDAPUtils {
LDAPConfig config = ldapProvider.getLdapIdentityStore().getConfig();
ldapQuery.setSearchScope(config.getSearchScope());
ldapQuery.addSearchDns(config.getUserDns());
- ldapQuery.addObjectClasses(config.getObjectClasses());
+ ldapQuery.addObjectClasses(config.getUserObjectClasses());
Set<UserFederationMapperModel> mapperModels = realm.getUserFederationMappers();
ldapQuery.addMappers(mapperModels);
@@ -137,31 +68,6 @@ public class LDAPUtils {
return ldapQuery;
}
- /*
- public static List<LDAPUser> getAllUsers(LDAPIdentityStore ldapIdentityStore) {
- LDAPIdentityQuery<LDAPUser> userQuery = ldapIdentityStore.createQueryBuilder().createIdentityQuery(LDAPUser.class);
- return userQuery.getResultList();
- }
-
- // Needed for ActiveDirectory updates
- private static String getFullName(String username, String firstName, String lastName) {
- String fullName;
- if (firstName != null && lastName != null) {
- fullName = firstName + " " + lastName;
- } else if (firstName != null && firstName.trim().length() > 0) {
- fullName = firstName;
- } else {
- fullName = lastName;
- }
-
- // Fallback to loginName
- if (fullName == null || fullName.trim().length() == 0) {
- fullName = username;
- }
-
- return fullName;
- } */
-
// ldapUser has filled attributes, but doesn't have filled dn
public static void computeAndSetDn(LDAPConfig config, LDAPObject ldapObject) {
String rdnLdapAttrName = config.getRdnLdapAttribute();
diff --git a/model/api/src/main/java/org/keycloak/models/LDAPConstants.java b/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
index 35323c0..ac15a5c 100644
--- a/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
+++ b/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
@@ -50,6 +50,7 @@ public class LDAPConstants {
public static final String GIVENNAME = "givenname";
public static final String CN = "cn";
public static final String SN = "sn";
+ public static final String SAM_ACCOUNT_NAME = "sAMAccountName";
public static final String EMAIL = "mail";
public static final String POSTAL_CODE = "postalCode";
public static final String MEMBER = "member";
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index bfcaefb..508a84c 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -24,6 +24,11 @@ public interface RealmModel extends RoleContainerModel {
ClientModel getCreatedClient();
}
+ interface UserFederationProviderCreationEvent extends ProviderEvent {
+ UserFederationProviderModel getCreatedFederationProvider();
+ RealmModel getRealm();
+ }
+
String getId();
String getName();
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationEventAwareProviderFactory.java b/model/api/src/main/java/org/keycloak/models/UserFederationEventAwareProviderFactory.java
new file mode 100644
index 0000000..866bf79
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationEventAwareProviderFactory.java
@@ -0,0 +1,33 @@
+package org.keycloak.models;
+
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderEventListener;
+
+/**
+ * Provides "onProviderModelCreated" callback invoked when UserFederationProviderModel for this factory implementation is created in realm
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class UserFederationEventAwareProviderFactory implements UserFederationProviderFactory {
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ factory.register(new ProviderEventListener() {
+
+ @Override
+ public void onEvent(ProviderEvent event) {
+ if (event instanceof RealmModel.UserFederationProviderCreationEvent) {
+ RealmModel.UserFederationProviderCreationEvent fedCreationEvent = (RealmModel.UserFederationProviderCreationEvent)event;
+ UserFederationProviderModel providerModel = fedCreationEvent.getCreatedFederationProvider();
+
+ if (providerModel.getProviderName().equals(getId())) {
+ onProviderModelCreated(fedCreationEvent.getRealm(), providerModel);
+ }
+ }
+ }
+
+ });
+ }
+
+ protected abstract void onProviderModelCreated(RealmModel realm, UserFederationProviderModel createdProviderModel);
+}
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationProviderCreationEventImpl.java b/model/api/src/main/java/org/keycloak/models/UserFederationProviderCreationEventImpl.java
new file mode 100644
index 0000000..995ddc8
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationProviderCreationEventImpl.java
@@ -0,0 +1,25 @@
+package org.keycloak.models;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserFederationProviderCreationEventImpl implements RealmModel.UserFederationProviderCreationEvent {
+
+ private final UserFederationProviderModel createdFederationProvider;
+ private final RealmModel realm;
+
+ public UserFederationProviderCreationEventImpl(RealmModel realm, UserFederationProviderModel createdFederationProvider) {
+ this.realm = realm;
+ this.createdFederationProvider = createdFederationProvider;
+ }
+
+ @Override
+ public UserFederationProviderModel getCreatedFederationProvider() {
+ return createdFederationProvider;
+ }
+
+ @Override
+ public RealmModel getRealm() {
+ return realm;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationProviderModel.java b/model/api/src/main/java/org/keycloak/models/UserFederationProviderModel.java
index 9c3bf1c..494670d 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationProviderModel.java
@@ -20,7 +20,7 @@ public class UserFederationProviderModel {
private int changedSyncPeriod = -1; // In seconds. -1 means that periodic changed sync is disabled
private int lastSync; // Date when last sync was done for this provider
- public UserFederationProviderModel() {};
+ public UserFederationProviderModel() {}
public UserFederationProviderModel(String id, String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync) {
this.id = id;
@@ -39,6 +39,10 @@ public class UserFederationProviderModel {
return id;
}
+ public void setId(String id) {
+ this.id = id;
+ }
+
public String getProviderName() {
return providerName;
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
index 382d9c0..988d9ec 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
@@ -10,6 +10,7 @@ import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
@@ -26,8 +27,10 @@ import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -273,6 +276,8 @@ public final class KeycloakModelUtils {
return false;
}
+ // USER FEDERATION RELATED STUFF
+
/**
* Ensure that displayName of myProvider (if not null) is unique and there is no other provider with same displayName in the list.
*
@@ -296,6 +301,7 @@ public final class KeycloakModelUtils {
}
}
+
public static UserFederationProviderModel findUserFederationProviderByDisplayName(String displayName, RealmModel realm) {
if (displayName == null) {
return null;
@@ -309,6 +315,7 @@ public final class KeycloakModelUtils {
return null;
}
+
public static UserFederationProviderModel findUserFederationProviderById(String fedProviderId, RealmModel realm) {
for (UserFederationProviderModel fedProvider : realm.getUserFederationProviders()) {
if (fedProviderId.equals(fedProvider.getId())) {
@@ -317,4 +324,29 @@ public final class KeycloakModelUtils {
}
return null;
}
+
+
+ public static UserFederationMapperModel createUserFederationMapperModel(String name, String federationProviderId, String mapperType, String... config) {
+ UserFederationMapperModel mapperModel = new UserFederationMapperModel();
+ mapperModel.setName(name);
+ mapperModel.setFederationProviderId(federationProviderId);
+ mapperModel.setFederationMapperType(mapperType);
+
+ Map<String, String> configMap = new HashMap<String, String>();
+ String key = null;
+ for (String configEntry : config) {
+ if (key == null) {
+ key = configEntry;
+ } else {
+ configMap.put(key, configEntry);
+ key = null;
+ }
+ }
+ if (key != null) {
+ throw new IllegalStateException("Invalid count of arguments for config. Maybe mistake?");
+ }
+ mapperModel.setConfig(configMap);
+
+ return mapperModel;
+ }
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 2d20266..67d5932 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -16,7 +16,7 @@ import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
-
+
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@@ -307,7 +307,7 @@ public class ModelToRepresentation {
config.putAll(model.getConfig());
rep.setConfig(config);
- UserFederationProviderModel fedProvider = KeycloakModelUtils.findUserFederationProviderById(model.getId(), realm);
+ UserFederationProviderModel fedProvider = KeycloakModelUtils.findUserFederationProviderById(model.getFederationProviderId(), realm);
if (fedProvider == null) {
throw new ModelException("Couldn't find federation provider with ID " + model.getId());
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index f59f0b5..715b14a 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -49,6 +49,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeSet;
public class RepresentationToModel {
@@ -239,11 +240,31 @@ public class RepresentationToModel {
newRealm.setBrowserSecurityHeaders(BrowserSecurityHeaders.defaultHeaders);
}
+ List<UserFederationProviderModel> providerModels = null;
if (rep.getUserFederationProviders() != null) {
- List<UserFederationProviderModel> providerModels = convertFederationProviders(rep.getUserFederationProviders());
+ providerModels = convertFederationProviders(rep.getUserFederationProviders());
newRealm.setUserFederationProviders(providerModels);
}
if (rep.getUserFederationMappers() != null) {
+
+ // Remove builtin mappers for federation providers, which have some mappers already provided in JSON (likely due to previous export)
+ if (rep.getUserFederationProviders() != null) {
+ Set<String> providerNames = new TreeSet<String>();
+ for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
+ providerNames.add(representation.getFederationProviderDisplayName());
+ }
+ for (String providerName : providerNames) {
+ for (UserFederationProviderModel providerModel : providerModels) {
+ if (providerName.equals(providerModel.getDisplayName())) {
+ Set<UserFederationMapperModel> toDelete = newRealm.getUserFederationMappersByFederationProvider(providerModel.getId());
+ for (UserFederationMapperModel mapperModel : toDelete) {
+ newRealm.removeUserFederationMapper(mapperModel);
+ }
+ }
+ }
+ }
+ }
+
for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
newRealm.addUserFederationMapper(toModel(newRealm, representation));
}
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
index 4092ffa..30b272d 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
@@ -28,6 +28,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationMapperModel;
+import org.keycloak.models.UserFederationProviderCreationEventImpl;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.entities.ClientEntity;
@@ -829,7 +830,9 @@ public class RealmAdapter implements RealmModel {
entity.setLastSync(lastSync);
realm.getUserFederationProviders().add(entity);
- return new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+ UserFederationProviderModel providerModel = new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+ session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, providerModel));
+ return providerModel;
}
@Override
@@ -907,8 +910,13 @@ public class RealmAdapter implements RealmModel {
List<UserFederationProviderEntity> entities = new LinkedList<UserFederationProviderEntity>();
for (UserFederationProviderModel model : providers) {
UserFederationProviderEntity entity = new UserFederationProviderEntity();
- if (model.getId() != null) entity.setId(model.getId());
- else entity.setId(KeycloakModelUtils.generateId());
+ if (model.getId() != null) {
+ entity.setId(model.getId());
+ } else {
+ String id = KeycloakModelUtils.generateId();
+ entity.setId(id);
+ model.setId(id);
+ }
entity.setProviderName(model.getProviderName());
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
@@ -921,6 +929,7 @@ public class RealmAdapter implements RealmModel {
entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
entity.setLastSync(model.getLastSync());
entities.add(entity);
+ session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, model));
}
realm.setUserFederationProviders(entities);
@@ -1205,7 +1214,7 @@ public class RealmAdapter implements RealmModel {
@Override
public UserFederationMapperModel addUserFederationMapper(UserFederationMapperModel model) {
if (getUserFederationMapperByName(model.getFederationProviderId(), model.getName()) != null) {
- throw new ModelDuplicateException("User federation mapper must be unique per federation provider");
+ throw new ModelDuplicateException("User federation mapper must be unique per federation provider. There is already: " + model.getName());
}
String id = KeycloakModelUtils.generateId();
UserFederationMapperEntity entity = new UserFederationMapperEntity();
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 990b087..5c1d7e3 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -6,13 +6,12 @@ import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.ModelException;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationMapperModel;
-import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderCreationEventImpl;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.jpa.entities.ClientEntity;
import org.keycloak.models.jpa.entities.IdentityProviderEntity;
@@ -783,7 +782,9 @@ public class RealmAdapter implements RealmModel {
em.persist(entity);
realm.getUserFederationProviders().add(entity);
em.flush();
- return new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+ UserFederationProviderModel providerModel = new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+ session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, providerModel));
+ return providerModel;
}
@Override
@@ -879,8 +880,13 @@ public class RealmAdapter implements RealmModel {
for (UserFederationProviderModel model : add) {
UserFederationProviderEntity entity = new UserFederationProviderEntity();
- if (model.getId() != null) entity.setId(model.getId());
- else entity.setId(KeycloakModelUtils.generateId());
+ if (model.getId() != null) {
+ entity.setId(model.getId());
+ } else {
+ String id = KeycloakModelUtils.generateId();
+ entity.setId(id);
+ model.setId(id);
+ }
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
@@ -895,7 +901,7 @@ public class RealmAdapter implements RealmModel {
entity.setLastSync(model.getLastSync());
em.persist(entity);
realm.getUserFederationProviders().add(entity);
-
+ session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, model));
}
}
@@ -1385,7 +1391,7 @@ public class RealmAdapter implements RealmModel {
@Override
public UserFederationMapperModel addUserFederationMapper(UserFederationMapperModel model) {
if (getUserFederationMapperByName(model.getFederationProviderId(), model.getName()) != null) {
- throw new ModelDuplicateException("User federation mapper must be unique per federation provider");
+ throw new ModelDuplicateException("User federation mapper must be unique per federation provider. There is already: " + model.getName());
}
String id = KeycloakModelUtils.generateId();
UserFederationMapperEntity entity = new UserFederationMapperEntity();
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index a327a8d..a36f83e 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -16,6 +16,7 @@ import org.keycloak.models.RealmProvider;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationMapperModel;
+import org.keycloak.models.UserFederationProviderCreationEventImpl;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.entities.IdentityProviderEntity;
import org.keycloak.models.entities.IdentityProviderMapperEntity;
@@ -852,7 +853,9 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
realm.getUserFederationProviders().add(entity);
updateRealm();
- return new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+ UserFederationProviderModel providerModel = new UserFederationProviderModel(entity.getId(), providerName, config, priority, displayName, fullSyncPeriod, changedSyncPeriod, lastSync);
+ session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, providerModel));
+ return providerModel;
}
@Override
@@ -932,8 +935,13 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
List<UserFederationProviderEntity> entities = new LinkedList<UserFederationProviderEntity>();
for (UserFederationProviderModel model : providers) {
UserFederationProviderEntity entity = new UserFederationProviderEntity();
- if (model.getId() != null) entity.setId(model.getId());
- else entity.setId(KeycloakModelUtils.generateId());
+ if (model.getId() != null) {
+ entity.setId(model.getId());
+ } else {
+ String id = KeycloakModelUtils.generateId();
+ entity.setId(id);
+ model.setId(id);
+ }
entity.setProviderName(model.getProviderName());
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
@@ -946,6 +954,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
entity.setChangedSyncPeriod(model.getChangedSyncPeriod());
entity.setLastSync(model.getLastSync());
entities.add(entity);
+ session.getKeycloakSessionFactory().publish(new UserFederationProviderCreationEventImpl(this, model));
}
realm.setUserFederationProviders(entities);
@@ -1236,7 +1245,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
@Override
public UserFederationMapperModel addUserFederationMapper(UserFederationMapperModel model) {
if (getUserFederationMapperByName(model.getFederationProviderId(), model.getName()) != null) {
- throw new ModelDuplicateException("User federation mapper must be unique per federation provider");
+ throw new ModelDuplicateException("User federation mapper must be unique per federation provider. There is already: " + model.getName());
}
String id = KeycloakModelUtils.generateId();
UserFederationMapperEntity entity = new UserFederationMapperEntity();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
index 966260a..aa61ee6 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
@@ -23,8 +23,6 @@ import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.utils.UserModelDelegate;
-import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AccountPasswordPage;
@@ -61,6 +59,7 @@ public class FederationProvidersIntegrationTest {
ldapConfig.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap", -1, -1, 0);
+ FederationTestUtils.addZipCodeLDAPMapper(appRealm, ldapModel);
// Delete all LDAP users and add some new for testing
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
@@ -150,6 +149,7 @@ public class FederationProvidersIntegrationTest {
RealmModel appRealm = manager.getRealm("test");
ldapModel = appRealm.addUserFederationProvider(ldapModel.getProviderName(), ldapModel.getConfig(), ldapModel.getPriority(), ldapModel.getDisplayName(), -1, -1, 0);
+ FederationTestUtils.addZipCodeLDAPMapper(appRealm, ldapModel);
} finally {
keycloakRule.stopSession(session, true);
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java
index f5dfc9a..ddda4ff 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationTestUtils.java
@@ -5,13 +5,20 @@ import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
import org.keycloak.federation.ldap.LDAPUtils;
import org.keycloak.federation.ldap.idm.model.LDAPObject;
+import org.keycloak.federation.ldap.mappers.RoleLDAPFederationMapper;
+import org.keycloak.federation.ldap.mappers.RoleLDAPFederationMapperFactory;
+import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapper;
+import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapperFactory;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
+import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.UserModelDelegate;
import org.keycloak.representations.idm.CredentialRepresentation;
@@ -59,7 +66,7 @@ class FederationTestUtils {
@Override
public String getAttribute(String name) {
- if (name == "postal_code") {
+ if ("postal_code".equals(name)) {
return postalCode;
} else {
return null;
@@ -82,4 +89,39 @@ class FederationTestUtils {
Assert.assertEquals(expectedEmail, user.getEmail());
Assert.assertEquals(expectedPostalCode, user.getAttribute("postal_code"));
}
+
+ public static void addZipCodeLDAPMapper(RealmModel realm, UserFederationProviderModel providerModel) {
+ UserFederationMapperModel mapperModel = KeycloakModelUtils.createUserFederationMapperModel("zipCodeMapper", providerModel.getId(), UserAttributeLDAPFederationMapperFactory.ID,
+ UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "postal_code",
+ UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.POSTAL_CODE,
+ UserAttributeLDAPFederationMapper.READ_ONLY, "false");
+ realm.addUserFederationMapper(mapperModel);
+ }
+
+ public static void addOrUpdateRoleLDAPMappers(RealmModel realm, UserFederationProviderModel providerModel, RoleLDAPFederationMapper.Mode mode) {
+ UserFederationMapperModel mapperModel = realm.getUserFederationMapperByName(providerModel.getId(), "realmRolesMapper");
+ if (mapperModel != null) {
+ mapperModel.getConfig().put(RoleLDAPFederationMapper.MODE, mode.toString());
+ realm.updateUserFederationMapper(mapperModel);
+ } else {
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("realmRolesMapper", providerModel.getId(), RoleLDAPFederationMapperFactory.ID,
+ RoleLDAPFederationMapper.ROLES_DN, "ou=RealmRoles,dc=keycloak,dc=org",
+ RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING, "true",
+ RoleLDAPFederationMapper.MODE, mode.toString());
+ realm.addUserFederationMapper(mapperModel);
+ }
+
+ mapperModel = realm.getUserFederationMapperByName(providerModel.getId(), "financeRolesMapper");
+ if (mapperModel != null) {
+ mapperModel.getConfig().put(RoleLDAPFederationMapper.MODE, mode.toString());
+ realm.updateUserFederationMapper(mapperModel);
+ } else {
+ mapperModel = KeycloakModelUtils.createUserFederationMapperModel("financeRolesMapper", providerModel.getId(), RoleLDAPFederationMapperFactory.ID,
+ RoleLDAPFederationMapper.ROLES_DN, "ou=FinanceRoles,dc=keycloak,dc=org",
+ RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING, "false",
+ RoleLDAPFederationMapper.CLIENT_ID, "finance",
+ RoleLDAPFederationMapper.MODE, mode.toString());
+ realm.addUserFederationMapper(mapperModel);
+ }
+ }
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java
index eff3572..a389fe5 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPRoleMappingsTest.java
@@ -1,6 +1,5 @@
package org.keycloak.testsuite.federation;
-import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -33,7 +32,6 @@ import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.cache.RealmAdapter;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AccountPasswordPage;
@@ -96,7 +94,9 @@ public class LDAPRoleMappingsTest {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
RoleLDAPFederationMapper roleMapper = new RoleLDAPFederationMapper();
- UserFederationMapperModel roleMapperModel = findRoleMapperModel(appRealm);
+
+ FederationTestUtils.addOrUpdateRoleLDAPMappers(appRealm, ldapModel, RoleLDAPFederationMapper.Mode.LDAP_ONLY);
+ UserFederationMapperModel roleMapperModel = appRealm.getUserFederationMapperByName(ldapModel.getId(), "realmRolesMapper");
LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
LDAPObject ldapRole = roleMapper.loadLDAPRoleByName(roleMapperModel, ldapProvider, "realmRole3");
@@ -130,25 +130,16 @@ public class LDAPRoleMappingsTest {
protected AppPage appPage;
@WebResource
- protected RegisterPage registerPage;
-
- @WebResource
protected LoginPage loginPage;
- @WebResource
- protected AccountUpdateProfilePage profilePage;
-
- @WebResource
- protected AccountPasswordPage changePasswordPage;
-
@Test
public void test01_ldapOnlyRoleMappings() {
- // TODO: Remove me!!!
- //RealmAdapter.LDAP_MODE = "LDAP_ONLY";
-
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
+
+ FederationTestUtils.addOrUpdateRoleLDAPMappers(appRealm, ldapModel, RoleLDAPFederationMapper.Mode.LDAP_ONLY);
+
UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm);
@@ -230,12 +221,12 @@ public class LDAPRoleMappingsTest {
@Test
public void test02_readOnlyRoleMappings() {
- // TODO: Remove me!!!
- //RealmAdapter.LDAP_MODE = "READ_ONLY";
-
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
+
+ FederationTestUtils.addOrUpdateRoleLDAPMappers(appRealm, ldapModel, RoleLDAPFederationMapper.Mode.READ_ONLY);
+
UserModel mary = session.users().getUserByUsername("marykeycloak", appRealm);
RoleModel realmRole1 = appRealm.getRole("realmRole1");
@@ -247,7 +238,7 @@ public class LDAPRoleMappingsTest {
// Add some role mappings directly into LDAP
RoleLDAPFederationMapper roleMapper = new RoleLDAPFederationMapper();
- UserFederationMapperModel roleMapperModel = findRoleMapperModel(appRealm);
+ UserFederationMapperModel roleMapperModel = appRealm.getUserFederationMapperByName(ldapModel.getId(), "realmRolesMapper");
LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
LDAPObject maryLdap = ldapProvider.loadLDAPUserByUsername(appRealm, "marykeycloak");
roleMapper.addRoleMappingInLDAP(roleMapperModel, "realmRole1", ldapProvider, maryLdap);
@@ -292,16 +283,15 @@ public class LDAPRoleMappingsTest {
@Test
public void test03_importRoleMappings() {
- // TODO: Remove me!!!
- //RealmAdapter.LDAP_MODE = "IMPORT";
-
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
+ FederationTestUtils.addOrUpdateRoleLDAPMappers(appRealm, ldapModel, RoleLDAPFederationMapper.Mode.IMPORT);
+
// Add some role mappings directly in LDAP
RoleLDAPFederationMapper roleMapper = new RoleLDAPFederationMapper();
- UserFederationMapperModel roleMapperModel = findRoleMapperModel(appRealm);
+ UserFederationMapperModel roleMapperModel = appRealm.getUserFederationMapperByName(ldapModel.getId(), "realmRolesMapper");
LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
LDAPObject robLdap = ldapProvider.loadLDAPUserByUsername(appRealm, "robkeycloak");
roleMapper.addRoleMappingInLDAP(roleMapperModel, "realmRole1", ldapProvider, robLdap);
@@ -345,17 +335,6 @@ public class LDAPRoleMappingsTest {
}
}
- private static UserFederationMapperModel findRoleMapperModel(RealmModel appRealm) {
- Set<UserFederationMapperModel> fedMappers = appRealm.getUserFederationMappers();
- for (UserFederationMapperModel mapper : fedMappers) {
- if ("realmRoleMapper".equals(mapper.getName())) {
- return mapper;
- }
- }
-
- throw new IllegalStateException("Mapper 'realmRoleMapper' not found");
- }
-
private void deleteRoleMappingsInLDAP(UserFederationMapperModel roleMapperModel, RoleLDAPFederationMapper roleMapper, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, String roleName) {
LDAPIdentityQuery ldapQuery = roleMapper.createRoleQuery(roleMapperModel, ldapProvider);
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
index 71a37b7..40ae50c 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java
@@ -19,7 +19,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserFederationSyncResult;
-import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.UsersSyncManager;
@@ -52,11 +51,13 @@ public class SyncProvidersTest {
Map<String,String> ldapConfig = ldapRule.getConfig();
ldapConfig.put(LDAPConstants.SYNC_REGISTRATIONS, "false");
- ldapConfig.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.UNSYNCED.toString());
+ ldapConfig.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap",
-1, -1, 0);
+ FederationTestUtils.addZipCodeLDAPMapper(appRealm, ldapModel);
+
// Delete all LDAP users and add 5 new users for testing
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
LDAPUtils.removeAllUsers(ldapFedProvider, appRealm);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
index 492aa1d..4d20bc8 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
@@ -12,6 +12,7 @@ import org.keycloak.models.Constants;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.LDAPConstants;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
@@ -216,22 +217,32 @@ public class ImportTest extends AbstractModelTest {
// Test federation providers
List<UserFederationProviderModel> fedProviders = realm.getUserFederationProviders();
- Assert.assertTrue(fedProviders.size() == 1);
- UserFederationProviderModel ldap = fedProviders.get(0);
- Assert.assertEquals("MyLDAPProvider", ldap.getDisplayName());
- Assert.assertEquals("dummy", ldap.getProviderName());
- Assert.assertEquals(1, ldap.getPriority());
- Assert.assertEquals("ldap://foo", ldap.getConfig().get("important.config"));
+ Assert.assertTrue(fedProviders.size() == 2);
+ UserFederationProviderModel ldap1 = fedProviders.get(0);
+ Assert.assertEquals("MyLDAPProvider1", ldap1.getDisplayName());
+ Assert.assertEquals("ldap", ldap1.getProviderName());
+ Assert.assertEquals(1, ldap1.getPriority());
+ Assert.assertEquals("ldap://foo", ldap1.getConfig().get(LDAPConstants.CONNECTION_URL));
+
+ UserFederationProviderModel ldap2 = fedProviders.get(1);
+ Assert.assertEquals("MyLDAPProvider2", ldap2.getDisplayName());
+ Assert.assertEquals("ldap://bar", ldap2.getConfig().get(LDAPConstants.CONNECTION_URL));
// Test federation mappers
- Set<UserFederationMapperModel> fedMappers = realm.getUserFederationMappers();
- Assert.assertTrue(fedMappers.size() == 1);
- UserFederationMapperModel fullNameMapper = fedMappers.iterator().next();
+ Set<UserFederationMapperModel> fedMappers1 = realm.getUserFederationMappersByFederationProvider(ldap1.getId());
+ Assert.assertTrue(fedMappers1.size() == 1);
+ UserFederationMapperModel fullNameMapper = fedMappers1.iterator().next();
Assert.assertEquals("FullNameMapper", fullNameMapper.getName());
Assert.assertEquals(FullNameLDAPFederationMapperFactory.ID, fullNameMapper.getFederationMapperType());
- Assert.assertEquals(ldap.getId(), fullNameMapper.getFederationProviderId());
+ Assert.assertEquals(ldap1.getId(), fullNameMapper.getFederationProviderId());
Assert.assertEquals("cn", fullNameMapper.getConfig().get(FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE));
+ // All builtin LDAP mappers should be here
+ Set<UserFederationMapperModel> fedMappers2 = realm.getUserFederationMappersByFederationProvider(ldap2.getId());
+ Assert.assertTrue(fedMappers2.size() > 3);
+ Set<UserFederationMapperModel> allMappers = realm.getUserFederationMappers();
+ Assert.assertEquals(allMappers.size(), fedMappers1.size() + fedMappers2.size());
+
// Assert that federation link wasn't created during import
UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, "dummy");
Assert.assertNull(factory.getInstance(session, null).getUserByUsername(realm, "wburke"));
diff --git a/testsuite/integration/src/test/resources/model/testrealm.json b/testsuite/integration/src/test/resources/model/testrealm.json
index 43458c9..0e41313 100755
--- a/testsuite/integration/src/test/resources/model/testrealm.json
+++ b/testsuite/integration/src/test/resources/model/testrealm.json
@@ -25,18 +25,26 @@
],
"userFederationProviders": [
{
- "displayName": "MyLDAPProvider",
- "providerName": "dummy",
+ "displayName": "MyLDAPProvider1",
+ "providerName": "ldap",
"priority": 1,
"config": {
- "important.config": "ldap://foo"
+ "connectionUrl": "ldap://foo"
+ }
+ },
+ {
+ "displayName": "MyLDAPProvider2",
+ "providerName": "ldap",
+ "priority": 2,
+ "config": {
+ "connectionUrl": "ldap://bar"
}
}
],
"userFederationMappers": [
{
"name": "FullNameMapper",
- "federationProviderDisplayName": "MyLDAPProvider",
+ "federationProviderDisplayName": "MyLDAPProvider1",
"federationMapperType": "full-name-ldap-mapper",
"config": {
"ldap.full.name.attribute": "cn"