Improving LDAP filters by escaping characters

This commit is contained in:
Martin Stockhammer 2020-05-10 11:02:54 +02:00
parent 8f6ca402c4
commit ef075525c8
5 changed files with 88 additions and 4 deletions

View File

@ -20,6 +20,7 @@ package org.apache.archiva.redback.authentication.ldap;
*/ */
import org.apache.archiva.redback.authentication.AbstractAuthenticator; import org.apache.archiva.redback.authentication.AbstractAuthenticator;
import org.apache.archiva.redback.common.ldap.LdapUtils;
import org.apache.archiva.redback.common.ldap.connection.DefaultLdapConnection; import org.apache.archiva.redback.common.ldap.connection.DefaultLdapConnection;
import org.apache.archiva.redback.common.ldap.connection.LdapConnection; import org.apache.archiva.redback.common.ldap.connection.LdapConnection;
import org.apache.archiva.redback.common.ldap.user.UserMapper; import org.apache.archiva.redback.common.ldap.user.UserMapper;
@ -100,7 +101,7 @@ public class LdapBindAuthenticator
String filter = "(&(objectClass=" + mapper.getUserObjectClass() + ")" + ( mapper.getUserFilter() != null String filter = "(&(objectClass=" + mapper.getUserObjectClass() + ")" + ( mapper.getUserFilter() != null
? mapper.getUserFilter() ? mapper.getUserFilter()
: "" ) + "(" + mapper.getUserIdAttribute() + "=" + source.getUsername() + "))"; : "" ) + "(" + mapper.getUserIdAttribute() + "=" + LdapUtils.encodeFilterValue( source.getUsername() ) + "))";
log.debug( "Searching for users with filter: '{}' from base dn: {}", filter, mapper.getUserBaseDn() ); log.debug( "Searching for users with filter: '{}' from base dn: {}", filter, mapper.getUserBaseDn() );

View File

@ -137,6 +137,17 @@ public class LdapBindAuthenticatorTest
assertTrue( result.isAuthenticated() ); assertTrue( result.isAuthenticated() );
} }
@Test
public void testAuthenticationWithInvalidChar()
throws Exception
{
PasswordBasedAuthenticationDataSource authDs = new PasswordBasedAuthenticationDataSource();
authDs.setPrincipal( "jesse)(mail=foo" );
authDs.setPassword( passwordEncoder.encodePassword( "foo" ) );
AuthenticationResult result = authnr.authenticate( authDs );
assertFalse( result.isAuthenticated() );
}
// REDBACK-289/MRM-1488 // REDBACK-289/MRM-1488
@Test @Test
public void testAuthenticationFromCache() public void testAuthenticationFromCache()

View File

@ -34,6 +34,28 @@ import javax.naming.ldap.Rdn;
*/ */
public final class LdapUtils public final class LdapUtils
{ {
private static String[] FILTER_ESCAPE_TABLE = new String['\\' + 1];
// Characters that must be escaped in a user filter
static {
// Filter encoding table -------------------------------------
// fill with char itself
for (char c = 0; c < FILTER_ESCAPE_TABLE.length; c++) {
FILTER_ESCAPE_TABLE[c] = String.valueOf(c);
}
// escapes (RFC2254)
FILTER_ESCAPE_TABLE['*'] = "\\2a";
FILTER_ESCAPE_TABLE['('] = "\\28";
FILTER_ESCAPE_TABLE[')'] = "\\29";
FILTER_ESCAPE_TABLE['\\'] = "\\5c";
FILTER_ESCAPE_TABLE[0] = "\\00";
}
private LdapUtils() private LdapUtils()
{ {
// no op // no op
@ -172,4 +194,38 @@ public final class LdapUtils
} }
return ""; return "";
} }
/**
* Escape a value for use in a filter.
* This method is copied from the spring framework class org.springframework.security.ldap.authentication.LdapEncoder
*
* @param value the value to escape.
* @return a properly escaped representation of the supplied value.
*/
public static String encodeFilterValue(String value) {
if (value == null) {
return null;
}
// make buffer roomy
StringBuilder encodedValue = new StringBuilder(value.length() * 2);
int length = value.length();
for (int i = 0; i < length; i++) {
char c = value.charAt(i);
if (c < FILTER_ESCAPE_TABLE.length) {
encodedValue.append(FILTER_ESCAPE_TABLE[c]);
}
else {
// default: add the char
encodedValue.append(c);
}
}
return encodedValue.toString();
}
} }

View File

@ -19,6 +19,7 @@ package org.apache.archiva.redback.users.ldap;
* under the License. * under the License.
*/ */
import org.apache.archiva.redback.common.ldap.LdapUtils;
import org.apache.archiva.redback.common.ldap.user.UserMapper; import org.apache.archiva.redback.common.ldap.user.UserMapper;
import org.apache.archiva.redback.users.AbstractUserQuery; import org.apache.archiva.redback.users.AbstractUserQuery;
@ -49,13 +50,13 @@ public class LdapUserQuery
String filter = ""; String filter = "";
if (this.getEmail() != null ) if (this.getEmail() != null )
{ {
filter += "(" + mapper.getEmailAddressAttribute() + "=" + this.getEmail() + ")"; filter += "(" + mapper.getEmailAddressAttribute() + "=" + LdapUtils.encodeFilterValue( this.getEmail() ) + ")";
} }
if ( this.getFullName() != null ) if ( this.getFullName() != null )
{ {
filter += "(" + mapper.getUserFullNameAttribute() + "=" + this.getFullName() + ")"; filter += "(" + mapper.getUserFullNameAttribute() + "=" + LdapUtils.encodeFilterValue( this.getFullName() ) + ")";
} }
filter += "(" + mapper.getUserIdAttribute() + "=" + ( this.getUsername() != null ? this.getUsername() : "*" ) + ")"; filter += "(" + mapper.getUserIdAttribute() + "=" + ( this.getUsername() != null ? LdapUtils.encodeFilterValue( this.getUsername() ) : "*" ) + ")";
return filter; return filter;
} }

View File

@ -233,6 +233,21 @@ public class LdapUserManagerTest
} }
} }
@Test
public void testUserWithInvalidChars()
throws Exception
{
try
{
userManager.findUser( "jesse)(mail=jesse@apache.org" );
fail( "UserNotFoundException should be thrown, if invalid filter chars are in the username" );
}
catch ( UserNotFoundException e )
{
// cool it works !
}
}
@Test @Test
public void testWithManyUsers() public void testWithManyUsers()
throws Exception throws Exception