Skip to content

Commit

Permalink
KEYCLOAK-599 Added UserFederationMappers. Added UserAttributeLDAPFede…
Browse files Browse the repository at this point in the history
…rationMapper
  • Loading branch information
mposolda committed May 22, 2015
1 parent 61c3526 commit 1490f10
Show file tree
Hide file tree
Showing 55 changed files with 1,877 additions and 1,976 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public void preRemove(RealmModel realm, RoleModel role) {
* @return
*/
@Override
public boolean isValid(UserModel local) {
public boolean isValid(RealmModel realm, UserModel local) {
return properties.containsKey(local.getUsername());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ public ClasspathPropertiesFederationProvider(KeycloakSession session, UserFedera
* @return
*/
@Override
public UserModel proxy(UserModel local) {
return new ReadonlyUserModelProxy(local);
public UserModel validateAndProxy(RealmModel realm, UserModel local) {
if (isValid(realm, local)) {
return new ReadonlyUserModelProxy(local);
} else {
return null;
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ public FilePropertiesFederationProvider(KeycloakSession session, Properties prop
* @return
*/
@Override
public UserModel proxy(UserModel local) {
return new WritableUserModelProxy(local, this);
public UserModel validateAndProxy(RealmModel realm, UserModel local) {
if (isValid(realm, local)) {
return new WritableUserModelProxy(local, this);
} else {
return null;
}
}

/**
Expand Down Expand Up @@ -65,7 +69,7 @@ public UserModel register(RealmModel realm, UserModel user) {
properties.setProperty(user.getUsername(), "");
save();
}
return proxy(user);
return validateAndProxy(realm, user);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ public KerberosFederationProvider(KeycloakSession session,UserFederationProvider
}

@Override
public UserModel proxy(UserModel local) {
public UserModel validateAndProxy(RealmModel realm, UserModel local) {
if (!isValid(realm, local)) {
return null;
}

if (kerberosConfig.getEditMode() == EditMode.READ_ONLY) {
return new ReadOnlyKerberosUserModelDelegate(local, this);
} else {
Expand Down Expand Up @@ -102,7 +106,7 @@ public void preRemove(RealmModel realm, RoleModel role) {
}

@Override
public boolean isValid(UserModel local) {
public boolean isValid(RealmModel realm, UserModel local) {
// KerberosUsernamePasswordAuthenticator.isUserAvailable is an overhead, so avoid it for now

String kerberosPrincipal = local.getUsername() + "@" + kerberosConfig.getKerberosRealm();
Expand Down Expand Up @@ -219,13 +223,16 @@ protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String usern
if (!model.getId().equals(user.getFederationLink())) {
logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() + "]");
return null;
} else if (isValid(user)) {
return proxy(user);
} else {
logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getDisplayName() +
"] but kerberos principal is not correct. Kerberos principal on user is: " + user.getAttribute(KERBEROS_PRINCIPAL));
logger.warn("Will re-create user");
session.userStorage().removeUser(realm, user);
UserModel proxied = validateAndProxy(realm, user);
if (proxied != null) {
return proxied;
} else {
logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getDisplayName() +
"] but kerberos principal is not correct. Kerberos principal on user is: " + user.getAttribute(KERBEROS_PRINCIPAL));
logger.warn("Will re-create user");
session.userStorage().removeUser(realm, user);
}
}
}

Expand All @@ -248,6 +255,6 @@ protected UserModel importUserToKeycloak(RealmModel realm, String username) {
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
}

return proxy(user);
return validateAndProxy(realm, user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package org.keycloak.federation.ldap;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.naming.directory.SearchControls;

import org.keycloak.models.LDAPConstants;
import org.keycloak.models.UserFederationProviderModel;

/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*
* TODO: init properties at startup instead of always compute them
*/
public class LDAPConfig {

private final Map<String, String> config;

public LDAPConfig(Map<String, String> config) {
this.config = config;
}

public String getConnectionUrl() {
return config.get(LDAPConstants.CONNECTION_URL);
}

public String getFactoryName() {
// hardcoded for now
return "com.sun.jndi.ldap.LdapCtxFactory";
}

public String getAuthType() {
// hardcoded for now
return "simple";
}

public String getSecurityProtocol() {
// hardcoded for now
return config.get(LDAPConstants.SECURITY_PROTOCOL);
}

public Collection<String> getUserDns() {
String value = config.get(LDAPConstants.USER_DNS);
if (value == null) {
return Collections.emptyList();
} else {
return Arrays.asList(value.split(LDAPConstants.CONFIG_DIVIDER));
}
}

public String getSingleUserDn() {
Collection<String> dns = getUserDns();
if (dns.size() == 0) {
throw new IllegalStateException("No user DN configured. User DNS value is " + config.get(LDAPConstants.USER_DNS));
}
return dns.iterator().next();
}

public Collection<String> getObjectClasses() {
String objClassesCfg = config.get(LDAPConstants.USER_OBJECT_CLASSES);
String objClassesStr = (objClassesCfg != null && objClassesCfg.length() > 0) ? objClassesCfg.trim() : "inetOrgPerson,organizationalPerson";

String[] objectClasses = objClassesStr.split(",");

// Trim them
Set<String> userObjClasses = new HashSet<String>();
for (int i=0 ; i<objectClasses.length ; i++) {
userObjClasses.add(objectClasses[i].trim());
}
return userObjClasses;
}

public String getBindDN() {
return config.get(LDAPConstants.BIND_DN);
}

public String getBindCredential() {
return config.get(LDAPConstants.BIND_CREDENTIAL);
}

public String getVendor() {
return config.get(LDAPConstants.VENDOR);
}

public boolean isActiveDirectory() {
String vendor = getVendor();
return vendor != null && vendor.equals(LDAPConstants.VENDOR_ACTIVE_DIRECTORY);
}

public String getConnectionPooling() {
return config.get(LDAPConstants.CONNECTION_POOLING);
}

public Properties getAdditionalConnectionProperties() {
// not supported for now
return null;
}

public int getSearchScope() {
String searchScope = config.get(LDAPConstants.SEARCH_SCOPE);
return searchScope == null ? SearchControls.SUBTREE_SCOPE : Integer.parseInt(searchScope);
}

public String getUuidAttributeName() {
String uuidAttrName = config.get(LDAPConstants.UUID_ATTRIBUTE_NAME);
if (uuidAttrName == null) {
// Differences of unique attribute among various vendors
String vendor = getVendor();
if (vendor != null) {
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;
}

// TODO: Remove and use mapper instead
public boolean isUserAccountControlsAfterPasswordUpdate() {
String userAccountCtrls = config.get(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE);
return userAccountCtrls==null ? false : Boolean.parseBoolean(userAccountCtrls);
}

public boolean isPagination() {
String pagination = config.get(LDAPConstants.PAGINATION);
return pagination==null ? false : Boolean.parseBoolean(pagination);
}

public String getUsernameLdapAttribute() {
String username = config.get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
if (username == null) {
username = isActiveDirectory() ? LDAPConstants.CN : LDAPConstants.UID;
}
return username;
}

public String getRdnLdapAttribute() {
String rdn = config.get(LDAPConstants.RDN_LDAP_ATTRIBUTE);
if (rdn == null) {
rdn = getUsernameLdapAttribute();
}
return rdn;
}
}
Loading

0 comments on commit 1490f10

Please sign in to comment.