Merge pull request #1944 from mposolda/master

KEYCLOAK-1906 Customized LDAP filter. LDAP conditions improvements
This commit is contained in:
Marek Posolda 2015-12-14 14:50:38 +01:00
commit f837cbfaa9
27 changed files with 308 additions and 319 deletions

View file

@ -14,7 +14,6 @@ import org.keycloak.models.UserFederationProvider;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* *
* TODO: init properties at constructor instead of always compute them
*/ */
public class LDAPConfig { public class LDAPConfig {
@ -147,6 +146,18 @@ public class LDAPConfig {
return rdn; return rdn;
} }
public String getCustomUserSearchFilter() {
String customFilter = config.get(LDAPConstants.CUSTOM_USER_SEARCH_FILTER);
if (customFilter != null) {
customFilter = customFilter.trim();
if (customFilter.length() > 0) {
return customFilter;
}
}
return null;
}
public UserFederationProvider.EditMode getEditMode() { public UserFederationProvider.EditMode getEditMode() {
String editModeString = config.get(LDAPConstants.EDIT_MODE); String editModeString = config.get(LDAPConstants.EDIT_MODE);
if (editModeString == null) { if (editModeString == null) {

View file

@ -5,7 +5,6 @@ import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticat
import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator; import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder; import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder;
import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore; import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore;
@ -209,10 +208,10 @@ public class LDAPFederationProvider implements UserFederationProvider {
// Mapper should replace parameter with correct LDAP mapped attributes // Mapper should replace parameter with correct LDAP mapped attributes
if (attributes.containsKey(FIRST_NAME)) { if (attributes.containsKey(FIRST_NAME)) {
ldapQuery.where(conditionsBuilder.equal(new QueryParameter(FIRST_NAME), attributes.get(FIRST_NAME))); ldapQuery.addWhereCondition(conditionsBuilder.equal(FIRST_NAME, attributes.get(FIRST_NAME)));
} }
if (attributes.containsKey(LAST_NAME)) { if (attributes.containsKey(LAST_NAME)) {
ldapQuery.where(conditionsBuilder.equal(new QueryParameter(LAST_NAME), attributes.get(LAST_NAME))); ldapQuery.addWhereCondition(conditionsBuilder.equal(LAST_NAME, attributes.get(LAST_NAME)));
} }
List<LDAPObject> ldapObjects = ldapQuery.getResultList(); List<LDAPObject> ldapObjects = ldapQuery.getResultList();
@ -287,8 +286,8 @@ public class LDAPFederationProvider implements UserFederationProvider {
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder(); LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
// Mapper should replace "email" in parameter name with correct LDAP mapped attribute // Mapper should replace "email" in parameter name with correct LDAP mapped attribute
Condition emailCondition = conditionsBuilder.equal(new QueryParameter(UserModel.EMAIL), email); Condition emailCondition = conditionsBuilder.equal(UserModel.EMAIL, email);
ldapQuery.where(emailCondition); ldapQuery.addWhereCondition(emailCondition);
return ldapQuery.getFirstResult(); return ldapQuery.getFirstResult();
} }
@ -434,8 +433,8 @@ public class LDAPFederationProvider implements UserFederationProvider {
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder(); LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
String usernameMappedAttribute = this.ldapIdentityStore.getConfig().getUsernameLdapAttribute(); String usernameMappedAttribute = this.ldapIdentityStore.getConfig().getUsernameLdapAttribute();
Condition usernameCondition = conditionsBuilder.equal(new QueryParameter(usernameMappedAttribute), username); Condition usernameCondition = conditionsBuilder.equal(usernameMappedAttribute, username);
ldapQuery.where(usernameCondition); ldapQuery.addWhereCondition(usernameCondition);
LDAPObject ldapUser = ldapQuery.getFirstResult(); LDAPObject ldapUser = ldapQuery.getFirstResult();
if (ldapUser == null) { if (ldapUser == null) {

View file

@ -8,7 +8,6 @@ import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticat
import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator; import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder; import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder;
import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore; import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore;
@ -21,7 +20,6 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakSessionTask; import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserFederationEventAwareProviderFactory; import org.keycloak.models.UserFederationEventAwareProviderFactory;
@ -211,12 +209,12 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
// Sync newly created and updated users // Sync newly created and updated users
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder(); LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
Condition createCondition = conditionsBuilder.greaterThanOrEqualTo(new QueryParameter(LDAPConstants.CREATE_TIMESTAMP), lastSync); Condition createCondition = conditionsBuilder.greaterThanOrEqualTo(LDAPConstants.CREATE_TIMESTAMP, lastSync);
Condition modifyCondition = conditionsBuilder.greaterThanOrEqualTo(new QueryParameter(LDAPConstants.MODIFY_TIMESTAMP), lastSync); Condition modifyCondition = conditionsBuilder.greaterThanOrEqualTo(LDAPConstants.MODIFY_TIMESTAMP, lastSync);
Condition orCondition = conditionsBuilder.orCondition(createCondition, modifyCondition); Condition orCondition = conditionsBuilder.orCondition(createCondition, modifyCondition);
LDAPQuery userQuery = createQuery(sessionFactory, realmId, model); LDAPQuery userQuery = createQuery(sessionFactory, realmId, model);
userQuery.where(orCondition); userQuery.addWhereCondition(orCondition);
UserFederationSyncResult result = syncImpl(sessionFactory, userQuery, realmId, model); UserFederationSyncResult result = syncImpl(sessionFactory, userQuery, realmId, model);
logger.infof("Sync changed users finished: %s", result.getStatus()); logger.infof("Sync changed users finished: %s", result.getStatus());

View file

@ -4,7 +4,9 @@ import java.util.Set;
import org.keycloak.federation.ldap.idm.model.LDAPDn; import org.keycloak.federation.ldap.idm.model.LDAPDn;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder;
import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore; import org.keycloak.federation.ldap.idm.store.ldap.LDAPIdentityStore;
import org.keycloak.federation.ldap.mappers.LDAPFederationMapper; import org.keycloak.federation.ldap.mappers.LDAPFederationMapper;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
@ -51,6 +53,12 @@ public class LDAPUtils {
ldapQuery.setSearchDn(config.getUsersDn()); ldapQuery.setSearchDn(config.getUsersDn());
ldapQuery.addObjectClasses(config.getUserObjectClasses()); ldapQuery.addObjectClasses(config.getUserObjectClasses());
String customFilter = config.getCustomUserSearchFilter();
if (customFilter != null) {
Condition customFilterCondition = new LDAPQueryConditionsBuilder().addCustomLDAPFilter(customFilter);
ldapQuery.addWhereCondition(customFilterCondition);
}
Set<UserFederationMapperModel> mapperModels = realm.getUserFederationMappersByFederationProvider(ldapProvider.getModel().getId()); Set<UserFederationMapperModel> mapperModels = realm.getUserFederationMappersByFederationProvider(ldapProvider.getModel().getId());
ldapQuery.addMappers(mapperModels); ldapQuery.addMappers(mapperModels);

View file

@ -8,11 +8,9 @@ package org.keycloak.federation.ldap.idm.query;
*/ */
public interface Condition { public interface Condition {
/** String getParameterName();
* <p>The {@link QueryParameter} restricted by this condition.</p> void setParameterName(String parameterName);
*
* @return void applyCondition(StringBuilder filter);
*/
QueryParameter getParameter();
} }

View file

@ -1,25 +0,0 @@
package org.keycloak.federation.ldap.idm.query;
/**
* A marker interface indicating that the implementing class can be used as a
* parameter within an IdentityQuery or RelationshipQuery
*
* @author Shane Bryzak
*
*/
public class QueryParameter {
private String name;
public QueryParameter(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View file

@ -5,16 +5,16 @@ package org.keycloak.federation.ldap.idm.query;
*/ */
public class Sort { public class Sort {
private final QueryParameter parameter; private final String paramName;
private final boolean asc; private final boolean asc;
public Sort(QueryParameter parameter, boolean asc) { public Sort(String paramName, boolean asc) {
this.parameter = parameter; this.paramName = paramName;
this.asc = asc; this.asc = asc;
} }
public QueryParameter getParameter() { public String getParameter() {
return this.parameter; return this.paramName;
} }
public boolean isAscending() { public boolean isAscending() {

View file

@ -1,33 +1,36 @@
package org.keycloak.federation.ldap.idm.query.internal; package org.keycloak.federation.ldap.idm.query.internal;
import org.keycloak.federation.ldap.idm.query.Condition; import java.util.Date;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.store.ldap.LDAPUtil;
/** /**
* @author Pedro Igor * @author Pedro Igor
*/ */
public class BetweenCondition implements Condition { class BetweenCondition extends NamedParameterCondition {
private final Comparable x; private final Comparable x;
private final Comparable y; private final Comparable y;
private final QueryParameter parameter;
public BetweenCondition(QueryParameter parameter, Comparable x, Comparable y) { public BetweenCondition(String name, Comparable x, Comparable y) {
this.parameter = parameter; super(name);
this.x = x; this.x = x;
this.y = y; this.y = y;
} }
@Override @Override
public QueryParameter getParameter() { public void applyCondition(StringBuilder filter) {
return this.parameter; Comparable x = this.x;
Comparable y = this.y;
if (Date.class.isInstance(x)) {
x = LDAPUtil.formatDate((Date) x);
} }
public Comparable getX() { if (Date.class.isInstance(y)) {
return this.x; y = LDAPUtil.formatDate((Date) y);
} }
public Comparable getY() { filter.append("(").append(x).append("<=").append(getParameterName()).append("<=").append(y).append(")");
return this.y;
} }
} }

View file

@ -0,0 +1,29 @@
package org.keycloak.federation.ldap.idm.query.internal;
import org.keycloak.federation.ldap.idm.query.Condition;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
class CustomLDAPFilter implements Condition {
private final String customFilter;
public CustomLDAPFilter(String customFilter) {
this.customFilter = customFilter;
}
@Override
public String getParameterName() {
return null;
}
@Override
public void setParameterName(String parameterName) {
}
@Override
public void applyCondition(StringBuilder filter) {
filter.append(customFilter);
}
}

View file

@ -1,34 +1,40 @@
package org.keycloak.federation.ldap.idm.query.internal; package org.keycloak.federation.ldap.idm.query.internal;
import org.keycloak.federation.ldap.idm.query.Condition; import java.util.Date;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.store.ldap.LDAPUtil;
import org.keycloak.models.LDAPConstants;
/** /**
* @author Pedro Igor * @author Pedro Igor
*/ */
public class EqualCondition implements Condition { public class EqualCondition extends NamedParameterCondition {
private final QueryParameter parameter;
private final Object value; private final Object value;
public EqualCondition(QueryParameter parameter, Object value) { public EqualCondition(String name, Object value) {
this.parameter = parameter; super(name);
this.value = value; this.value = value;
} }
@Override
public QueryParameter getParameter() {
return this.parameter;
}
public Object getValue() { public Object getValue() {
return this.value; return this.value;
} }
@Override
public void applyCondition(StringBuilder filter) {
Object parameterValue = value;
if (Date.class.isInstance(value)) {
parameterValue = LDAPUtil.formatDate((Date) parameterValue);
}
filter.append("(").append(getParameterName()).append(LDAPConstants.EQUAL).append(parameterValue).append(")");
}
@Override @Override
public String toString() { public String toString() {
return "EqualCondition{" + return "EqualCondition{" +
"parameter=" + parameter.getName() + "paramName=" + getParameterName() +
", value=" + value + ", value=" + value +
'}'; '}';
} }

View file

@ -1,34 +1,37 @@
package org.keycloak.federation.ldap.idm.query.internal; package org.keycloak.federation.ldap.idm.query.internal;
import java.util.Date;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter; import org.keycloak.federation.ldap.idm.store.ldap.LDAPUtil;
/** /**
* @author Pedro Igor * @author Pedro Igor
*/ */
public class GreaterThanCondition implements Condition { class GreaterThanCondition extends NamedParameterCondition {
private final boolean orEqual; private final boolean orEqual;
private final QueryParameter parameter;
private final Comparable value; private final Comparable value;
public GreaterThanCondition(QueryParameter parameter, Comparable value, boolean orEqual) { public GreaterThanCondition(String name, Comparable value, boolean orEqual) {
this.parameter = parameter; super(name);
this.value = value; this.value = value;
this.orEqual = orEqual; this.orEqual = orEqual;
} }
@Override @Override
public QueryParameter getParameter() { public void applyCondition(StringBuilder filter) {
return this.parameter; Comparable parameterValue = value;
if (Date.class.isInstance(parameterValue)) {
parameterValue = LDAPUtil.formatDate((Date) parameterValue);
} }
public Comparable getValue() { if (orEqual) {
return this.value; filter.append("(").append(getParameterName()).append(">=").append(parameterValue).append(")");
} } else {
filter.append("(").append(getParameterName()).append(">").append(parameterValue).append(")");
public boolean isOrEqual() { }
return this.orEqual;
} }
} }

View file

@ -1,28 +1,31 @@
package org.keycloak.federation.ldap.idm.query.internal; package org.keycloak.federation.ldap.idm.query.internal;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.models.LDAPConstants;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
/** /**
* @author Pedro Igor * @author Pedro Igor
*/ */
public class InCondition implements Condition { class InCondition extends NamedParameterCondition {
private final QueryParameter parameter; private final Object[] valuesToCompare;
private final Object[] value;
public InCondition(QueryParameter parameter, Object[] value) { public InCondition(String name, Object[] valuesToCompare) {
this.parameter = parameter; super(name);
this.value = value; this.valuesToCompare = valuesToCompare;
} }
@Override @Override
public QueryParameter getParameter() { public void applyCondition(StringBuilder filter) {
return this.parameter;
filter.append("(&(");
for (int i = 0; i< valuesToCompare.length; i++) {
Object value = valuesToCompare[i];
filter.append("(").append(getParameterName()).append(LDAPConstants.EQUAL).append(value).append(")");
} }
public Object[] getValue() { filter.append("))");
return this.value;
} }
} }

View file

@ -48,13 +48,11 @@ public class LDAPQuery {
private int searchScope = SearchControls.SUBTREE_SCOPE; private int searchScope = SearchControls.SUBTREE_SCOPE;
private String ldapFilter = null;
public LDAPQuery(LDAPFederationProvider ldapProvider) { public LDAPQuery(LDAPFederationProvider ldapProvider) {
this.ldapFedProvider = ldapProvider; this.ldapFedProvider = ldapProvider;
} }
public LDAPQuery where(Condition... condition) { public LDAPQuery addWhereCondition(Condition... condition) {
this.conditions.addAll(Arrays.asList(condition)); this.conditions.addAll(Arrays.asList(condition));
return this; return this;
} }
@ -191,12 +189,4 @@ public class LDAPQuery {
return this.conditions; return this.conditions;
} }
public String getLdapFilter() {
return ldapFilter;
}
public void setLdapFilter(String ldapFilter) {
this.ldapFilter = ldapFilter;
}
} }

View file

@ -1,7 +1,6 @@
package org.keycloak.federation.ldap.idm.query.internal; package org.keycloak.federation.ldap.idm.query.internal;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.Sort; import org.keycloak.federation.ldap.idm.query.Sort;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
@ -10,38 +9,30 @@ import org.keycloak.models.ModelException;
*/ */
public class LDAPQueryConditionsBuilder { public class LDAPQueryConditionsBuilder {
public Condition like(QueryParameter parameter, String pattern) { public Condition equal(String parameter, Object value) {
return new LikeCondition(parameter, pattern);
}
public Condition equal(QueryParameter parameter, Object value) {
return new EqualCondition(parameter, value); return new EqualCondition(parameter, value);
} }
public Condition greaterThan(QueryParameter parameter, Object x) { public Condition greaterThan(String paramName, Object x) {
throwExceptionIfNotComparable(x); throwExceptionIfNotComparable(x);
return new GreaterThanCondition(parameter, (Comparable) x, false); return new GreaterThanCondition(paramName, (Comparable) x, false);
} }
public Condition greaterThanOrEqualTo(QueryParameter parameter, Object x) { public Condition greaterThanOrEqualTo(String paramName, Object x) {
throwExceptionIfNotComparable(x); throwExceptionIfNotComparable(x);
return new GreaterThanCondition(parameter, (Comparable) x, true); return new GreaterThanCondition(paramName, (Comparable) x, true);
} }
public Condition lessThan(QueryParameter parameter, Object x) { public Condition lessThan(String paramName, Comparable x) {
throwExceptionIfNotComparable(x); return new LessThanCondition(paramName, x, false);
return new LessThanCondition(parameter, (Comparable) x, false);
} }
public Condition lessThanOrEqualTo(QueryParameter parameter, Object x) { public Condition lessThanOrEqualTo(String paramName, Comparable x) {
throwExceptionIfNotComparable(x); return new LessThanCondition(paramName, x, true);
return new LessThanCondition(parameter, (Comparable) x, true);
} }
public Condition between(QueryParameter parameter, Object x, Object y) { public Condition between(String paramName, Comparable x, Comparable y) {
throwExceptionIfNotComparable(x); return new BetweenCondition(paramName, x, y);
throwExceptionIfNotComparable(y);
return new BetweenCondition(parameter, (Comparable) x, (Comparable) y);
} }
public Condition orCondition(Condition... conditions) { public Condition orCondition(Condition... conditions) {
@ -51,16 +42,24 @@ public class LDAPQueryConditionsBuilder {
return new OrCondition(conditions); return new OrCondition(conditions);
} }
public Condition in(QueryParameter parameter, Object... x) { public Condition addCustomLDAPFilter(String filter) {
return new InCondition(parameter, x); filter = filter.trim();
if (!filter.startsWith("(") || !filter.endsWith(")")) {
throw new ModelException("Custom filter doesn't start with ( or doesn't end with ). ");
}
return new CustomLDAPFilter(filter);
} }
public Sort asc(QueryParameter parameter) { public Condition in(String paramName, Object... x) {
return new Sort(parameter, true); return new InCondition(paramName, x);
} }
public Sort desc(QueryParameter parameter) { public Sort asc(String paramName) {
return new Sort(parameter, false); return new Sort(paramName, true);
}
public Sort desc(String paramName) {
return new Sort(paramName, false);
} }
private void throwExceptionIfNotComparable(Object x) { private void throwExceptionIfNotComparable(Object x) {

View file

@ -1,34 +1,37 @@
package org.keycloak.federation.ldap.idm.query.internal; package org.keycloak.federation.ldap.idm.query.internal;
import java.util.Date;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter; import org.keycloak.federation.ldap.idm.store.ldap.LDAPUtil;
/** /**
* @author Pedro Igor * @author Pedro Igor
*/ */
public class LessThanCondition implements Condition { class LessThanCondition extends NamedParameterCondition {
private final boolean orEqual; private final boolean orEqual;
private final QueryParameter parameter;
private final Comparable value; private final Comparable value;
public LessThanCondition(QueryParameter parameter, Comparable value, boolean orEqual) { public LessThanCondition(String name, Comparable value, boolean orEqual) {
this.parameter = parameter; super(name);
this.value = value; this.value = value;
this.orEqual = orEqual; this.orEqual = orEqual;
} }
@Override @Override
public QueryParameter getParameter() { public void applyCondition(StringBuilder filter) {
return this.parameter; Comparable parameterValue = value;
if (Date.class.isInstance(parameterValue)) {
parameterValue = LDAPUtil.formatDate((Date) parameterValue);
} }
public Comparable getValue() { if (orEqual) {
return this.value; filter.append("(").append(getParameterName()).append("<=").append(parameterValue).append(")");
} } else {
filter.append("(").append(getParameterName()).append("<").append(parameterValue).append(")");
public boolean isOrEqual() { }
return this.orEqual;
} }
} }

View file

@ -1,28 +0,0 @@
package org.keycloak.federation.ldap.idm.query.internal;
import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
/**
* @author Pedro Igor
*/
public class LikeCondition implements Condition {
private final QueryParameter parameter;
private final Object value;
public LikeCondition(QueryParameter parameter, Object value) {
this.parameter = parameter;
this.value = value;
}
@Override
public QueryParameter getParameter() {
return this.parameter;
}
public Object getValue() {
return this.value;
}
}

View file

@ -0,0 +1,25 @@
package org.keycloak.federation.ldap.idm.query.internal;
import org.keycloak.federation.ldap.idm.query.Condition;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public abstract class NamedParameterCondition implements Condition {
private String parameterName;
public NamedParameterCondition(String parameterName) {
this.parameterName = parameterName;
}
@Override
public String getParameterName() {
return parameterName;
}
@Override
public void setParameterName(String parameterName) {
this.parameterName = parameterName;
}
}

View file

@ -1,12 +1,11 @@
package org.keycloak.federation.ldap.idm.query.internal; package org.keycloak.federation.ldap.idm.query.internal;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public class OrCondition implements Condition { class OrCondition implements Condition {
private final Condition[] innerConditions; private final Condition[] innerConditions;
@ -14,12 +13,23 @@ public class OrCondition implements Condition {
this.innerConditions = innerConditions; this.innerConditions = innerConditions;
} }
public Condition[] getInnerConditions() { @Override
return innerConditions; public String getParameterName() {
return null;
} }
@Override @Override
public QueryParameter getParameter() { public void setParameterName(String parameterName) {
return null; }
@Override
public void applyCondition(StringBuilder filter) {
filter.append("(|");
for (Condition innerCondition : innerConditions) {
innerCondition.applyCondition(filter);
}
filter.append(")");
} }
} }

View file

@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -28,14 +27,8 @@ import org.keycloak.federation.ldap.LDAPConfig;
import org.keycloak.federation.ldap.idm.model.LDAPDn; import org.keycloak.federation.ldap.idm.model.LDAPDn;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.BetweenCondition;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.federation.ldap.idm.query.internal.EqualCondition; import org.keycloak.federation.ldap.idm.query.internal.EqualCondition;
import org.keycloak.federation.ldap.idm.query.internal.GreaterThanCondition;
import org.keycloak.federation.ldap.idm.query.internal.InCondition;
import org.keycloak.federation.ldap.idm.query.internal.LessThanCondition;
import org.keycloak.federation.ldap.idm.query.internal.OrCondition;
import org.keycloak.federation.ldap.idm.store.IdentityStore; import org.keycloak.federation.ldap.idm.store.IdentityStore;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
import org.keycloak.models.ModelException; import org.keycloak.models.ModelException;
@ -124,20 +117,20 @@ public class LDAPIdentityStore implements IdentityStore {
// Check if we are searching by ID // Check if we are searching by ID
String uuidAttrName = getConfig().getUuidLDAPAttributeName(); String uuidAttrName = getConfig().getUuidLDAPAttributeName();
if (condition.getParameter() != null && condition.getParameter().getName().equalsIgnoreCase(uuidAttrName)) { if (condition instanceof EqualCondition) {
if (EqualCondition.class.isInstance(condition)) {
EqualCondition equalCondition = (EqualCondition) condition; EqualCondition equalCondition = (EqualCondition) condition;
if (equalCondition.getParameterName().equalsIgnoreCase(uuidAttrName)) {
SearchResult search = this.operationManager SearchResult search = this.operationManager
.lookupById(baseDN, equalCondition.getValue().toString(), identityQuery.getReturningLdapAttributes()); .lookupById(baseDN, equalCondition.getValue().toString(), identityQuery.getReturningLdapAttributes());
if (search != null) { if (search != null) {
results.add(populateAttributedType(search, identityQuery)); results.add(populateAttributedType(search, identityQuery));
} }
}
return results; return results;
} }
} }
}
StringBuilder filter = createIdentityTypeSearchFilter(identityQuery); StringBuilder filter = createIdentityTypeSearchFilter(identityQuery);
@ -253,10 +246,7 @@ public class LDAPIdentityStore implements IdentityStore {
StringBuilder filter = new StringBuilder(); StringBuilder filter = new StringBuilder();
for (Condition condition : identityQuery.getConditions()) { for (Condition condition : identityQuery.getConditions()) {
applyCondition(filter, condition); condition.applyCondition(filter);
}
if (!(identityQuery.getLdapFilter() == null || identityQuery.getLdapFilter().isEmpty())) {
filter.append(identityQuery.getLdapFilter());
} }
filter.insert(0, "(&"); filter.insert(0, "(&");
@ -270,95 +260,6 @@ public class LDAPIdentityStore implements IdentityStore {
} }
protected void applyCondition(StringBuilder filter, Condition condition) {
if (OrCondition.class.isInstance(condition)) {
OrCondition orCondition = (OrCondition) condition;
filter.append("(|");
for (Condition innerCondition : orCondition.getInnerConditions()) {
applyCondition(filter, innerCondition);
}
filter.append(")");
return;
}
QueryParameter queryParameter = condition.getParameter();
if (!getConfig().getUuidLDAPAttributeName().equalsIgnoreCase(queryParameter.getName())) {
String attributeName = queryParameter.getName();
if (attributeName != null) {
if (EqualCondition.class.isInstance(condition)) {
EqualCondition equalCondition = (EqualCondition) condition;
Object parameterValue = equalCondition.getValue();
if (Date.class.isInstance(parameterValue)) {
parameterValue = LDAPUtil.formatDate((Date) parameterValue);
}
filter.append("(").append(attributeName).append(LDAPConstants.EQUAL).append(parameterValue).append(")");
} else if (GreaterThanCondition.class.isInstance(condition)) {
GreaterThanCondition greaterThanCondition = (GreaterThanCondition) condition;
Comparable parameterValue = greaterThanCondition.getValue();
if (Date.class.isInstance(parameterValue)) {
parameterValue = LDAPUtil.formatDate((Date) parameterValue);
}
if (greaterThanCondition.isOrEqual()) {
filter.append("(").append(attributeName).append(">=").append(parameterValue).append(")");
} else {
filter.append("(").append(attributeName).append(">").append(parameterValue).append(")");
}
} else if (LessThanCondition.class.isInstance(condition)) {
LessThanCondition lessThanCondition = (LessThanCondition) condition;
Comparable parameterValue = lessThanCondition.getValue();
if (Date.class.isInstance(parameterValue)) {
parameterValue = LDAPUtil.formatDate((Date) parameterValue);
}
if (lessThanCondition.isOrEqual()) {
filter.append("(").append(attributeName).append("<=").append(parameterValue).append(")");
} else {
filter.append("(").append(attributeName).append("<").append(parameterValue).append(")");
}
} else if (BetweenCondition.class.isInstance(condition)) {
BetweenCondition betweenCondition = (BetweenCondition) condition;
Comparable x = betweenCondition.getX();
Comparable y = betweenCondition.getY();
if (Date.class.isInstance(x)) {
x = LDAPUtil.formatDate((Date) x);
}
if (Date.class.isInstance(y)) {
y = LDAPUtil.formatDate((Date) y);
}
filter.append("(").append(x).append("<=").append(attributeName).append("<=").append(y).append(")");
} else if (InCondition.class.isInstance(condition)) {
InCondition inCondition = (InCondition) condition;
Object[] valuesToCompare = inCondition.getValue();
filter.append("(&(");
for (int i = 0; i< valuesToCompare.length; i++) {
Object value = valuesToCompare[i];
filter.append("(").append(attributeName).append(LDAPConstants.EQUAL).append(value).append(")");
}
filter.append("))");
} else {
throw new ModelException("Unsupported query condition [" + condition + "].");
}
}
}
}
private StringBuilder getObjectClassesFilter(Collection<String> objectClasses) { private StringBuilder getObjectClassesFilter(Collection<String> objectClasses) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();

View file

@ -6,7 +6,6 @@ import java.util.Set;
import org.keycloak.federation.ldap.LDAPFederationProvider; import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.EqualCondition; import org.keycloak.federation.ldap.idm.query.internal.EqualCondition;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
@ -105,18 +104,18 @@ public class FullNameLDAPFederationMapper extends AbstractLDAPFederationMapper {
EqualCondition lastNameCondition = null; EqualCondition lastNameCondition = null;
Set<Condition> conditionsCopy = new HashSet<Condition>(query.getConditions()); Set<Condition> conditionsCopy = new HashSet<Condition>(query.getConditions());
for (Condition condition : conditionsCopy) { for (Condition condition : conditionsCopy) {
QueryParameter param = condition.getParameter(); String paramName = condition.getParameterName();
if (param != null) { if (paramName != null) {
if (param.getName().equals(UserModel.FIRST_NAME)) { if (paramName.equals(UserModel.FIRST_NAME)) {
firstNameCondition = (EqualCondition) condition; firstNameCondition = (EqualCondition) condition;
query.getConditions().remove(condition); query.getConditions().remove(condition);
} else if (param.getName().equals(UserModel.LAST_NAME)) { } else if (paramName.equals(UserModel.LAST_NAME)) {
lastNameCondition = (EqualCondition) condition; lastNameCondition = (EqualCondition) condition;
query.getConditions().remove(condition); query.getConditions().remove(condition);
} else if (param.getName().equals(LDAPConstants.GIVENNAME)) { } else if (paramName.equals(LDAPConstants.GIVENNAME)) {
// Some previous mapper already converted it to LDAP name // Some previous mapper already converted it to LDAP name
firstNameCondition = (EqualCondition) condition; firstNameCondition = (EqualCondition) condition;
} else if (param.getName().equals(LDAPConstants.SN)) { } else if (paramName.equals(LDAPConstants.SN)) {
// Some previous mapper already converted it to LDAP name // Some previous mapper already converted it to LDAP name
lastNameCondition = (EqualCondition) condition; lastNameCondition = (EqualCondition) condition;
} }
@ -134,8 +133,8 @@ public class FullNameLDAPFederationMapper extends AbstractLDAPFederationMapper {
} else { } else {
return; return;
} }
EqualCondition fullNameCondition = new EqualCondition(new QueryParameter(ldapFullNameAttrName), fullName); EqualCondition fullNameCondition = new EqualCondition(ldapFullNameAttrName, fullName);
query.getConditions().add(fullNameCondition); query.addWhereCondition(fullNameCondition);
} }
protected String getLdapFullNameAttrName(UserFederationMapperModel mapperModel) { protected String getLdapFullNameAttrName(UserFederationMapperModel mapperModel) {

View file

@ -11,7 +11,6 @@ import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.idm.model.LDAPDn; import org.keycloak.federation.ldap.idm.model.LDAPDn;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder; import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
@ -26,7 +25,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.UserModelDelegate; import org.keycloak.models.utils.UserModelDelegate;
/** /**
* Map realm roles or roles of particular client to LDAP roles * Map realm roles or roles of particular client to LDAP groups
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -131,7 +130,13 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
ldapQuery.addObjectClasses(roleObjectClasses); ldapQuery.addObjectClasses(roleObjectClasses);
String rolesRdnAttr = getRoleNameLdapAttribute(mapperModel); String rolesRdnAttr = getRoleNameLdapAttribute(mapperModel);
ldapQuery.setLdapFilter(mapperModel.getConfig().get(RoleLDAPFederationMapper.ROLES_LDAP_FILTER));
String customFilter = mapperModel.getConfig().get(RoleLDAPFederationMapper.ROLES_LDAP_FILTER);
if (customFilter != null && customFilter.trim().length() > 0) {
Condition customFilterCondition = new LDAPQueryConditionsBuilder().addCustomLDAPFilter(customFilter);
ldapQuery.addWhereCondition(customFilterCondition);
}
String membershipAttr = getMembershipLdapAttribute(mapperModel); String membershipAttr = getMembershipLdapAttribute(mapperModel);
ldapQuery.addReturningLdapAttribute(rolesRdnAttr); ldapQuery.addReturningLdapAttribute(rolesRdnAttr);
ldapQuery.addReturningLdapAttribute(membershipAttr); ldapQuery.addReturningLdapAttribute(membershipAttr);
@ -227,7 +232,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
// Remove membership placeholder if present // Remove membership placeholder if present
for (String membership : memberships) { for (String membership : memberships) {
if (membership.trim().length() == 0) { if (LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE.equals(membership)) {
memberships.remove(membership); memberships.remove(membership);
break; break;
} }
@ -243,7 +248,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
Set<String> memberships = getExistingMemberships(mapperModel, ldapRole); Set<String> memberships = getExistingMemberships(mapperModel, ldapRole);
memberships.remove(ldapUser.getDn().toString()); memberships.remove(ldapUser.getDn().toString());
// Some membership placeholder needs to be always here as "member" is mandatory attribute on some LDAP servers. But not on active directory! (Empty membership is not allowed here) // Some membership placeholder needs to be always here as "member" is mandatory attribute on some LDAP servers. But not on active directory! (Placeholder, which not matches any real object is not allowed here)
if (memberships.size() == 0 && !ldapProvider.getLdapIdentityStore().getConfig().isActiveDirectory()) { if (memberships.size() == 0 && !ldapProvider.getLdapIdentityStore().getConfig().isActiveDirectory()) {
memberships.add(LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE); memberships.add(LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE);
} }
@ -254,8 +259,8 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
public LDAPObject loadLDAPRoleByName(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, String roleName) { public LDAPObject loadLDAPRoleByName(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, String roleName) {
LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider); LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider);
Condition roleNameCondition = new LDAPQueryConditionsBuilder().equal(new QueryParameter(getRoleNameLdapAttribute(mapperModel)), roleName); Condition roleNameCondition = new LDAPQueryConditionsBuilder().equal(getRoleNameLdapAttribute(mapperModel), roleName);
ldapQuery.where(roleNameCondition); ldapQuery.addWhereCondition(roleNameCondition);
return ldapQuery.getFirstResult(); return ldapQuery.getFirstResult();
} }
@ -271,8 +276,8 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
protected List<LDAPObject> getLDAPRoleMappings(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser) { protected List<LDAPObject> getLDAPRoleMappings(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser) {
LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider); LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider);
String membershipAttr = getMembershipLdapAttribute(mapperModel); String membershipAttr = getMembershipLdapAttribute(mapperModel);
Condition membershipCondition = new LDAPQueryConditionsBuilder().equal(new QueryParameter(membershipAttr), ldapUser.getDn().toString()); Condition membershipCondition = new LDAPQueryConditionsBuilder().equal(membershipAttr, ldapUser.getDn().toString());
ldapQuery.where(membershipCondition); ldapQuery.addWhereCondition(membershipCondition);
return ldapQuery.getResultList(); return ldapQuery.getResultList();
} }
@ -431,9 +436,9 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider); LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider);
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder(); LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
Condition roleNameCondition = conditionsBuilder.equal(new QueryParameter(getRoleNameLdapAttribute(mapperModel)), role.getName()); Condition roleNameCondition = conditionsBuilder.equal(getRoleNameLdapAttribute(mapperModel), role.getName());
Condition membershipCondition = conditionsBuilder.equal(new QueryParameter(getMembershipLdapAttribute(mapperModel)), ldapUser.getDn().toString()); Condition membershipCondition = conditionsBuilder.equal(getMembershipLdapAttribute(mapperModel), ldapUser.getDn().toString());
ldapQuery.where(roleNameCondition).where(membershipCondition); ldapQuery.addWhereCondition(roleNameCondition).addWhereCondition(membershipCondition);
LDAPObject ldapRole = ldapQuery.getFirstResult(); LDAPObject ldapRole = ldapQuery.getFirstResult();
if (ldapRole == null) { if (ldapRole == null) {

View file

@ -54,7 +54,7 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
ProviderConfigProperty ldapFilter = createConfigProperty(RoleLDAPFederationMapper.ROLES_LDAP_FILTER, ProviderConfigProperty ldapFilter = createConfigProperty(RoleLDAPFederationMapper.ROLES_LDAP_FILTER,
"LDAP Filter", "LDAP Filter",
"LDAP Filter adds additional custom filter to the whole query.", "LDAP Filter adds additional custom filter to the whole query. Make sure that it starts with '(' and ends with ')'",
ProviderConfigProperty.STRING_TYPE, null); ProviderConfigProperty.STRING_TYPE, null);
configProperties.add(ldapFilter); configProperties.add(ldapFilter);
@ -153,6 +153,11 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
throw new MapperConfigValidationException("Client ID needs to be provided in config when Realm Roles Mapping is not used"); throw new MapperConfigValidationException("Client ID needs to be provided in config when Realm Roles Mapping is not used");
} }
} }
String customLdapFilter = mapperModel.getConfig().get(RoleLDAPFederationMapper.ROLES_LDAP_FILTER);
if ((customLdapFilter != null && customLdapFilter.trim().length() > 0) && (!customLdapFilter.startsWith("(") || !customLdapFilter.endsWith(")"))) {
throw new MapperConfigValidationException("Custom Roles LDAP filter must starts with '(' and ends with ')'");
}
} }
@Override @Override

View file

@ -14,7 +14,6 @@ import org.jboss.logging.Logger;
import org.keycloak.federation.ldap.LDAPFederationProvider; import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
@ -322,9 +321,9 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
// Change conditions and use ldapAttribute instead of userModel // Change conditions and use ldapAttribute instead of userModel
for (Condition condition : query.getConditions()) { for (Condition condition : query.getConditions()) {
QueryParameter param = condition.getParameter(); String paramName = condition.getParameterName();
if (param != null && param.getName().equalsIgnoreCase(userModelAttrName)) { if (paramName != null && paramName.equalsIgnoreCase(userModelAttrName)) {
param.setName(ldapAttrName); condition.setParameterName(ldapAttrName);
} }
} }
} }

View file

@ -149,6 +149,13 @@
<a class="btn btn-primary" data-ng-click="testAuthentication()">Test authentication</a> <a class="btn btn-primary" data-ng-click="testAuthentication()">Test authentication</a>
</div> </div>
</div> </div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="customUserSearchFilter">Custom User LDAP Filter</label>
<div class="col-md-6">
<input class="form-control" id="customUserSearchFilter" type="text" ng-model="instance.config.customUserSearchFilter" placeholder="LDAP Filter">
</div>
<kc-tooltip>Additional LDAP Filter for filtering searched users. Leave this empty if you don't need additional filter. Make sure that it starts with '(' and ends with ')'</kc-tooltip>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label" for="searchScope">Search scope</label> <label class="col-md-2 control-label" for="searchScope">Search scope</label>
<div class="col-md-6"> <div class="col-md-6">

View file

@ -46,6 +46,9 @@ public class LDAPConstants {
// Applicable just for active directory // Applicable just for active directory
public static final String USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE = "userAccountControlsAfterPasswordUpdate"; public static final String USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE = "userAccountControlsAfterPasswordUpdate";
// Custom user search filter
public static final String CUSTOM_USER_SEARCH_FILTER = "customUserSearchFilter";
// Custom attributes on UserModel, which is mapped to LDAP // Custom attributes on UserModel, which is mapped to LDAP
public static final String LDAP_ID = "LDAP_ID"; public static final String LDAP_ID = "LDAP_ID";
public static final String LDAP_ENTRY_DN = "LDAP_ENTRY_DN"; public static final String LDAP_ENTRY_DN = "LDAP_ENTRY_DN";

View file

@ -659,6 +659,45 @@ public class FederationProvidersIntegrationTest {
} }
} }
@Test
public void testSearchWithCustomLDAPFilter() {
// Add custom filter for searching users
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
ldapModel.getConfig().put(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(|(mail=user5@email.org)(mail=user6@email.org))");
appRealm.updateUserFederationProvider(ldapModel);
} finally {
keycloakRule.stopSession(session, true);
}
session = keycloakRule.startSession();
try {
LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
RealmModel appRealm = session.realms().getRealmByName("test");
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username5", "John5", "Doel5", "user5@email.org", null, "125");
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username6", "John6", "Doel6", "user6@email.org", null, "126");
FederationTestUtils.addLDAPUser(ldapProvider, appRealm, "username7", "John7", "Doel7", "user7@email.org", null, "127");
// search by email
session.users().searchForUser("user5@email.org", appRealm);
FederationTestUtils.assertUserImported(session.userStorage(), appRealm, "username5", "John5", "Doel5", "user5@email.org", "125");
session.users().searchForUser("user6@email.org", appRealm);
FederationTestUtils.assertUserImported(session.userStorage(), appRealm, "username6", "John6", "Doel6", "user6@email.org", "126");
session.users().searchForUser("user7@email.org", appRealm);
Assert.assertNull(session.userStorage().getUserByUsername("username7", appRealm));
// Remove custom filter
ldapModel.getConfig().remove(LDAPConstants.CUSTOM_USER_SEARCH_FILTER);
appRealm.updateUserFederationProvider(ldapModel);
} finally {
keycloakRule.stopSession(session, true);
}
}
@Test @Test
public void testUnsynced() { public void testUnsynced() {
KeycloakSession session = keycloakRule.startSession(); KeycloakSession session = keycloakRule.startSession();

View file

@ -15,7 +15,6 @@ import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.LDAPFederationProviderFactory; import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPQuery;
import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder; import org.keycloak.federation.ldap.idm.query.internal.LDAPQueryConditionsBuilder;
import org.keycloak.federation.ldap.mappers.RoleLDAPFederationMapper; import org.keycloak.federation.ldap.mappers.RoleLDAPFederationMapper;
@ -331,8 +330,8 @@ public class LDAPRoleMappingsTest {
private void deleteRoleMappingsInLDAP(UserFederationMapperModel roleMapperModel, RoleLDAPFederationMapper roleMapper, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, String roleName) { private void deleteRoleMappingsInLDAP(UserFederationMapperModel roleMapperModel, RoleLDAPFederationMapper roleMapper, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, String roleName) {
LDAPQuery ldapQuery = roleMapper.createRoleQuery(roleMapperModel, ldapProvider); LDAPQuery ldapQuery = roleMapper.createRoleQuery(roleMapperModel, ldapProvider);
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder(); LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
Condition roleNameCondition = conditionsBuilder.equal(new QueryParameter(LDAPConstants.CN), roleName); Condition roleNameCondition = conditionsBuilder.equal(LDAPConstants.CN, roleName);
ldapQuery.where(roleNameCondition); ldapQuery.addWhereCondition(roleNameCondition);
LDAPObject ldapRole1 = ldapQuery.getFirstResult(); LDAPObject ldapRole1 = ldapQuery.getFirstResult();
roleMapper.deleteRoleMappingInLDAP(roleMapperModel, ldapProvider, ldapUser, ldapRole1); roleMapper.deleteRoleMappingInLDAP(roleMapperModel, ldapProvider, ldapUser, ldapRole1);
} }