KEYCLOAK-886 Added builtin federation mappers when creating new LDAP Federation model. Testsuite passing

This commit is contained in:
mposolda 2015-05-22 15:04:28 +02:00
parent 7476ee51e4
commit 490b3e3603
22 changed files with 348 additions and 200 deletions

View file

@ -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);
}
}
}

View file

@ -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()) {

View file

@ -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";
@ -55,11 +62,6 @@ public class LDAPFederationProviderFactory implements UserFederationProviderFact
this.ldapStoreRegistry = new LDAPIdentityStoreRegistry();
}
@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());

View file

@ -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 {

View file

@ -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);
LDAPUtils.computeAndSetDn(ldapConfig, ldapUser);
ldapStore.add(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);
}
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();

View file

@ -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";

View file

@ -24,6 +24,11 @@ public interface RealmModel extends RoleContainerModel {
ClientModel getCreatedClient();
}
interface UserFederationProviderCreationEvent extends ProviderEvent {
UserFederationProviderModel getCreatedFederationProvider();
RealmModel getRealm();
}
String getId();
String getName();

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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());
}

View file

@ -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));
}

View file

@ -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();

View file

@ -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();

View file

@ -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();

View file

@ -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);
}

View file

@ -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);
}
}
}

View file

@ -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");
@ -129,26 +129,17 @@ public class LDAPRoleMappingsTest {
@WebResource
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();

View file

@ -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);

View file

@ -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"));

View file

@ -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"