/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.milton.ldap;
import io.milton.resource.LdapContact;
import io.milton.common.LogUtils;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.NotAuthorizedException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author brad
*/
class SimpleLdapFilter implements LdapFilter {
private static final Logger log = LoggerFactory.getLogger(SimpleLdapFilter.class);
private final UserFactory userFactory;
private final LdapPropertyMapper propertyMapper;
private final Conditions conditions;
static final String STAR = "*";
final String attributeName;
final String value;
final int mode;
final int operator;
final boolean canIgnore;
SimpleLdapFilter(LdapPropertyMapper propertyMapper, UserFactory userFactory, String attributeName) {
this.userFactory = userFactory;
this.propertyMapper = propertyMapper;
this.conditions = new Conditions(propertyMapper);
this.attributeName = attributeName;
this.value = SimpleLdapFilter.STAR;
this.operator = Ldap.LDAP_FILTER_SUBSTRINGS;
this.mode = 0;
this.canIgnore = checkIgnore();
}
SimpleLdapFilter(LdapPropertyMapper propertyMapper, UserFactory userFactory, String attributeName, String value, int ldapFilterOperator, int ldapFilterMode) {
this.userFactory = userFactory;
this.propertyMapper = propertyMapper;
this.conditions = new Conditions(propertyMapper);
this.attributeName = attributeName;
this.value = value;
this.operator = ldapFilterOperator;
this.mode = ldapFilterMode;
this.canIgnore = checkIgnore();
}
private boolean checkIgnore() {
if ("objectclass".equals(attributeName) && STAR.equals(value)) {
// ignore cases where any object class can match
return true;
// } else if (LdapConnection.CRITERIA_MAP.get(attributeName) == null && LdapUtils.getContactAttributeName(attributeName) == null) {
// log.debug("LOG_LDAP_UNSUPPORTED_FILTER_ATTRIBUTE", attributeName, value);
// return true;
}
return false;
}
@Override
public boolean isFullSearch() {
// only (objectclass=*) is a full search
return "objectclass".equals(attributeName) && STAR.equals(value);
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append('(');
buffer.append(attributeName);
buffer.append('=');
if (SimpleLdapFilter.STAR.equals(value)) {
buffer.append(SimpleLdapFilter.STAR);
} else if (operator == Ldap.LDAP_FILTER_SUBSTRINGS) {
if (mode == Ldap.LDAP_SUBSTRING_FINAL || mode == Ldap.LDAP_SUBSTRING_ANY) {
buffer.append(SimpleLdapFilter.STAR);
}
buffer.append(value);
if (mode == Ldap.LDAP_SUBSTRING_INITIAL || mode == Ldap.LDAP_SUBSTRING_ANY) {
buffer.append(SimpleLdapFilter.STAR);
}
} else {
buffer.append(value);
}
buffer.append(')');
return buffer.toString();
}
@Override
public Condition getContactSearchFilter() {
String contactAttributeName = attributeName;
if (canIgnore || (contactAttributeName == null)) {
return null;
}
Condition condition = null;
if (operator == Ldap.LDAP_FILTER_EQUALITY) {
LogUtils.debug(log, "getContactSearchFilter: equality", value);
condition = conditions.isEqualTo(contactAttributeName, value);
} else if ("*".equals(value)) {
LogUtils.debug(log, "getContactSearchFilter: *");
condition = conditions.not(conditions.isNull(contactAttributeName));
// do not allow substring search on integer field imapUid
} else if (!"imapUid".equals(contactAttributeName)) {
// endsWith not supported by exchange, convert to contains
if (mode == Ldap.LDAP_SUBSTRING_FINAL || mode == Ldap.LDAP_SUBSTRING_ANY) {
LogUtils.debug(log, "getContactSearchFilter: contains", value);
condition = conditions.contains(contactAttributeName, value);
} else {
LogUtils.debug(log, "getContactSearchFilter: startswith", value);
condition = conditions.startsWith(contactAttributeName, value);
}
}
return condition;
}
@Override
public boolean isMatch(LdapContact person) throws NotAuthorizedException, BadRequestException {
if (canIgnore) {
// Ignore this filter
return true;
}
String propValue = propertyMapper.getLdapPropertyValue(attributeName, person);
if (propValue == null) {
// No value to allow for filter match
return false;
} else if (propValue == null) {
// This is a presence filter: found
return true;
} else if ((operator == Ldap.LDAP_FILTER_EQUALITY) && propValue.equalsIgnoreCase(value)) {
// Found an exact match
return true;
} else if ((operator == Ldap.LDAP_FILTER_SUBSTRINGS) && (propValue.toLowerCase().indexOf(value.toLowerCase()) >= 0)) {
// Found a substring match
return true;
}
return false;
}
@Override
public List<LdapContact> findInGAL(LdapPrincipal user, Set<String> returningAttributes, int sizeLimit) throws IOException, NotAuthorizedException, BadRequestException {
if (canIgnore) {
return null;
}
String contactAttributeName = attributeName;
if (contactAttributeName != null) {
// quick fix for cn=* filter
List<LdapContact> galPersons = userFactory.galFind(conditions.startsWith(contactAttributeName, "*".equals(value) ? "A" : value), sizeLimit);
if (operator == Ldap.LDAP_FILTER_EQUALITY) {
// Make sure only exact matches are returned
List<LdapContact> list = new ArrayList<LdapContact>();
for (LdapContact person : galPersons) {
if (isMatch(person)) {
// Found an exact match
list.add(person);
}
}
return list;
} else {
return galPersons;
}
}
return null;
}
@Override
public void add(LdapFilter filter) {
// Should never be called
log.error("LOG_LDAP_UNSUPPORTED_FILTER", "nested simple filters");
}
}