Merge pull request #1334 from mposolda/ldap

KEYCLOAK-1359 more Active Directory fixes
This commit is contained in:
Marek Posolda 2015-06-05 11:59:08 +02:00
commit d958d85290
8 changed files with 66 additions and 20 deletions

View file

@ -94,12 +94,42 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
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("full name", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
// CN is typically used as RDN for Active Directory deployments
if (ldapConfig.getRdnLdapAttribute().equalsIgnoreCase(LDAPConstants.CN)) {
if (usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.CN)) {
// For AD deployments with "cn" as username, we will map "givenName" to first name
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.GIVENNAME,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
} else {
if (editMode == UserFederationProvider.EditMode.WRITABLE) {
// For AD deployments with "sAMAccountName" as username and writable, we need to map "cn" as username as well (this is needed so we can register new users from KC into LDAP) and we will map "givenName" to first name.
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.GIVENNAME,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("username2", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.USERNAME,
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.CN,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
} else {
// For read-only LDAP, we map "cn" as full name
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("full name", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
}
}
} else {
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,

View file

@ -24,7 +24,7 @@ public class LDAPIdentityStoreRegistry {
// Ldap config might have changed for the realm. In this case, we must re-initialize
Map<String, String> config = model.getConfig();
if (context == null || !config.equals(context.config)) {
logLDAPConfig(model.getId(), config);
logLDAPConfig(model.getDisplayName(), config);
LDAPIdentityStore store = createLdapIdentityStore(config);
context = new LDAPIdentityStoreContext(config, store);
@ -34,10 +34,10 @@ public class LDAPIdentityStoreRegistry {
}
// Don't log LDAP password
private void logLDAPConfig(String fedProviderId, Map<String, String> ldapConfig) {
private void logLDAPConfig(String fedProviderDisplayName, Map<String, String> ldapConfig) {
Map<String, String> copy = new HashMap<String, String>(ldapConfig);
copy.remove(LDAPConstants.BIND_CREDENTIAL);
logger.infof("Creating new LDAP based partition manager for the Federation provider: " + fedProviderId + ", LDAP Configuration: " + copy);
logger.infof("Creating new LDAP based partition manager for the Federation provider: " + fedProviderDisplayName + ", LDAP Configuration: " + copy);
}
/**

View file

@ -75,7 +75,8 @@ public class LDAPIdentityStore implements IdentityStore {
}
String entryDN = ldapObject.getDn().toString();
this.operationManager.createSubContext(entryDN, extractAttributes(ldapObject, true));
BasicAttributes ldapAttributes = extractAttributes(ldapObject, true);
this.operationManager.createSubContext(entryDN, ldapAttributes);
ldapObject.setUuid(getEntryIdentifier(ldapObject));
if (logger.isTraceEnabled()) {

View file

@ -94,6 +94,9 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
// Sync roles from LDAP tree and create them in local Keycloak DB (if they don't exist here yet)
protected void syncRolesFromLDAP(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, RealmModel realm) {
if (!rolesSyncedModels.contains(mapperModel.getId())) {
// TODO: debug
logger.infof("Syncing roles from LDAP into Keycloak DB. Mapper is [%s], LDAP provider is [%s]", mapperModel.getName(), ldapProvider.getModel().getDisplayName());
LDAPIdentityQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider);
// Send query
@ -105,6 +108,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
String roleName = ldapRole.getAttributeAsString(rolesRdnAttr);
if (roleContainer.getRole(roleName) == null) {
// TODO: debug
logger.infof("Syncing role [%s] from LDAP to keycloak DB", roleName);
roleContainer.addRole(roleName);
}

View file

@ -52,7 +52,7 @@ public class LDAPConstants {
public static final String CONFIG_DIVIDER = ":::";
// Those are forked from Picketlink
public static final String GIVENNAME = "givenname";
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";

View file

@ -279,15 +279,16 @@ public class FederationProvidersIntegrationTest {
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "fullname", "James Dee", "Dee", "fullname@email.org", "4578");
// add fullname mapper to the provider and remove "firstNameMapper"
// add fullname mapper to the provider and remove "firstNameMapper". For this test, we will simply map full name to the LDAP attribute, which was before firstName ( "givenName" on active directory, "cn" on other LDAP servers)
firstNameMapper = appRealm.getUserFederationMapperByName(ldapModel.getId(), "first name");
String ldapFirstNameAttributeName = firstNameMapper.getConfig().get(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE);
appRealm.removeUserFederationMapper(firstNameMapper);
UserFederationMapperModel fullNameMapperModel = KeycloakModelUtils.createUserFederationMapperModel("full name", ldapModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, ldapFirstNameAttributeName,
UserAttributeLDAPFederationMapper.READ_ONLY, "false");
appRealm.addUserFederationMapper(fullNameMapperModel);
firstNameMapper = appRealm.getUserFederationMapperByName(ldapModel.getId(), "first name");
appRealm.removeUserFederationMapper(firstNameMapper);
// Assert user is successfully imported in Keycloak DB now with correct firstName and lastName
FederationTestUtils.assertUserImported(session.users(), appRealm, "fullname", "James", "Dee", "fullname@email.org", "4578");
} finally {

View file

@ -67,14 +67,14 @@ public class LDAPRoleMappingsTest {
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
FederationTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
// Add sample application
ClientModel finance = appRealm.addClient("finance");
// Delete all LDAP roles
FederationTestUtils.addOrUpdateRoleLDAPMappers(appRealm, ldapModel, RoleLDAPFederationMapper.Mode.LDAP_ONLY);
FederationTestUtils.removeAllLDAPRoles(manager.getSession(), appRealm, ldapModel, "realmRolesMapper");
FederationTestUtils.removeAllLDAPRoles(manager.getSession(), appRealm, ldapModel, "financeRolesMapper");
// Add sample application
ClientModel finance = appRealm.addClient("finance");
// Add some users for testing
LDAPObject john = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", "1234");
ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
@ -133,7 +133,12 @@ public class LDAPRoleMappingsTest {
RoleModel realmRole2 = appRealm.getRole("realmRole2");
mary.grantRole(realmRole2);
RoleModel realmRole3 = appRealm.addRole("realmRole3");
// This role may already exists from previous test (was imported from LDAP), but may not
RoleModel realmRole3 = appRealm.getRole("realmRole3");
if (realmRole3 == null) {
realmRole3 = appRealm.addRole("realmRole3");
}
john.grantRole(realmRole3);
mary.grantRole(realmRole3);

View file

@ -75,6 +75,11 @@ public class SyncProvidersTest {
.outerRule(ldapRule)
.around(keycloakRule);
// @Test
// public void test01runit() throws Exception {
// Thread.sleep(10000000);
// }
@Test
public void testLDAPSync() {
UsersSyncManager usersSyncManager = new UsersSyncManager();