/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import org.gluu.site.ldap.persistence.LdapEntryManager;
import org.slf4j.Logger;
import org.xdi.ldap.model.LdapDummyEntry;
import org.xdi.oxauth.model.configuration.BaseFilter;
import org.xdi.util.ArrayHelper;
import org.xdi.util.StringHelper;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPException;
/**
* @author Yuriy Movchan
* @author Yuriy Zabrovarnyy
* @author Javier Rojas Blum
* @version March 4, 2016
*/
public abstract class BaseAuthFilterService {
@Inject
protected Logger log;
public static final Pattern PARAM_VALUE_PATTERN = Pattern.compile("([\\w]+)[\\s]*\\=[\\*\\s]*(\\{[\\s]*[\\d]+[\\s]*\\})[\\*\\s]*");
private boolean enabled;
private boolean filterAttributes = true;
private List<AuthenticationFilterWithParameters> filterWithParameters;
public static class AuthenticationFilterWithParameters {
private BaseFilter authenticationFilter;
private List<String> variableNames;
private List<AuthenticationFilterService.IndexedParameter> indexedVariables;
public AuthenticationFilterWithParameters(BaseFilter authenticationFilter, List<String> variableNames, List<AuthenticationFilterService.IndexedParameter> indexedVariables) {
this.authenticationFilter = authenticationFilter;
this.variableNames = variableNames;
this.indexedVariables = indexedVariables;
}
public BaseFilter getAuthenticationFilter() {
return authenticationFilter;
}
public void setAuthenticationFilter(BaseFilter authenticationFilter) {
this.authenticationFilter = authenticationFilter;
}
public List<String> getVariableNames() {
return variableNames;
}
public void setVariableNames(List<String> variableNames) {
this.variableNames = variableNames;
}
public List<AuthenticationFilterService.IndexedParameter> getIndexedVariables() {
return indexedVariables;
}
public void setIndexedVariables(List<AuthenticationFilterService.IndexedParameter> indexedVariables) {
this.indexedVariables = indexedVariables;
}
public String toString() {
return String.format("AutheticationFilterWithParameters [authenticationFilter=%s, variableNames=%s, indexedVariables=%s]",
authenticationFilter, variableNames, indexedVariables);
}
}
public static class IndexedParameter {
private String paramName;
private String paramIndex;
public IndexedParameter(String paramName, String paramIndex) {
this.paramName = paramName;
this.paramIndex = paramIndex;
}
public String getParamName() {
return paramName;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
public String getParamIndex() {
return paramIndex;
}
public void setParamIndex(String paramIndex) {
this.paramIndex = paramIndex;
}
public String toString() {
return String.format("IndexedParameter [paramName=%s, paramIndex=%s]", paramName, paramIndex);
}
}
public void init(List<? extends BaseFilter> p_filterList, boolean p_enabled, boolean p_filterAttributes) {
this.enabled = p_enabled;
this.filterWithParameters = prepareAuthenticationFilterWithParameters(p_filterList);
this.filterAttributes = p_filterAttributes;
}
private List<AuthenticationFilterWithParameters> prepareAuthenticationFilterWithParameters(List<? extends BaseFilter> p_filterList) {
final List<AuthenticationFilterWithParameters> tmpAuthenticationFilterWithParameters = new ArrayList<AuthenticationFilterWithParameters>();
if (!this.enabled || p_filterList == null) {
return tmpAuthenticationFilterWithParameters;
}
for (BaseFilter authenticationFilter : p_filterList) {
if (Boolean.TRUE.equals(authenticationFilter.getBind()) && StringHelper.isEmpty(authenticationFilter.getBindPasswordAttribute())) {
log.error("Skipping authentication filter:\n '{}'\n. It should contains not empty bind-password-attribute attribute. ", authenticationFilter);
continue;
}
List<String> variableNames = new ArrayList<String>();
List<BaseAuthFilterService.IndexedParameter> indexedParameters = new ArrayList<BaseAuthFilterService.IndexedParameter>();
Matcher matcher = BaseAuthFilterService.PARAM_VALUE_PATTERN.matcher(authenticationFilter.getFilter());
while (matcher.find()) {
String paramName = normalizeAttributeName(matcher.group(1));
String paramIndex = matcher.group(2);
variableNames.add(paramName);
indexedParameters.add(new BaseAuthFilterService.IndexedParameter(paramName, paramIndex));
}
AuthenticationFilterWithParameters tmpAutheticationFilterWithParameter = new AuthenticationFilterWithParameters(authenticationFilter, variableNames, indexedParameters);
tmpAuthenticationFilterWithParameters.add(tmpAutheticationFilterWithParameter);
log.debug("Authentication filter with parameters: '{}'. ", tmpAutheticationFilterWithParameter);
}
return tmpAuthenticationFilterWithParameters;
}
public static List<AuthenticationFilterWithParameters> getAllowedAuthenticationFilters(Collection<?> attributeNames, List<AuthenticationFilterWithParameters> p_filterList) {
List<AuthenticationFilterWithParameters> tmpAuthenticationFilterWithParameters = new ArrayList<AuthenticationFilterWithParameters>();
if (attributeNames == null) {
return tmpAuthenticationFilterWithParameters;
}
Set<String> normalizedAttributeNames = new HashSet<String>();
for (Object attributeName : attributeNames) {
normalizedAttributeNames.add(normalizeAttributeName(attributeName.toString()));
}
for (AuthenticationFilterWithParameters autheticationFilterWithParameters : p_filterList) {
if (normalizedAttributeNames.containsAll(autheticationFilterWithParameters.getVariableNames())) {
tmpAuthenticationFilterWithParameters.add(autheticationFilterWithParameters);
}
}
return tmpAuthenticationFilterWithParameters;
}
public static Map<String, String> normalizeAttributeMap(Map<?, ?> attributeValues) {
Map<String, String> normalizedAttributeValues = new HashMap<String, String>();
for (Map.Entry<?, ?> attributeValueEntry : attributeValues.entrySet()) {
String attributeValue = null;
Object attributeValueEntryValue = attributeValueEntry.getValue();
if (attributeValueEntryValue instanceof String[]) {
if (ArrayHelper.isNotEmpty((String[]) attributeValueEntryValue)) {
attributeValue = ((String[]) attributeValueEntryValue)[0];
}
} else if (attributeValueEntryValue instanceof String) {
attributeValue = (String) attributeValueEntryValue;
} else if (attributeValueEntryValue != null) {
attributeValue = attributeValueEntryValue.toString();
}
if (attributeValue != null) {
normalizedAttributeValues.put(normalizeAttributeName(attributeValueEntry.getKey().toString()), attributeValue);
}
}
return normalizedAttributeValues;
}
public static String buildFilter(AuthenticationFilterWithParameters authenticationFilterWithParameters, Map<String, String> p_normalizedAttributeValues) {
String filter = authenticationFilterWithParameters.getAuthenticationFilter().getFilter();
for (IndexedParameter indexedParameter : authenticationFilterWithParameters.getIndexedVariables()) {
String attributeValue = p_normalizedAttributeValues.get(indexedParameter.getParamName());
if (attributeValue != null) {
filter = filter.replace(indexedParameter.getParamIndex(), attributeValue);
}
}
return filter;
}
public String loadEntryDN(LdapEntryManager p_manager, AuthenticationFilterWithParameters authenticationFilterWithParameters, Map<String, String> normalizedAttributeValues) {
final String filter = buildFilter(authenticationFilterWithParameters, normalizedAttributeValues);
Filter ldapFilter;
try {
ldapFilter = Filter.create(filter);
} catch (LDAPException ex) {
log.error("Failed to create Ldap filter: '{}'", ex, filter);
return null;
}
List<LdapDummyEntry> foundEntries = p_manager.findEntries(authenticationFilterWithParameters.getAuthenticationFilter().getBaseDn(), LdapDummyEntry.class, new String[0], ldapFilter);
if (foundEntries.size() > 1) {
log.error("Found more than one entry by filter: '{}'. Entries:\n", ldapFilter, foundEntries);
return null;
}
if (!(foundEntries.size() == 1)) {
return null;
}
return foundEntries.get(0).getDn();
}
public String processAuthenticationFilters(Map<?, ?> attributeValues) {
if (attributeValues == null) {
return null;
}
final List<AuthenticationFilterWithParameters> allowedList = filterAttributes ?
getAllowedAuthenticationFilters(attributeValues.keySet(), getFilterWithParameters()) :
getFilterWithParameters();
for (AuthenticationFilterWithParameters allowed : allowedList) {
String resultDn = processAuthenticationFilter(allowed, attributeValues);
if (StringHelper.isNotEmpty(resultDn)) {
return resultDn;
}
}
return null;
}
public abstract String processAuthenticationFilter(AuthenticationFilterWithParameters p_allowed, Map<?, ?> p_attributeValues);
public List<AuthenticationFilterWithParameters> getFilterWithParameters() {
return filterWithParameters;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean p_enabled) {
enabled = p_enabled;
}
public boolean isFilterAttributes() {
return filterAttributes;
}
public void setFilterAttributes(boolean p_filterAttributes) {
filterAttributes = p_filterAttributes;
}
public static String normalizeAttributeName(String attributeName) {
return StringHelper.toLowerCase(attributeName.trim());
}
}