问题
I have to configure Spring security to authenticate user through LDAP. This is the subtree where manager user is:
ldaps://vldp.floal:636/CN=Administration,CN=fdam,DC=fg,DC=local
and this is where users are:
ldaps://vldp.floal:636/CN=ProxyUsers,CN=fdam,DC=fg,DC=local
So I use this setting:
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
auth.ldapAuthentication()
.contextSource()
.url("ldaps://vldp.floal:636/DC=fg,DC=local")
.managerDn("CN=A0XXX32,CN=Administration,CN=fdam,DC=fg,DC=local")
.managerPassword(password)
.and()
.userSearchBase("CN=ProxyUsers,CN=fdam")
.userSearchFilter("(CN={0})")
.ldapAuthoritiesPopulator(myAuthPopulator);
}
The problem is exception thrown when I try to make login through user, i receive this error:
2016-03-25 14:43:14 [http-nio-8086-exec-6] ERROR o.s.s.w.a.UsernamePasswordAuthenticationFilter - An internal error occurred while trying to authenticate the user.
org.springframework.security.authentication.InternalAuthenticationServiceException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031522C9, problem 2001 (NO_OBJECT), data 0, best match of:
'CN=fdam,DC=fg,DC=local'
]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031522C9, problem 2001 (NO_OBJECT), data 0, best match of:
'CN=fdam,DC=fg,DC=local'
]; remaining name 'cn=F67XXX7A,cn=ProxyUsers,cn=fdam'
at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:207) ~[spring-security-ldap-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:82) ~[spring-security-ldap-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167) ~[spring-security-core-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192) ~[spring-security-core-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:93) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217) ~[spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) [spring-security-web-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) [spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.26]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.26]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) [catalina.jar:8.0.26]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [catalina.jar:8.0.26]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [catalina.jar:8.0.26]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [catalina.jar:8.0.26]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [catalina.jar:8.0.26]
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) [catalina.jar:8.0.26]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [catalina.jar:8.0.26]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518) [catalina.jar:8.0.26]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091) [tomcat-coyote.jar:8.0.26]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673) [tomcat-coyote.jar:8.0.26]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1526) [tomcat-coyote.jar:8.0.26]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1482) [tomcat-coyote.jar:8.0.26]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.0.26]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]
Caused by: org.springframework.ldap.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031522C9, problem 2001 (NO_OBJECT), data 0, best match of:
'CN=fdam,DC=fg,DC=local'
]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031522C9, problem 2001 (NO_OBJECT), data 0, best match of:
'CN=fdam,DC=fg,DC=local'
]; remaining name 'cn=F67XXX7A,cn=ProxyUsers,cn=fdam'
at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:183) ~[spring-ldap-core-2.0.2.RELEASE.jar:2.0.2.RELEASE]
at org.springframework.security.ldap.authentication.BindAuthenticator.bindWithDn(BindAuthenticator.java:148) ~[spring-security-ldap-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.ldap.authentication.BindAuthenticator.authenticate(BindAuthenticator.java:95) ~[spring-security-ldap-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:189) ~[spring-security-ldap-4.0.2.RELEASE.jar:4.0.2.RELEASE]
... 41 common frames omitted
Caused by: javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031522C9, problem 2001 (NO_OBJECT), data 0, best match of:
'CN=fdam,DC=fg,DC=local'
]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3160) ~[na:1.8.0_60]
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3081) ~[na:1.8.0_60]
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2888) ~[na:1.8.0_60]
at com.sun.jndi.ldap.LdapCtx.c_getAttributes(LdapCtx.java:1329) ~[na:1.8.0_60]
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_getAttributes(ComponentDirContext.java:235) ~[na:1.8.0_60]
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.getAttributes(PartialCompositeDirContext.java:141) ~[na:1.8.0_60]
at javax.naming.directory.InitialDirContext.getAttributes(InitialDirContext.java:152) ~[na:1.8.0_60]
at org.springframework.security.ldap.authentication.BindAuthenticator.bindWithDn(BindAuthenticator.java:124) ~[spring-security-ldap-4.0.2.RELEASE.jar:4.0.2.RELEASE]
... 43 common frames omitted
There is a problem with spring parameters because if I use java code to authenticate users it works. I can't figure out where is the problem, can you help me?
I went in debug and this is the output before the error:
2016-03-30 11:35:22 [http-nio-8086-exec-6] DEBUG o.s.security.web.FilterChainProxy - /login at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-03-30 11:35:22 [http-nio-8086-exec-6] DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request : '/login'; against '/login'
2016-03-30 11:35:22 [http-nio-8086-exec-6] DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Request is to process authentication
2016-03-30 11:35:22 [http-nio-8086-exec-6] DEBUG o.s.s.authentication.ProviderManager - Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider
2016-03-30 11:35:22 [http-nio-8086-exec-6] DEBUG o.s.s.l.a.LdapAuthenticationProvider - Processing authentication request for user: F67XXX7A
2016-03-30 11:35:22 [http-nio-8086-exec-6] DEBUG o.s.s.l.s.FilterBasedLdapUserSearch - Searching for user 'F67XXX7A', with user search [ searchFilter: '(CN={0})', searchBase: 'CN=fdam', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ]
2016-03-30 11:35:23 [http-nio-8086-exec-6] DEBUG o.s.l.c.s.AbstractContextSource - Got Ldap context on server 'ldaps://vldp.floal:636/dc=fg,dc=local'
2016-03-30 11:35:23 [http-nio-8086-exec-6] DEBUG o.s.s.l.SpringSecurityLdapTemplate - Searching for entry under DN 'dc=fg,dc=local', base = 'cn=fdam', filter = '(CN={0})'
2016-03-30 11:35:23 [http-nio-8086-exec-6] DEBUG o.s.s.l.SpringSecurityLdapTemplate - Found DN: CN=F67XX7A,CN=ProxyUsers,CN=fdam
2016-03-30 11:35:23 [http-nio-8086-exec-6] DEBUG o.s.s.l.a.BindAuthenticator - Attempting to bind as cn=F67XX7A,cn=ProxyUsers,cn=fdam,dc=fg,dc=local
2016-03-30 11:35:23 [http-nio-8086-exec-6] DEBUG o.s.s.l.DefaultSpringSecurityContextSource - Removing pooling flag for user cn=F67XX7A,cn=ProxyUsers,cn=fdam,dc=fg,dc=local
2016-03-30 11:35:23 [http-nio-8086-exec-6] DEBUG o.s.l.c.s.AbstractContextSource - Got Ldap context on server 'ldaps://vldp.floal:636/dc=fg,dc=local'
2016-03-30 11:35:23 [http-nio-8086-exec-6] DEBUG o.s.s.l.a.BindAuthenticator - Retrieving attributes...
2016-03-30 11:35:23 [http-nio-8086-exec-6] ERROR o.s.s.w.a.UsernamePasswordAuthenticationFilter - An internal error occurred while trying to authenticate the user.
PS: If with a ldap browser use CN=F67XXX7A,CN=ProxyUsers,CN=fdam,DC=fg,DC=local
it binds.
UPDATE: if I use java without Spring login works, I need to use Spring and figure out how to configure it:
@Override
public void isAuthenticated(String username, String password) throws LdapException{
if (databaseMatlabClientServices.getByUsersEnabled(username)== null)
throw new LdapException("User doesn't exist into DART database. Please contact the administrator!");
String dn="";;
//First query to retriev DN
Hashtable<String, Object> ldapEnv = new Hashtable<String, Object>();
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapEnv.put(Context.PROVIDER_URL, env.getRequiredProperty(PROPERTY_NAME_LDAP_URL));
//Without authentication ldapEnv.put(Context.SECURITY_AUTHENTICATION, "none");
//With authentication to access to LDAP server
ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapEnv.put(Context.SECURITY_PRINCIPAL, env.getRequiredProperty(PROPERTY_NAME_LDAP_NAME));
ldapEnv.put(Context.SECURITY_CREDENTIALS, env.getRequiredProperty(PROPERTY_NAME_LDAP_PASSWORD));
String[] returnAttribute = {"dn"};
DirContext ctx = null;
NamingEnumeration<SearchResult> results = null;
try {
ctx = new InitialDirContext(ldapEnv);
SearchControls controls = new SearchControls();
controls.setReturningAttributes(returnAttribute);
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// without authentication on local server String filter = "uid=" + username ;
String filter = "CN=" + username ;
results = ctx.search(env.getRequiredProperty(PROPERTY_NAME_LDAP_USERSEARCHBASE), filter, controls);
if (results.hasMore())
dn = results.nextElement().getNameInNamespace();
else
throw new LdapException("Wrong username. Please retry!");
} catch (NamingException e) {
throw new LdapException(e);
} finally {
try{
if (results != null)
results.close();
if (ctx != null)
ctx.close();
}catch(Exception e){
throw new LdapException(e);
}
}
//Second query to try to access with obtained Dn and given password
Hashtable<String, Object> authEnv = new Hashtable<String, Object>();
authEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
authEnv.put(Context.PROVIDER_URL, env.getRequiredProperty(PROPERTY_NAME_LDAP_URL));
authEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
authEnv.put(Context.SECURITY_PRINCIPAL, dn);
authEnv.put(Context.SECURITY_CREDENTIALS, password);
DirContext ctx2 = null;
try {
ctx2 = new InitialDirContext(authEnv);
} catch (AuthenticationException authEx) {
throw new LdapException("Authentication error. Password was wrong");
} catch(Exception e){
throw new LdapException(e);
}finally {
try{
if (ctx2 != null)
ctx2.close();
}catch(Exception e){
throw new LdapException(e);
}
}
}
UPDATE @pczeus code: To set referral=follow I have used this code:
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldaps://vldp.floal:636/");
contextSource.setUserDn("CN=A0XXX32,CN=Administration,CN=fdam,DC=fg,DC=local");
contextSource.setPassword(password);
contextSource.setReferral("follow");
contextSource.afterPropertiesSet();
LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth.ldapAuthentication();
ldapAuthenticationProviderConfigurer
.ldapAuthoritiesPopulator(myAuthPopulator)
.userSearchFilter("(CN={0},CN=ProxyUsers,CN=fdam,DC=fg,DC=local)")
.userSearchBase("")
.contextSource(contextSource);
and I receive the classic exception:
2016-04-07 09:34:41 [http-nio-8086-exec-4] ERROR o.s.s.w.a.UsernamePasswordAuthenticationFilter - An internal error occurred while trying to authenticate the user.
org.springframework.security.authentication.InternalAuthenticationServiceException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031001E5, problem 2001 (NO_OBJECT), data 0, best match of:
''
]; nested exception is javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031001E5, problem 2001 (NO_OBJECT), data 0, best match of:
''
]; remaining name '/'
if I add .userSearchBase("CN=ProxyUsers,CN=fgadam,DC=fg,DC=local")
I receive
2016-04-07 10:32:56 [http-nio-8086-exec-4] DEBUG o.s.s.l.s.FilterBasedLdapUserSearch - Searching for user 'F6XXX7A', with user search [ searchFilter: '(CN={0},CN=ProxyUsers,CN=fdam,DC=fg,DC=local)', searchBase: 'CN=ProxyUsers,CN=fdam,DC=fg,DC=local', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ]
2016-04-07 10:32:57 [http-nio-8086-exec-4] DEBUG o.s.l.c.s.AbstractContextSource - Got Ldap context on server 'ldaps://vldp.floal:636/'
2016-04-07 10:32:57 [http-nio-8086-exec-4] DEBUG o.s.s.l.SpringSecurityLdapTemplate - Searching for entry under DN '', base = 'cn=ProxyUsers,cn=fdam,dc=fg,dc=local', filter = '(CN={0},CN=ProxyUsers,CN=fdam,DC=fg,DC=local)'
2016-04-07 10:32:57 [http-nio-8086-exec-4] DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
where DN is '', why?
回答1:
In AbstractContextSource (parent of LdapContextSource), the Javadoc for the setBase() method says the following: "Set the base suffix from which all operations should origin. If a base suffix is set, you will not have to (and, indeed, must not) specify the full distinguished names in any operations performed.". Since you specify the full DN for the userDN/filter, hence you must not specify the base.
Try setting the userSearchBase
either to an empty String (""), or remove the call all togehter.
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
auth.ldapAuthentication()
.contextSource()
.url("ldaps://vldp.floal:636/DC=fg,DC=local")
.managerDn("CN=A0XXX32,CN=Administration,CN=fdam,DC=fg,DC=local")
.managerPassword(password)
.and()
.userSearchBase("")
.userSearchFilter("CN={0},CN=ProxyUsers,CN=fdam,DC=fg,DC=local")
.ldapAuthoritiesPopulator(myAuthPopulator);
}
回答2:
We have a legacy app that uses Spring Security 3.2.5. We still use XML to config it. Maybe my config could help you to identify whats going on with yours.
What I noticed is that your userSearchBase
does not use the complete "FQDN". Try using userSearchBase("CN=ProxyUsers,CN=fdam,DC=fg,DC=local")
(despite the log msg "Attempting to bind as cn=F67XX7A,cn=ProxyUsers,cn=fdam,dc=fg,dc=local").
Another hint is to use a LDAP browser tool in order navigate into the ldap server and check to see if the CN, DN and OU are ok.
<ldap-server
url="ldap://SERVERNAME.XPTO.BLAH:389"
manager-dn="usrLogin"
manager-password="usrPwd" />
<authentication-manager>
<ldap-authentication-provider
role-prefix=""
user-search base="OU=BR,OU=MYCOMP,DC=XPTO,DC=BLAH"
user-search-filter="sAMAccountName={0}"
group-search-base="OU=Groups,OU=BR,OU=MYCOMP,DC=XPTO,DC=BLAH"
group-search-filter="member={0}" />
</authentication-manager>
<beans:bean id="ldapEnv" class="java.util.Hashtable" scope="prototype">
<beans:constructor-arg>
<beans:map key-type="java.lang.String" value-type="java.lang.String">
<beans:entry key="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory" />
<beans:entry key="java.naming.provider.url" value="ldap://SERVERNAME.XPTO.BLAH:389" />
<beans:entry key="java.naming.security.authentication" value="simple" />
<beans:entry key="java.naming.security.principal" value="usrLogin" />
<beans:entry key="java.naming.security.credentials" value="usrPwd" />
</beans:map>
</beans:constructor-arg>
</beans:bean>
来源:https://stackoverflow.com/questions/36305360/configure-spring-security-for-ldap-connection