SEC-1661: LDAP search base should not require JNDI escaping in addition to LDAP escaping for special characters #1899

Closed
spring-issuemaster opened this Issue Jan 25, 2011 · 7 comments

1 participant

@spring-issuemaster

Jason Konicki (Migrated from SEC-1661) said:

Having double quotes in the base dn (search base) does not work.

The following base dn value is valid, but does not work:

  • OU="Admin Users",OU=TEST-NC,DC=TESTCustomers,DC=Com
@spring-issuemaster

Luke Taylor said:

If you are reporting an issue, please check with the latest release (3.0.5 in this case).

The DN you've given here is not valid - it would be rejected if you entered it in an LDIF file and attempted to import it into a directory. Likewise if you used it as an argument to any LDAP operation. Quotes in DNs need to be escaped. If the name in the directory contains quotes then you need to use ou= \"Admin Users\".

Escaping is further complicated when used from Java, because of JNDI, see:

http://download.oracle.com/javase/jndi/tutorial/beyond/names/syntax.html

so it wouldn't surprise me if there were other bugs in this area, but "does not work" isn't much to go on. Please explain what the directory entries contain, what configuration parameters you are using (make sure DN strings are LDAP escaped), what exceptions occur (if any) and what actually goes wrong.

@spring-issuemaster

Jason Konicki said:

Sorry about the lack of information:

I also tested with latest code from git and modified the BindAuthenticatorTests to test the quoted string, but it failed.

Here is the stacktrace when the quoted string is used instead of the non-quoted string:
org.springframework.security.authentication.BadCredentialsException: Bad credentials
at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.authenticate(LdapAuthenticationProvider.java:266)
at com.hyperic.hq.security.LdapHQAuthenticationProvider.authenticateFromSearchBase(LdapHQAuthenticationProvider.java:198)
at com.hyperic.hq.security.LdapHQAuthenticationProvider.authenticate(LdapHQAuthenticationProvider.java:165)
at org.hyperic.hq.security.InternalAuthenticationProvider.authenticate(InternalAuthenticationProvider.java:88)
at org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:121)
at org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:49)
at org.hyperic.hq.auth.server.session.AuthManagerImpl.authenticate(AuthManagerImpl.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
at org.hyperic.hq.monitor.aop.aspects.PerformanceMonitor.monitorServiceMethod(PerformanceMonitor.java:84)
at sun.reflect.GeneratedMethodAccessor324.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:622)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:611)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:108)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy46.authenticate(Unknown Source)

@spring-issuemaster

Luke Taylor said:

Ok, this still doesn't clear up what the directory contains or what the configuration valuues are. If you write a basic Java LDAP test:

    Hashtable<String,String> env = new Hashtable<String,String>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, "ldap://127.0.0.1:22389/dc=springsource,dc=com"); // use your URL
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL, "cn=admin,dc=springsource,dc=com"); // use whatever username and credentials you need to perform the search
    env.put(Context.SECURITY_CREDENTIALS, "password");

    InitialDirContext idc = new InitialDirContext(env);
    SearchControls searchControls = new SearchControls();
    searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

    String baseDn = ?
    String username = ?

    NamingEnumeration<SearchResult> matches = idc.search(baseDn, "(cn={0})", new Object[] {username}, searchControls);

    while(matches.hasMore()) {
        SearchResult match = matches.next();
        System.out.println("**** Match: " +match.getName());

    }

Then what value of the string "baseDn" gives you a match on a valid username?

@spring-issuemaster

Luke Taylor said:

I've added the use of an LDAP DistinguishedName to the baseDn to avoid the need for JNDI escaping (see the link to the Java Tutorial above). However, the string still needs to be LDAP escaped in the configuration if it contains any special characters.

@spring-issuemaster

Luke Taylor said:

Does the DN in the directory actually contain quotes?

If not, then they shouldn't be there in the configuration (either escaped or otherwise).

It looks like you are saying that the system should treat one with quotes as if they weren't there - i.e. that the original system treated DNs with and without the quotes in the same way. I'd regard that as a bug in the original system. Since quotes are valid content in a DN, if the actual value contained in the directory doesn't have any nor should the value you use to represent it elsewhere.

@spring-issuemaster

Jason Konicki said:

Luke,

I received feedback from the customer, their DN was "OU=Admin-Users,OU=TEST-NC,DC=TESTCustomers,DC=Com" (without the quotes around Admin-Users).
So it appears that the other 3rdparty Ldap must have been stripping off the quotes which would not be correct as you said.

Thanks for the clarification on this issue.

@spring-issuemaster

Luke Taylor said:

The initial report is essentially invalid, so changing the title to reflect the minor change to the code that has actually been made - i.e. the search base should now only require LDAP escaping.

@spring-issuemaster spring-issuemaster added this to the 3.1.0.RC1 milestone Feb 5, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment