KEYCLOAK-1357 LDAP migration
This commit is contained in:
parent
75e1f50faf
commit
0af68d28f1
10 changed files with 101 additions and 56 deletions
|
@ -48,7 +48,14 @@ public class LDAPConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUsersDn() {
|
public String getUsersDn() {
|
||||||
return config.get(LDAPConstants.USERS_DN);
|
String usersDn = config.get(LDAPConstants.USERS_DN);
|
||||||
|
|
||||||
|
if (usersDn == null) {
|
||||||
|
// Just for the backwards compatibility 1.2 -> 1.3 . Should be removed later.
|
||||||
|
usersDn = config.get("userDnSuffix");
|
||||||
|
}
|
||||||
|
|
||||||
|
return usersDn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<String> getUserObjectClasses() {
|
public Collection<String> getUserObjectClasses() {
|
||||||
|
@ -101,31 +108,13 @@ public class LDAPConfig {
|
||||||
if (uuidAttrName == null) {
|
if (uuidAttrName == null) {
|
||||||
// Differences of unique attribute among various vendors
|
// Differences of unique attribute among various vendors
|
||||||
String vendor = getVendor();
|
String vendor = getVendor();
|
||||||
if (vendor != null) {
|
uuidAttrName = LDAPConstants.getUuidAttributeName(vendor);
|
||||||
switch (vendor) {
|
|
||||||
case LDAPConstants.VENDOR_RHDS:
|
|
||||||
uuidAttrName = "nsuniqueid";
|
|
||||||
break;
|
|
||||||
case LDAPConstants.VENDOR_TIVOLI:
|
|
||||||
uuidAttrName = "uniqueidentifier";
|
|
||||||
break;
|
|
||||||
case LDAPConstants.VENDOR_NOVELL_EDIRECTORY:
|
|
||||||
uuidAttrName = "guid";
|
|
||||||
break;
|
|
||||||
case LDAPConstants.VENDOR_ACTIVE_DIRECTORY:
|
|
||||||
uuidAttrName = LDAPConstants.OBJECT_GUID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uuidAttrName == null) {
|
|
||||||
uuidAttrName = LDAPConstants.ENTRY_UUID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return uuidAttrName;
|
return uuidAttrName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove and use mapper instead
|
// TODO: Remove and use mapper instead?
|
||||||
public boolean isUserAccountControlsAfterPasswordUpdate() {
|
public boolean isUserAccountControlsAfterPasswordUpdate() {
|
||||||
String userAccountCtrls = config.get(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE);
|
String userAccountCtrls = config.get(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE);
|
||||||
return userAccountCtrls==null ? false : Boolean.parseBoolean(userAccountCtrls);
|
return userAccountCtrls==null ? false : Boolean.parseBoolean(userAccountCtrls);
|
||||||
|
@ -148,6 +137,12 @@ public class LDAPConfig {
|
||||||
String rdn = config.get(LDAPConstants.RDN_LDAP_ATTRIBUTE);
|
String rdn = config.get(LDAPConstants.RDN_LDAP_ATTRIBUTE);
|
||||||
if (rdn == null) {
|
if (rdn == null) {
|
||||||
rdn = getUsernameLdapAttribute();
|
rdn = getUsernameLdapAttribute();
|
||||||
|
|
||||||
|
if (rdn.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
|
||||||
|
// Just for the backwards compatibility 1.2 -> 1.3 . Should be removed later.
|
||||||
|
rdn = LDAPConstants.CN;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return rdn;
|
return rdn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public class LDAPFederationProviderFactory extends UserFederationEventAwareProviderFactory {
|
public class LDAPFederationProviderFactory extends UserFederationEventAwareProviderFactory {
|
||||||
private static final Logger logger = Logger.getLogger(LDAPFederationProviderFactory.class);
|
private static final Logger logger = Logger.getLogger(LDAPFederationProviderFactory.class);
|
||||||
public static final String PROVIDER_NAME = "ldap";
|
public static final String PROVIDER_NAME = LDAPConstants.LDAP_PROVIDER;
|
||||||
|
|
||||||
private LDAPIdentityStoreRegistry ldapStoreRegistry;
|
private LDAPIdentityStoreRegistry ldapStoreRegistry;
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
|
||||||
|
|
||||||
// Best effort to create appropriate mappers according to our LDAP config
|
// Best effort to create appropriate mappers according to our LDAP config
|
||||||
@Override
|
@Override
|
||||||
protected void onProviderModelCreated(RealmModel realm, UserFederationProviderModel newProviderModel) {
|
public void onProviderModelCreated(RealmModel realm, UserFederationProviderModel newProviderModel) {
|
||||||
LDAPConfig ldapConfig = new LDAPConfig(newProviderModel.getConfig());
|
LDAPConfig ldapConfig = new LDAPConfig(newProviderModel.getConfig());
|
||||||
|
|
||||||
boolean activeDirectory = ldapConfig.isActiveDirectory();
|
boolean activeDirectory = ldapConfig.isActiveDirectory();
|
||||||
|
|
|
@ -55,23 +55,6 @@ public class LDAPIdentityStoreRegistry {
|
||||||
checkSystemProperty("com.sun.jndi.ldap.connect.pool.protocol", "plain");
|
checkSystemProperty("com.sun.jndi.ldap.connect.pool.protocol", "plain");
|
||||||
checkSystemProperty("com.sun.jndi.ldap.connect.pool.debug", "off");
|
checkSystemProperty("com.sun.jndi.ldap.connect.pool.debug", "off");
|
||||||
|
|
||||||
/*String ldapLoginNameMapping = ldapConfig.get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
|
|
||||||
if (ldapLoginNameMapping == null) {
|
|
||||||
ldapLoginNameMapping = activeDirectory ? LDAPConstants.CN : LDAPConstants.UID;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ldapFirstNameMapping = activeDirectory ? "givenName" : LDAPConstants.CN;
|
|
||||||
String createTimestampMapping = activeDirectory ? "whenCreated" : LDAPConstants.CREATE_TIMESTAMP;
|
|
||||||
String modifyTimestampMapping = activeDirectory ? "whenChanged" : LDAPConstants.MODIFY_TIMESTAMP;
|
|
||||||
String[] userObjectClasses = getUserObjectClasses(ldapConfig); */
|
|
||||||
|
|
||||||
|
|
||||||
/* if (activeDirectory && ldapLoginNameMapping.equals("sAMAccountName")) {
|
|
||||||
ldapUserMappingConfig.setBindingDnPropertyName("fullName");
|
|
||||||
ldapUserMappingConfig.addAttributeMapping("fullName", LDAPConstants.CN);
|
|
||||||
logger.infof("Using 'cn' attribute for DN of user and 'sAMAccountName' for username");
|
|
||||||
} */
|
|
||||||
|
|
||||||
return new LDAPIdentityStore(cfg);
|
return new LDAPIdentityStore(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ public interface MigrationModel {
|
||||||
/**
|
/**
|
||||||
* Must have the form of major.minor.micro as the version is parsed and numbers are compared
|
* Must have the form of major.minor.micro as the version is parsed and numbers are compared
|
||||||
*/
|
*/
|
||||||
public static final String LATEST_VERSION = "1.2.0.CR1";
|
public static final String LATEST_VERSION = "1.3.0.Beta1";
|
||||||
|
|
||||||
String getStoredVersion();
|
String getStoredVersion();
|
||||||
void setStoredVersion(String version);
|
void setStoredVersion(String version);
|
||||||
|
|
|
@ -17,11 +17,13 @@ public class MigrationModelManager {
|
||||||
String storedVersion = model.getStoredVersion();
|
String storedVersion = model.getStoredVersion();
|
||||||
if (MigrationModel.LATEST_VERSION.equals(storedVersion)) return;
|
if (MigrationModel.LATEST_VERSION.equals(storedVersion)) return;
|
||||||
ModelVersion stored = null;
|
ModelVersion stored = null;
|
||||||
if (storedVersion != null) new ModelVersion(storedVersion);
|
if (storedVersion != null) {
|
||||||
|
stored = new ModelVersion(storedVersion);
|
||||||
|
}
|
||||||
|
|
||||||
if (stored == null || stored.lessThan(MigrationTo1_2_0_CR1.VERSION)) {
|
if (stored == null || stored.lessThan(MigrationTo1_2_0_CR1.VERSION)) {
|
||||||
if (stored != null) {
|
if (stored != null) {
|
||||||
logger.debug("Migrating older model to 1.2.0.RC1 updates");
|
logger.debug("Migrating older model to 1.2.0.CR1 updates");
|
||||||
}
|
}
|
||||||
new MigrationTo1_2_0_CR1().migrate(session);
|
new MigrationTo1_2_0_CR1().migrate(session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class ModelVersion {
|
||||||
if (major < version.major) return true;
|
if (major < version.major) return true;
|
||||||
if (minor < version.minor) return true;
|
if (minor < version.minor) return true;
|
||||||
if (micro < version.micro) return true;
|
if (micro < version.micro) return true;
|
||||||
if (qualifier == version.qualifier) return false;
|
if (qualifier != null && qualifier.equals(version.qualifier)) return false;
|
||||||
if (qualifier == null) return false;
|
if (qualifier == null) return false;
|
||||||
if (version.qualifier == null) return true;
|
if (version.qualifier == null) return true;
|
||||||
int comp = qualifier.compareTo(version.qualifier);
|
int comp = qualifier.compareTo(version.qualifier);
|
||||||
|
|
|
@ -2,10 +2,18 @@ package org.keycloak.migration.migrators;
|
||||||
|
|
||||||
import org.keycloak.migration.ModelVersion;
|
import org.keycloak.migration.ModelVersion;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserFederationEventAwareProviderFactory;
|
||||||
|
import org.keycloak.models.UserFederationProvider;
|
||||||
|
import org.keycloak.models.UserFederationProviderFactory;
|
||||||
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.naming.directory.SearchControls;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -21,7 +29,45 @@ public class MigrateTo1_3_0_Beta1 {
|
||||||
if (realm.getAuthenticationFlows().size() == 0) {
|
if (realm.getAuthenticationFlows().size() == 0) {
|
||||||
DefaultAuthenticationFlows.addFlows(realm);
|
DefaultAuthenticationFlows.addFlows(realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
migrateLDAPProviders(session, realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void migrateLDAPProviders(KeycloakSession session, RealmModel realm) {
|
||||||
|
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
|
||||||
|
for (UserFederationProviderModel fedProvider : federationProviders) {
|
||||||
|
|
||||||
|
if (fedProvider.getProviderName().equals(LDAPConstants.LDAP_PROVIDER)) {
|
||||||
|
Map<String, String> config = fedProvider.getConfig();
|
||||||
|
|
||||||
|
// Update config properties for LDAP federation provider
|
||||||
|
config.put(LDAPConstants.SEARCH_SCOPE, String.valueOf(SearchControls.SUBTREE_SCOPE));
|
||||||
|
|
||||||
|
String usersDn = config.remove("userDnSuffix");
|
||||||
|
config.put(LDAPConstants.USERS_DN, usersDn);
|
||||||
|
|
||||||
|
String rdnLdapAttribute = config.get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
|
||||||
|
if (rdnLdapAttribute != null) {
|
||||||
|
if (rdnLdapAttribute.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
|
||||||
|
config.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, LDAPConstants.CN);
|
||||||
|
} else {
|
||||||
|
config.put(LDAPConstants.RDN_LDAP_ATTRIBUTE, rdnLdapAttribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String uuidAttrName = LDAPConstants.getUuidAttributeName(config.get(LDAPConstants.VENDOR));
|
||||||
|
config.put(LDAPConstants.UUID_LDAP_ATTRIBUTE, uuidAttrName);
|
||||||
|
|
||||||
|
realm.updateUserFederationProvider(fedProvider);
|
||||||
|
|
||||||
|
// Create default mappers for LDAP
|
||||||
|
UserFederationProviderFactory ldapFactory = (UserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, LDAPConstants.LDAP_PROVIDER);
|
||||||
|
if (ldapFactory != null) {
|
||||||
|
((UserFederationEventAwareProviderFactory) ldapFactory).onProviderModelCreated(realm, fedProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ package org.keycloak.models;
|
||||||
*/
|
*/
|
||||||
public class LDAPConstants {
|
public class LDAPConstants {
|
||||||
|
|
||||||
|
public static final String LDAP_PROVIDER = "ldap";
|
||||||
|
|
||||||
public static final String VENDOR = "vendor";
|
public static final String VENDOR = "vendor";
|
||||||
public static final String VENDOR_RHDS = "rhds";
|
public static final String VENDOR_RHDS = "rhds";
|
||||||
public static final String VENDOR_ACTIVE_DIRECTORY = "ad";
|
public static final String VENDOR_ACTIVE_DIRECTORY = "ad";
|
||||||
|
@ -80,4 +82,21 @@ public class LDAPConstants {
|
||||||
public static final String OBJECT_GUID = "objectGUID";
|
public static final String OBJECT_GUID = "objectGUID";
|
||||||
public static final String CREATE_TIMESTAMP = "createTimestamp";
|
public static final String CREATE_TIMESTAMP = "createTimestamp";
|
||||||
public static final String MODIFY_TIMESTAMP = "modifyTimestamp";
|
public static final String MODIFY_TIMESTAMP = "modifyTimestamp";
|
||||||
|
|
||||||
|
public static String getUuidAttributeName(String vendor) {
|
||||||
|
if (vendor != null) {
|
||||||
|
switch (vendor) {
|
||||||
|
case VENDOR_RHDS:
|
||||||
|
return "nsuniqueid";
|
||||||
|
case VENDOR_TIVOLI:
|
||||||
|
return "uniqueidentifier";
|
||||||
|
case VENDOR_NOVELL_EDIRECTORY:
|
||||||
|
return "guid";
|
||||||
|
case VENDOR_ACTIVE_DIRECTORY:
|
||||||
|
return OBJECT_GUID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ENTRY_UUID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ public abstract class UserFederationEventAwareProviderFactory implements UserFed
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void onProviderModelCreated(RealmModel realm, UserFederationProviderModel createdProviderModel);
|
public abstract void onProviderModelCreated(RealmModel realm, UserFederationProviderModel createdProviderModel);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,30 +16,30 @@ public class MigrationVersionTest {
|
||||||
Assert.assertEquals(version_100Beta1.getMajor(), 1);
|
Assert.assertEquals(version_100Beta1.getMajor(), 1);
|
||||||
Assert.assertEquals(version_100Beta1.getMinor(), 0);
|
Assert.assertEquals(version_100Beta1.getMinor(), 0);
|
||||||
Assert.assertEquals(version_100Beta1.getMicro(), 0);
|
Assert.assertEquals(version_100Beta1.getMicro(), 0);
|
||||||
ModelVersion version_100RC1 = new ModelVersion("1.0.0.RC1");
|
ModelVersion version_100CR1 = new ModelVersion("1.0.0.CR1");
|
||||||
ModelVersion version_100 = new ModelVersion("1.0.0");
|
ModelVersion version_100 = new ModelVersion("1.0.0");
|
||||||
ModelVersion version_110Beta1 = new ModelVersion("1.1.0.Beta1");
|
ModelVersion version_110Beta1 = new ModelVersion("1.1.0.Beta1");
|
||||||
ModelVersion version_110RC1 = new ModelVersion("1.1.0.RC1");
|
ModelVersion version_110CR1 = new ModelVersion("1.1.0.CR1");
|
||||||
ModelVersion version_110 = new ModelVersion("1.1.0");
|
ModelVersion version_110 = new ModelVersion("1.1.0");
|
||||||
ModelVersion version_111Beta1 = new ModelVersion("1.1.1.Beta1");
|
ModelVersion version_111Beta1 = new ModelVersion("1.1.1.Beta1");
|
||||||
ModelVersion version_111RC1 = new ModelVersion("1.1.1.RC1");
|
ModelVersion version_111CR1 = new ModelVersion("1.1.1.CR1");
|
||||||
ModelVersion version_111 = new ModelVersion("1.1.1");
|
ModelVersion version_111 = new ModelVersion("1.1.1");
|
||||||
ModelVersion version_211Beta1 = new ModelVersion("2.1.1.Beta1");
|
ModelVersion version_211Beta1 = new ModelVersion("2.1.1.Beta1");
|
||||||
ModelVersion version_211RC1 = new ModelVersion("2.1.1.RC1");
|
ModelVersion version_211CR1 = new ModelVersion("2.1.1.CR1");
|
||||||
Assert.assertEquals(version_211RC1.getMajor(), 2);
|
Assert.assertEquals(version_211CR1.getMajor(), 2);
|
||||||
Assert.assertEquals(version_211RC1.getMinor(), 1);
|
Assert.assertEquals(version_211CR1.getMinor(), 1);
|
||||||
Assert.assertEquals(version_211RC1.getMicro(), 1);
|
Assert.assertEquals(version_211CR1.getMicro(), 1);
|
||||||
Assert.assertEquals(version_211RC1.getQualifier(), "RC1");
|
Assert.assertEquals(version_211CR1.getQualifier(), "CR1");
|
||||||
ModelVersion version_211 = new ModelVersion("2.1.1");
|
ModelVersion version_211 = new ModelVersion("2.1.1");
|
||||||
|
|
||||||
Assert.assertFalse(version_100Beta1.lessThan(version_100Beta1));
|
Assert.assertFalse(version_100Beta1.lessThan(version_100Beta1));
|
||||||
Assert.assertTrue(version_100Beta1.lessThan(version_100RC1));
|
Assert.assertTrue(version_100Beta1.lessThan(version_100CR1));
|
||||||
Assert.assertTrue(version_100Beta1.lessThan(version_100));
|
Assert.assertTrue(version_100Beta1.lessThan(version_100));
|
||||||
Assert.assertTrue(version_100Beta1.lessThan(version_110Beta1));
|
Assert.assertTrue(version_100Beta1.lessThan(version_110Beta1));
|
||||||
Assert.assertTrue(version_100Beta1.lessThan(version_110RC1));
|
Assert.assertTrue(version_100Beta1.lessThan(version_110CR1));
|
||||||
Assert.assertTrue(version_100Beta1.lessThan(version_110));
|
Assert.assertTrue(version_100Beta1.lessThan(version_110));
|
||||||
|
|
||||||
Assert.assertFalse(version_211.lessThan(version_110RC1));
|
Assert.assertFalse(version_211.lessThan(version_110CR1));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue