Spring LDAP Context.REFERRAL to follow
How to configure LDAP Context.REFERRAL in Spring Security Configuration? This is due to an issue I already reported and for which I found an unsatisfactory solution before discovering a real solution that I am aiming to enable setting this environment attribute in an LDAP context to follow the referral for ActiveDirectoryLdapAuthenticationProvider.
Here is a link to my original question: Spring Security 4.0.0 + ActiveDirectoryLdapAuthenticationProvider + BadCredentialsException PartialResultException
Addendum: There seems to be no such environment here. Despite the silence on this issue, I am posting my config here hoping someone can help me. I just don't know what I should do to fix this problem.
Here are the error messages in my log:
2015-06-15 10:32:19,810 DEBUG (o.s.s.w.FilterChainProxy$VirtualFilterChain.doFilter) [http-8443-1] /identite.proc at position 7 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2015-06-15 10:32:19,810 DEBUG (o.s.s.w.u.m.AntPathRequestMatcher.matches) [http-8443-1] Checking match of request : '/identite.proc'; against '/identite.proc'
2015-06-15 10:32:19,810 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.doFilter) [http-8443-1] Request is to process authentication
2015-06-15 10:32:19,811 DEBUG (o.s.s.a.ProviderManager.authenticate) [http-8443-1] Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider
2015-06-15 10:32:19,811 DEBUG (o.s.s.l.a.AbstractLdapAuthenticationProvider.authenticate) [http-8443-1] Processing authentication request for user: myusername
2015-06-15 10:32:19,841 DEBUG (o.s.s.l.SpringSecurityLdapTemplate.searchForSingleEntryInternal) [http-8443-1] Searching for entry under DN '', base = 'dc=dept,dc=company,dc=com', filter = '(&(userPrincipalName={0})(objectClass=user)(objectCategory=inetOrgPerson))'
2015-06-15 10:32:19,842 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-1] Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2015-06-15 10:32:19,842 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-1] Updated SecurityContextHolder to contain null Authentication
2015-06-15 10:32:19,842 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-1] Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@a5d7f2
And here is the configuration:
<b:bean id="monFournisseurAD" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<b:constructor-arg value="dept.company.com" />
<b:constructor-arg value="ldap://dept.company.com:3268/" />
<b:constructor-arg value="dc=dept,dc=company,dc=com" />
<b:property name="searchFilter" value="(&(userPrincipalName={0})(objectClass=user)(objectCategory=inetOrgPerson))" />
<b:property name="userDetailsContextMapper">
<b:bean class="org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper" />
</b:property>
<b:property name="authoritiesMapper" ref="grantedAuthoritiesMapper" />
<b:property name="convertSubErrorCodesToExceptions" value="true" />
</b:bean>
<b:bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<b:constructor-arg value="ldap://dept.company.com:3268/dc=dept,dc=company,dc=com" />
<b:property name="baseEnvironmentProperties">
<b:map>
<b:entry key="java.naming.referral" value="follow" />
</b:map>
</b:property>
</b:bean>
<b:bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
<b:constructor-arg ref="contextSource" />
</b:bean>
<b:bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />
<b:bean id="myDeconnexionHandler" class="com.company.dept.web.my.DeconnexionHandler" />
The two beans with ids contextSource and ldapTemplate don't seem to change anything. I've tried to achieve the behavior that referrals follow. This doesn't seem to be the correct way to set it up. Also, here the port in the ldap url is set to 3268 because it's a shared directory and someone else in the description elsewhere suggested using it. But, the results are exactly the same with port 389.
If I change the first constructor argument in the monFournisseurAD bean to set it to the same userPrincipalName domain, it works for all users in that domain. Though I can actually authenticate someone from the command line using the ldapsearch command using dept.company.com instead of the userPrincipalName domain associated directly with the user. In fact, if I enter a wrong password, I get a specific wrong password message. This seems to prove that the user is actually AD / LDAP authenticated, however Spring will not be able to retrieve the attributes for that user.
How can I solve this problem?
source to share
Finally, the only way to solve this problem is to change the code with the org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.searchForUser () method hooked up to pass the bindPrincipal to SpringSecurityLdapTemplate.searchForSingleEntryInternal () which is actually used to restore the record filter for the user using search defined in XML, or set using setSearchFilter (). Since bindPrincipal is actually the domain of username @, this value is not suitable for using sAMAccountName in a search filter, it will always fail. Since binding to the Active Directory server is done using userPrincipalName and then bindPrincipal, you have no way to specify searchForUser (), it should only use the username in the search and not in the bindPrincipal (UPN).I fixed my problem by copying the entire org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider class into my package and changing the searchForUser () method to pass the username instead of the bindPrincipal to the searchForSingleEntryInternal () method. This works, but it is still a wired / hardcoded solution. A more elegant solution would be to introduce a list of templates and a method for constructing values to call searchForSingleEntryInternal (), or a method that will determine the types of arguments required from the searchFilter () string.to pass the username instead of bindPrincipal to the searchForSingleEntryInternal () method. This works, but it is still a wired / hardcoded solution. A more elegant solution would be to introduce a list of templates and a method for constructing values to call searchForSingleEntryInternal (), or a method that will determine the types of arguments required from the searchFilter () string.to pass the username instead of bindPrincipal to the searchForSingleEntryInternal () method. This works, but it is still a wired / hardcoded solution. A more elegant solution would be to introduce a list of templates and a method for constructing values to call searchForSingleEntryInternal (), or a method that will determine the types of arguments required from the searchFilter () string.
source to share