Skip to content

Commit

Permalink
KEYCLOAK-1359 more Active Directory fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mposolda committed Jun 5, 2015
1 parent 399a4a0 commit 5b40031
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 20 deletions.
Expand Up @@ -94,12 +94,42 @@ protected void onProviderModelCreated(RealmModel realm, UserFederationProviderMo
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,
Expand Down
Expand Up @@ -24,7 +24,7 @@ public LDAPIdentityStore getLdapStore(UserFederationProviderModel model) {
// 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);
Expand All @@ -34,10 +34,10 @@ public LDAPIdentityStore getLdapStore(UserFederationProviderModel model) {
}

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

/**
Expand Down
Expand Up @@ -75,7 +75,8 @@ public void add(LDAPObject ldapObject) {
}

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()) {
Expand Down
Expand Up @@ -94,6 +94,9 @@ public void onRegisterUserToLDAP(UserFederationMapperModel mapperModel, LDAPFede
// 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
Expand All @@ -105,6 +108,7 @@ protected void syncRolesFromLDAP(UserFederationMapperModel mapperModel, LDAPFede
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);
}
Expand Down
Expand Up @@ -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";
Expand Down
Expand Up @@ -279,15 +279,16 @@ public void testFullNameMapper() {
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 {
Expand Down
Expand Up @@ -67,14 +67,14 @@ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmMod
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");
Expand Down Expand Up @@ -133,7 +133,12 @@ public void test01_ldapOnlyRoleMappings() {
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);

Expand Down
Expand Up @@ -75,6 +75,11 @@ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmMod
.outerRule(ldapRule)
.around(keycloakRule);

// @Test
// public void test01runit() throws Exception {
// Thread.sleep(10000000);
// }

@Test
public void testLDAPSync() {
UsersSyncManager usersSyncManager = new UsersSyncManager();
Expand Down

0 comments on commit 5b40031

Please sign in to comment.