I'm writing a Spring web application that requires users to login. My company has an Active Directory server that I'd like to make use of for this purpose. However, I'm having trouble using Spring Security to connect to the server.
I'm using Spring 2.5.5 and Spring Security 2.0.3, along with Java 1.6.
If I change the LDAP URL to the wrong IP address, it doesn't throw an exception or anything, so I'm wondering if it's even trying to connect to the server to begin with.
Although the web application starts up just fine, any information I enter into the login page is rejected. I had previously used an InMemoryDaoImpl, which worked fine, so the rest of my application seems to be configured correctly.
Here are my security-related beans:
<beans:bean id="ldapAuthProvider" class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
<beans:constructor-arg>
<beans:bean class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
<beans:constructor-arg ref="initialDirContextFactory" />
<beans:property name="userDnPatterns">
<beans:list>
<beans:value>CN={0},OU=SBSUsers,OU=Users,OU=MyBusiness,DC=Acme,DC=com</beans:value>
</beans:list>
</beans:property>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="userDetailsService" class="org.springframework.security.userdetails.ldap.LdapUserDetailsManager">
<beans:constructor-arg ref="initialDirContextFactory" />
</beans:bean>
<beans:bean id="initialDirContextFactory" class="org.springframework.security.ldap.DefaultInitialDirContextFactory">
<beans:constructor-arg value="ldap://192.168.123.456:389/DC=Acme,DC=com" />
</beans:bean>
I was able to authenticate against active directory using spring security 2.0.4.
I documented the settings
http://maniezhilan.blogspot.com/2008/10/spring-security-204-with-active.html
I had the same banging-my-head-against-the-wall experience you did, and ended up writing a custom authentication provider that does an LDAP query against the Active Directory server.
So my security-related beans are:
Then the LdapAuthenticationProvider class:
Then the LdapAuthenticatorImpl class:
And finally, the LdapAuthenticationToken class:
You'll notice that there are a few bits in there that you might not need.
For example, my app needed to retain the successfully-logged-in LDAP context for further use by the user once logged in -- the app's purpose is to let users log in via their AD credentials and then perform further AD-related functions. So because of that, I have a custom authentication token, LdapAuthenticationToken, that I pass around (rather than Spring's default Authentication token) which allows me to attach the LDAP context. In LdapAuthenticationProvider.authenticate(), I create that token and pass it back out; in LdapAuthenticatorImpl.authenticate(), I attach the logged-in context to the return object so that it can be added to the user's Spring authentication object.
Also, in LdapAuthenticationProvider.authenticate(), I assign all logged-in users the ROLE_USER role -- that's what lets me then test for that role in my intercept-url elements. You'll want to make this match whatever role you want to test for, or even assign roles based on Active Directory groups or whatever.
Finally, and a corollary to that, the way I implemented LdapAuthenticationProvider.authenticate() gives all users with valid AD accounts the same ROLE_USER role. Obviously, in that method, you can perform further tests on the user (i.e., is the user in a specific AD group?) and assign roles that way, or even test for some condition before even granting the user access at all.
Just to bring this to an up-to-date status. Spring Security 3.0 has a complete package with default implementations devoted to ldap-bind as well as query and compare authentication.
From Luke's answer above:
I tried the above with Spring Security 3.1.1: there are some slight changes from ldap - the active directory groups the user is a member of come through as original case.
Previously under ldap the groups were capitalized and prefixed with "ROLE_", which made them easy to find with a text search in a project but obviously might case problems in a unix group if for some strange reason had 2 separate groups only differentiated by case(ie accounts and Accounts).
Also the syntax requires manual specification of the domain controller name and port, which makes it a bit scary for redundancy. Surely there is a way of looking up the SRV DNS record for the domain in java, ie equivalent of(from Samba 4 howto):
followed by regular A lookup:
(Actually might need to lookup _kerberos SRV record too...)
The above was with Samba4.0rc1, we are progressively upgrading from Samba 3.x LDAP environment to Samba AD one.
For reference, Spring Security 3.1 has an authentication provider specifically for Active Directory.