Open deanabadie opened 5 years ago
Can you put together a minimal sample so I can take a look? I'd also check your environment. It sounds like for some reason OpenJDK is not using org.springframework.ldap.core.support.DefaultDirObjectFactory
(which is set in the environment Map within Spring LDAP).
Hi Rob,
Thanks for your response and for checking this out. I have attached a zip file with a sample: ldap-demo.zip
In order to configure the LDAP connection you need to fill in the following properties in the application.yml file:
ldap.url: ldap://{ip}:{port} ldap.userDn: (e.g. domain\admin) ldap.password: (e.g. Pa$$w0rd) ldap.treeRoot: (e.g. dc=my,dc=ad,dc=tree,dc=root)
By the way I went ahead and checked this on Java 9.0.4
as well and got the same error, so this may not be only an OpenJDK issue.
@deanabadie Can you please update the sample to be self contained by pointing to an in memory LDAP instance. See https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-ldap-embedded
@rwinch Please see the updated attached sample: ldap-demo.zip
Thanks.
@rwinch FYI I tried running the demo with the embedded LDAP server and I can't reproduce the error (To be honest I am getting an empty tree, it looks like I am unable to get any data from the ldif file). However, when connecting to an actual LDAP server this error does occur. I have tried connecting to multiple LDAP servers and I was able to reproduce this problem on all attempts.
@rwinch I was able to reproduce the error with the embedded LDAP server, please see updated zip file: ldap-demo.zip
Also not working with OpenJDK10 and OpenJDK11, the code is working while running it from the IDE "gradlew bootRun" but failed when compiling and running the jar itself. using "gradlew build" and then run with "Java -jar"
Is there any update on this issue or has anyone found an acceptable workaround?
I haven't sorted it out, but it is likely due to the DefaultDirObjectFactory not being used. I'd try and see if there were changes in JDK 9 on what factory is used.
Actually that happened to us with OpenJdk we just switched to other distribution (amazon corretto 8 and it worked). Didn't invest much time in identifying the root cause.
Seeing the same - but I think it might be connected with fat-jar packaging: https://github.com/spring-projects/spring-boot/issues/20666 - it runs fine in IntellJ on same jdk (but different OS)
in my case the problem was threading: https://stackoverflow.com/questions/45742638/classcastexception-while-searching-for-ldap-user - so I guess it's really a classloader related bug in spring-ldap.
@davidkarlsen In the stacktrace you mentioned it says:
java.lang.ClassCastException: com.sun.jndi.ldap.LdapCtx cannot be cast to org.springframework.ldap.core.DirContextAdapter
This is true. com.sun.jndi.ldap.LdapCtx
is not an instance of org.springframework.ldap.core.DirContextAdapter
.
Spring LDAP expects to work with DirContextAdapter
which should be created with DefaultDirObjectFactory
, but it appears that for whatever reason certain JDKs are not finding using DefaultDirObjectFactory
. I'd look and see what if anything changed on how that is configured.
It's due to the threadclassloader, see the SO thread I linked to. I ran it from a parallel stream and it failed with the classcast - making it a normal serial stream and it works.
IDK - the sample wasn't mine - but I can tell that it works as long as I run things serially.
using parallel streams gives this error. Any reason why this would be the case? Can parallel stream support be added? Thanks.
Are there any updates on this?
Just catching up on this issue. I notice that the sample does not come with any build configuration, app configuration, or tests. It will help me go faster if the sample includes these. For example, it would be nice if there were a test (or repro steps) that demonstrate the behavior. Can someone either update the earlier sample with these or provide a new one?
I (finally) updated my spring-security dependencies, and LDAP Logins stopped working. My test is working fine, but when running under the application server (tomcat), the different classloader makes it so that the ClassCastException is hurting me.
the error trace starts with:
java.lang.ClassCastException: class com.sun.jndi.ldap.LdapCtx cannot be cast to class org.springframework.ldap.core.DirContextAdapter (com.sun.jndi.ldap.LdapCtx is in module java.naming of loader 'bootstrap'; org.springframework.ldap.core.DirContextAdapter is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @43b3dac7)
at org.springframework.security.ldap.SpringSecurityLdapTemplate.searchForSingleEntryInternal(SpringSecurityLdapTemplate.java:279) ~[spring-security-ldap-5.8.9.jar:5.8.9]
at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.searchForUser(ActiveDirectoryLdapAuthenticationProvider.java:324) ~[spring-security-ldap-5.8.9.jar:5.8.9]
at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.doAuthentication(ActiveDirectoryLdapAuthenticationProvider.java:168) ~[spring-security-ldap-5.8.9.jar:5.8.9]
at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:79) ~[spring-security-ldap-5.8.9.jar:5.8.9]
My usage is pretty standard (or so i thought): I'm creating am ActiveDirectoryLdapAuthenticationProvider
, and calling the authenticate
method with a manually created UsernamePasswordAuthenticationToken. I don't really know what could I do wrong there.
The following AuthenticationProvider wrapper solved the issue for me:
public class ClassLoaderAuthenticationProviderWrapper implements AuthenticationProvider {
private final AuthenticationProvider itsAuthenticationProvider;
public ClassLoaderAuthenticationProviderWrapper(AuthenticationProvider aAuthenticationProvider) {
itsAuthenticationProvider = aAuthenticationProvider;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(itsAuthenticationProvider.getClass().getClassLoader());
return itsAuthenticationProvider.authenticate(authentication);
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoader);
}
}
@Override
public boolean supports(Class<?> authentication) {
return itsAuthenticationProvider.supports(authentication);
}
}
I have a Spring Boot 2.0.6 application with spring-data-ldap 2.0.9.RELEASE, and I always get an
java.lang.ClassCastException: java.naming/com.sun.jndi.ldap.LdapCtx cannot be cast to org.springframework.ldap.core.DirContextOperations
exception when trying to retrieve all the distinguishedNames from an Active Directory tree. This problem occurs only while using openjdk (I tried usingopenjdk-9.0.4
andopenjdk-10.0.2
).I get the following stack trace:
I went over the official Spring Boot 2.0.6 documentation and in the System Requirements section it states:
In addition the official Spring Data LDAP official documentation states:
However this error doesn't occur if I use
Java 1.8.0_181
. Is there some compatibility issue with open-jdk that I am not aware of?