parent
a29c30ccd5
commit
512e30b210
4 changed files with 40 additions and 17 deletions
|
@ -431,16 +431,16 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
|||
|
||||
// Mapper should replace parameter with correct LDAP mapped attributes
|
||||
if (attributes.containsKey(UserModel.USERNAME)) {
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.equal(UserModel.USERNAME, attributes.get(UserModel.USERNAME), EscapeStrategy.NON_ASCII_CHARS_ONLY));
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.equal(UserModel.USERNAME, attributes.get(UserModel.USERNAME), EscapeStrategy.DEFAULT_EXCEPT_ASTERISK));
|
||||
}
|
||||
if (attributes.containsKey(UserModel.EMAIL)) {
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.equal(UserModel.EMAIL, attributes.get(UserModel.EMAIL), EscapeStrategy.NON_ASCII_CHARS_ONLY));
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.equal(UserModel.EMAIL, attributes.get(UserModel.EMAIL), EscapeStrategy.DEFAULT_EXCEPT_ASTERISK));
|
||||
}
|
||||
if (attributes.containsKey(UserModel.FIRST_NAME)) {
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.equal(UserModel.FIRST_NAME, attributes.get(UserModel.FIRST_NAME), EscapeStrategy.NON_ASCII_CHARS_ONLY));
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.equal(UserModel.FIRST_NAME, attributes.get(UserModel.FIRST_NAME), EscapeStrategy.DEFAULT_EXCEPT_ASTERISK));
|
||||
}
|
||||
if (attributes.containsKey(UserModel.LAST_NAME)) {
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.equal(UserModel.LAST_NAME, attributes.get(UserModel.LAST_NAME), EscapeStrategy.NON_ASCII_CHARS_ONLY));
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.equal(UserModel.LAST_NAME, attributes.get(UserModel.LAST_NAME), EscapeStrategy.DEFAULT_EXCEPT_ASTERISK));
|
||||
}
|
||||
// for all other searchable fields: Ignoring is the fallback option, since it may overestimate the results but does not ignore matches.
|
||||
// for empty params: all users are returned (pagination applies)
|
||||
|
@ -476,10 +476,10 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
|||
s += "*";
|
||||
}
|
||||
|
||||
conditions.add(conditionsBuilder.equal(UserModel.USERNAME, s.trim().toLowerCase(), EscapeStrategy.NON_ASCII_CHARS_ONLY));
|
||||
conditions.add(conditionsBuilder.equal(UserModel.EMAIL, s.trim().toLowerCase(), EscapeStrategy.NON_ASCII_CHARS_ONLY));
|
||||
conditions.add(conditionsBuilder.equal(UserModel.FIRST_NAME, s, EscapeStrategy.NON_ASCII_CHARS_ONLY));
|
||||
conditions.add(conditionsBuilder.equal(UserModel.LAST_NAME, s, EscapeStrategy.NON_ASCII_CHARS_ONLY));
|
||||
conditions.add(conditionsBuilder.equal(UserModel.USERNAME, s.trim().toLowerCase(), EscapeStrategy.DEFAULT_EXCEPT_ASTERISK));
|
||||
conditions.add(conditionsBuilder.equal(UserModel.EMAIL, s.trim().toLowerCase(), EscapeStrategy.DEFAULT_EXCEPT_ASTERISK));
|
||||
conditions.add(conditionsBuilder.equal(UserModel.FIRST_NAME, s, EscapeStrategy.DEFAULT_EXCEPT_ASTERISK));
|
||||
conditions.add(conditionsBuilder.equal(UserModel.LAST_NAME, s, EscapeStrategy.DEFAULT_EXCEPT_ASTERISK));
|
||||
|
||||
ldapQuery.addWhereCondition(conditionsBuilder.orCondition(conditions.toArray(Condition[]::new)));
|
||||
}
|
||||
|
|
|
@ -24,17 +24,35 @@ import java.nio.charset.StandardCharsets;
|
|||
*/
|
||||
public enum EscapeStrategy {
|
||||
|
||||
|
||||
// LDAP special characters like * ( ) \ are not escaped. Only non-ASCII characters like é are escaped
|
||||
NON_ASCII_CHARS_ONLY {
|
||||
/**
|
||||
* LDAP special character * is not escaped, other special characters are escaped. Non-ASCII characters like é are escaped.
|
||||
* Use it for searches where wildcards are allowed.
|
||||
*/
|
||||
DEFAULT_EXCEPT_ASTERISK {
|
||||
|
||||
@Override
|
||||
public String escape(String input) {
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
for (byte b : input.getBytes(StandardCharsets.UTF_8)) {
|
||||
switch (b) {
|
||||
case 0x5c:
|
||||
output.append("\\5c"); // \
|
||||
break;
|
||||
case 0x28:
|
||||
output.append("\\28"); // (
|
||||
break;
|
||||
case 0x29:
|
||||
output.append("\\29"); // )
|
||||
break;
|
||||
case 0x00:
|
||||
output.append("\\00"); // \u0000
|
||||
break;
|
||||
default: {
|
||||
appendByte(b, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output.toString();
|
||||
}
|
||||
|
@ -42,7 +60,9 @@ public enum EscapeStrategy {
|
|||
},
|
||||
|
||||
|
||||
// Escaping of LDAP special characters including non-ASCII characters like é
|
||||
/**
|
||||
* Escaping of LDAP special characters including non-ASCII characters like é.
|
||||
*/
|
||||
DEFAULT {
|
||||
|
||||
|
||||
|
|
|
@ -27,16 +27,16 @@ import org.keycloak.storage.ldap.idm.query.EscapeStrategy;
|
|||
public class EscapeTest {
|
||||
|
||||
@Test
|
||||
public void testNoAsciiOnlyEscaping() throws Exception {
|
||||
public void testEscapingExceptAsterisk() {
|
||||
String text = "Véronique* Martin(john)second\\fff//eee\u0000";
|
||||
Assert.assertEquals(EscapeStrategy.NON_ASCII_CHARS_ONLY.escape(text), "V\\c3\\a9ronique* Martin(john)second\\fff//eee\u0000");
|
||||
Assert.assertEquals(EscapeStrategy.DEFAULT_EXCEPT_ASTERISK.escape(text), "V\\c3\\a9ronique* Martin\\28john\\29second\\5cfff//eee\\00");
|
||||
|
||||
text = "Hi This is a test #çà";
|
||||
Assert.assertEquals(EscapeStrategy.DEFAULT.escape(text), "Hi This is a test #\\c3\\a7\\c3\\a0");
|
||||
Assert.assertEquals(EscapeStrategy.DEFAULT_EXCEPT_ASTERISK.escape(text), "Hi This is a test #\\c3\\a7\\c3\\a0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEscaping() throws Exception {
|
||||
public void testEscaping() {
|
||||
String text = "Véronique* Martin(john)second\\fff//eee\u0000";
|
||||
Assert.assertEquals(EscapeStrategy.DEFAULT.escape(text), "V\\c3\\a9ronique\\2a Martin\\28john\\29second\\5cfff//eee\\00");
|
||||
|
||||
|
|
|
@ -1023,6 +1023,9 @@ public class LDAPProvidersIntegrationTest extends AbstractLDAPTest {
|
|||
// search by a string that matches multiple fields. Should still return the one entity it matches.
|
||||
Assert.assertEquals(1, session.users().searchForUserStream(appRealm, "*11*").count());
|
||||
LDAPTestAsserts.assertUserImported(UserStoragePrivateUtil.userLocalStorage(session), appRealm, "username11", "John11", "Doel11", "user11@email.org", "124");
|
||||
|
||||
// search by a string that has special characters. Should succeed with an empty set, but no exceptions.
|
||||
Assert.assertEquals(0, session.users().searchForUserStream(appRealm, "John)").count());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue