[Security] handle null values when attempting to parse as DN when mapping roles (elastic/x-pack-elasticsearch#3791)

This commit adds special handling for null values when building a DistinguishedNamePredicate for
role mapping. Previously this would have resulted in an exception from the unboundid ldapsdk as
the DN is invalid.

relates elastic/x-pack-elasticsearch#3787

Original commit: elastic/x-pack-elasticsearch@9386dae03e
This commit is contained in:
Jay Modi 2018-02-06 10:19:49 -07:00 committed by GitHub
parent 20c1791dd8
commit 18c04c714d
2 changed files with 42 additions and 5 deletions

View File

@ -7,9 +7,13 @@ package org.elasticsearch.xpack.security.authc.support;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.util.LDAPSDKUsageException;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.lucene.util.automaton.CharacterRunAutomaton;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.ExpressionModel;
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.FieldExpression;
@ -78,7 +82,7 @@ public interface UserRoleMapper {
model.defineField("dn", dn, new DistinguishedNamePredicate(dn));
model.defineField("groups", groups, groups.stream()
.<Predicate<FieldExpression.FieldValue>>map(DistinguishedNamePredicate::new)
.reduce((a, b) -> a.or(b))
.reduce(Predicate::or)
.orElse(fieldValue -> false)
);
metadata.keySet().forEach(k -> model.defineField("metadata." + k, metadata.get(k)));
@ -155,6 +159,8 @@ public interface UserRoleMapper {
*
*/
class DistinguishedNamePredicate implements Predicate<FieldExpression.FieldValue> {
private static final Logger LOGGER = Loggers.getLogger(DistinguishedNamePredicate.class);
private final String string;
private final DN dn;
@ -164,12 +170,19 @@ public interface UserRoleMapper {
}
private static DN parseDn(String string) {
if (string == null) {
return null;
} else {
try {
return new DN(string);
} catch (LDAPException e) {
} catch (LDAPException | LDAPSDKUsageException e) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace(new ParameterizedMessage("failed to parse [{}] as a DN", string), e);
}
return null;
}
}
}
@Override
public String toString() {
@ -227,7 +240,7 @@ public interface UserRoleMapper {
}
return testString.equalsIgnoreCase(dn.toNormalizedString());
}
return false;
return string == null && fieldValue.getValue() == null;
}
}
}

View File

@ -48,6 +48,30 @@ public class DistinguishedNamePredicateTests extends ESTestCase {
assertPredicate(predicate, null, false);
}
public void testParsingMalformedInput() {
Predicate<FieldValue> predicate = new UserRoleMapper.DistinguishedNamePredicate(null);
assertPredicate(predicate, null, true);
assertPredicate(predicate, "", false);
assertPredicate(predicate, randomAlphaOfLengthBetween(1, 8), false);
predicate = new UserRoleMapper.DistinguishedNamePredicate("");
assertPredicate(predicate, null, false);
assertPredicate(predicate, "", true);
assertPredicate(predicate, randomAlphaOfLengthBetween(1, 8), false);
predicate = new UserRoleMapper.DistinguishedNamePredicate("foo=");
assertPredicate(predicate, null, false);
assertPredicate(predicate, "foo", false);
assertPredicate(predicate, "foo=", true);
assertPredicate(predicate, randomAlphaOfLengthBetween(5, 12), false);
predicate = new UserRoleMapper.DistinguishedNamePredicate("=bar");
assertPredicate(predicate, null, false);
assertPredicate(predicate, "bar", false);
assertPredicate(predicate, "=bar", true);
assertPredicate(predicate, randomAlphaOfLengthBetween(5, 12), false);
}
private void assertPredicate(Predicate<FieldValue> predicate, Object value, boolean expected) {
assertThat("Predicate [" + predicate + "] match [" + value + "]", predicate.test(new FieldValue(value)), equalTo(expected));
}