views:

623

answers:

1

I am using Nexus repository manager (nexus.sonatype.org) with the open source LDAP plugin (code.google.com/p/nexus-ldap/) and I get an error indicating that the wrong protocol version is used (details below). All the plugin does is using the JNDI LDAP service provider to connect to my LDAP Server. If you look at the stack trace in the nexus.log file the exception occurs during context initialization in the JNDI LDAP implementation. So my guess is, the problem described below is not caused by the Nexus plugin but by a misusage of JNDI or misunderstanding of LDAP authentication.

Any guess or idea on how this is error is caused is much appreciated!

What steps will reproduce the problem?

  1. Configure Nexus to use the LdapAuthenticatingRealm using an OpenLDAP 1.2.x server - therefor version 2 of the LDAP protocol.
  2. Try listing users from the OpenLDAP-Server and mapping them to roles in the Nexus config UI - works perfectly.
  3. Now try to log in to or authenticate against the running Nexus instance by using a LDAP-User that was mapped to a role succesfully.

What is the expected output? What do you see instead?

While trying to log in I get the error message "Incorrect username, password or no permission to use the Nexus User Interface. Try again.". In the Nexus log file I see an exception thrown when the JNDI-LDAP-implementation by Sun (see stack trace taken from the log file below) tries to initialize a context with the given information in order to authenticate the user against the LDAP server. The user lookup using the Nexus UI works fine as well as the lookup performed during authentication (see log file below).

The error message contained in the CommunicationException ("[LDAP: error code 2 - version not supported]") indicates the usage of a wrong LDAP protocol version. I tried to explicitly use the protocol version 2 since the OpenLDAP version 1.2.7-30 only supports LDAP v2 (corporate environment - server version not negotiable). I did so by checking out your source code, adding the line "env.put("java.naming.ldap.version", "2");" to se.devoteam.nexus.ldap.NexusLdapContextFactory:52. Nothing changed.

During testing I realized while browsing through the Sun source code that the first thing the javax.naming.ldap.InitialLdapContext.InitialLdapContext()-method does is setting the ldap protocol version to "3" (javax.naming.ldap.InitialLdapContext:131). Although the Java6-documentation explains the property (java.sun[dot]com/javase/6/docs/technotes/guides/jndi/jndi-ldap-gl.html#version) I used and the JNDI-tutorial mentions this as the proper way to solve protocol version conflicts (java.sun[dot]com/products/jndi/tutorial/ldap/misc/version.html) I wonder: Is there a way at all to explicitly use the LDAP protocol version 2 when using JNDI as a LDAP service provider?

Next I tried using a rather up-to-date version of the OpenLDAP server (openldap2-2.3) as a proxy for LDAP protocol version 3 requests which would delegate them to the older server. Same problem, same exception.

Additional information

Environment: Nexus Webapp deployed on a Tomcat 6.0.16 Nexus version: 1.3.6 ldap-realm version: 0.4 JRE version: JDK 1.6.0_14-b08 Platform: Virtual Environment LDAP Directory brand: OpenLDAP 1.2.7 and 2.2.3

Relevant part of the nexus.log:

2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - o.s.j.r.PlexusSecur~          - Realm: 'org.sonatype.jsecurity.realms.XmlAuthenticatingRealm', caused: User 'testuser' cannot be retrieved.
org.jsecurity.authc.AccountException: User 'testuser' cannot be retrieved.
    at org.sonatype.jsecurity.realms.XmlAuthenticatingRealm.doGetAuthenticationInfo(XmlAuthenticatingRealm.java:68)
    at org.jsecurity.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:168)
    at org.sonatype.jsecurity.web.WebPlexusSecurity.getAuthenticationInfo(WebPlexusSecurity.java:185)
    at org.jsecurity.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:186)
    at org.jsecurity.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:276)
    at org.jsecurity.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:141)
    at org.jsecurity.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:171)
    at org.jsecurity.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:312)
    at org.jsecurity.subject.DelegatingSubject.login(DelegatingSubject.java:237)
    at org.jsecurity.web.filter.authc.AuthenticatingFilter.executeLogin(AuthenticatingFilter.java:49)
    at org.sonatype.nexus.security.filter.authc.NexusHttpAuthenticationFilter.onAccessDenied(NexusHttpAuthenticationFilter.java:121)
    at org.jsecurity.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:145)
    at org.jsecurity.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:175)
    at org.jsecurity.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:129)
    at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
    at org.jsecurity.web.servlet.FilterChainWrapper.doFilter(FilterChainWrapper.java:57)
    at org.jsecurity.web.servlet.JSecurityFilter.doFilterInternal(JSecurityFilter.java:382)
    at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
    at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:419)
    at org.apache.coyote.ajp.AjpAprProtocol$AjpConnectionHandler.process(AjpAprProtocol.java:378)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1509)
    at java.lang.Thread.run(Thread.java:619)
Caused by: org.sonatype.jsecurity.realms.tools.NoSuchUserException: User with id='testuser' not found!
    at org.sonatype.jsecurity.realms.tools.DefaultConfigurationManager.readUser(DefaultConfigurationManager.java:410)
    at org.sonatype.jsecurity.realms.tools.ResourceMergingConfigurationManager.readUser(ResourceMergingConfigurationManager.java:278)
    at org.sonatype.jsecurity.realms.XmlAuthenticatingRealm.doGetAuthenticationInfo(XmlAuthenticatingRealm.java:64)
    ... 29 more
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.LdapAuthent~          - Authenticating user 'testuser' through LDAP
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.LdapAuthent~          - LDAP user search filter: (&(objectClass=account)(uid={0}))
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP security principal not set
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP security credentials not set
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP provider url(s): ldap://ldap:389
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP initial context factory: com.sun.jndi.ldap.LdapCtxFactory
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP security protocol: null
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP security authentication: null
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP search scope: subtree
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.LdapAuthent~          - User object found
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.LdapAuthent~          - LDAP authentication principal: uid=testuser, dc=corporation,dc=de
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP provider url(s): ldap://ldap:389
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP initial context factory: com.sun.jndi.ldap.LdapCtxFactory
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP security protocol: null
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - s.d.n.l.NexusLdapCo~          - LDAP security authentication: null
2009-10-23 15:06:37 ERROR [ajp-8009-3     ] - o.j.r.l.AbstractLda~          - LDAP naming error while attempting to authenticate user.
javax.naming.CommunicationException: [LDAP: error code 2 - version not supported]
    at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3089)
    at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2987)
    at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2789)
    at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2703)
    at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293)
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
    at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
    at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
    at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
    at javax.naming.InitialContext.init(InitialContext.java:223)
    at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:134)
    at se.devoteam.nexus.ldap.NexusLdapContextFactory.getLdapContext(NexusLdapContextFactory.java:63)
    at se.devoteam.nexus.ldap.LdapAuthenticatingRealm.queryForAuthenticationInfo(LdapAuthenticatingRealm.java:139)
    at org.jsecurity.realm.ldap.AbstractLdapRealm.doGetAuthenticationInfo(AbstractLdapRealm.java:186)
    at org.jsecurity.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:168)
    at org.sonatype.jsecurity.web.WebPlexusSecurity.getAuthenticationInfo(WebPlexusSecurity.java:185)
    at org.jsecurity.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:186)
    at org.jsecurity.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:276)
    at org.jsecurity.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:141)
    at org.jsecurity.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:171)
    at org.jsecurity.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:312)
    at org.jsecurity.subject.DelegatingSubject.login(DelegatingSubject.java:237)
    at org.jsecurity.web.filter.authc.AuthenticatingFilter.executeLogin(AuthenticatingFilter.java:49)
    at org.sonatype.nexus.security.filter.authc.NexusHttpAuthenticationFilter.onAccessDenied(NexusHttpAuthenticationFilter.java:121)
    at org.jsecurity.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:145)
    at org.jsecurity.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:175)
    at org.jsecurity.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:129)
    at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
    at org.jsecurity.web.servlet.FilterChainWrapper.doFilter(FilterChainWrapper.java:57)
    at org.jsecurity.web.servlet.JSecurityFilter.doFilterInternal(JSecurityFilter.java:382)
    at org.jsecurity.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:180)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
    at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:419)
    at org.apache.coyote.ajp.AjpAprProtocol$AjpConnectionHandler.process(AjpAprProtocol.java:378)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1509)
    at java.lang.Thread.run(Thread.java:619)
2009-10-23 15:06:37 INFO  [ajp-8009-3     ] - o.s.n.s.f.a.NexusSe~          - Unable to authenticate user [testuser] from address/host [172.31.2.155/172.31.2.155]
2009-10-23 15:06:37 DEBUG [ajp-8009-3     ] - o.s.n.e.Authenticat~:default  - Notifying 1 EventListener about event org.sonatype.nexus.auth.NexusAuthenticationEvent fired (org.sonatype.nexus.auth.NexusAuthenticationEvent@d637d)
+1  A: 

Mmmm... I'm not a LDAP expert but, according to the Bug ID: 4908306 LDAP Provider version negotiation fails with OpenLDAP server (LDAP v2):

InitialLdapContext is used for LDAP v3 only. It adds methods to DirContext that make sense only for v3. To use DirContext methods, use InitialDirContext. InitialDirContext will do the appropriate v2/v3 negotiation. The change was made in 1.4.1 to tighten up the implementation to match the spec and also to avoid sending extraneous BINDs for v3.

Actually, my understanding of the comment above and of the InitialLdapContext javadoc is that:

This class is the starting context for performing LDAPv3-style extended operations and controls.

The InitialLdapContext class can't be used for LDAP-v2, it sets explicitly the java.naming.ldap.version environment property to "3" in its sources. For LDAP-v2, you'll have to use InitialDirContext.

If changing the server is not an option, I guess that you'll have to patch http://code.google.com/p/nexus-ldap/

Pascal Thivent
I guess I had almost all the information already at my fingertips, thank you for piecing it together for me.I'll let you now if using the InitialDirContext works.
Patrick Zeising