2
votes

I have a working setup for SpringFramework Security 4.0.0 with my AD server. This was working fine with the default search filter until I discovered that the users in the AD database are much more twisted than expected originally.

My setup was as follow for the ActiveDirectoryLdapAuthenticationProvider bean in the namespace:

<b:bean id="monFournisseurAD" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <b:constructor-arg value="subdom1.dom1.com" />
    <b:constructor-arg value="ldap://fsapps.company.uni:389/" />
    <b:constructor-arg value="dc=fsapps,dc=company,dc=uni" />
    <b:property name="searchFilter" value="(&amp;(userPrincipalName={0})(objectClass=user))" />
    <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>

I then moved to the following setup instead to remove the dependency on the domain:

<b:bean id="monFournisseurAD" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <b:constructor-arg value="" />
    <b:constructor-arg value="ldap://fsapps.company.uni:389/" />
    <b:constructor-arg value="dc=fsapps,dc=company,dc=uni" />
    <b:property name="searchFilter" value="(&amp;(sAMAccountName={0})(objectClass=user))" />
    <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>

The problem now is the {0} substitution in the searchFilter accordingly to the SpringFramework Security 4.0.0 documentation is substituting username@domain where domain seems to be the default domain of the AD server itself, which in this case is fsapps.company.uni since my first constructor argument is empty. SpringFramework Security 4.0.0 Class ActiveDirectoryLdapAuthenticationProvider's documentation

Question: Is there a way to substitute only username rather than username@domain? Any other suggestions how I can circumvent this problem?

NOTE: After looking at the source code. It seems the expected behavior should be as follow: if the domain argument for the constructor of the class ActiveDirectoryLdapAuthenticationProvider is an empty string or an all white spaces string, it is set to null. When the domain is set to null, the substitution of the {0} pattern should be the username only without the domain appended to it and this should do exactly what I want it to do: search for the sAMAccountName attribute equals to the username alone and a record of objectClass user. So, why does it fail to find users which are not in the rootDN as a domain (third constructor's argument fsapps.company.com in my example)? I have no problem to match users which would have a userPrincipalName of the form: [email protected] while I cannot match users with a userPrincipalName of the form: [email protected] ?

NOTE 2: I found the problem, not yet the solution. Actually, my search filter is perfectly fine and Spring Security is using it correctly. The problem is the authentication is performed by a bind to the AD server and to bind to the server I must use [email protected] (if authorized) or either [email protected]. The sAMAccountName attribute is checked against a username with a domain rather than a username without a domain. If the domain is added, there is no sAMAccountName matching the value passed as an argument.

2

2 Answers

0
votes

A working solution is to rely on the first shown configuration using the userPrincipalName and emptying the first constructor's argument to pass an empty string to the constructor. This way, nothing will be appended to the username and instead of typing a simple username, the users have to type their complete usernames with the domain specified. So, instead of logging in with username, the use username@domain.

Another solution would be to investigate if it is possible to bind to the AD database with a generic and authorized user to perform all the queries on its behalf. I haven't investigate if it is feasible (it is done with plain LDAP) and how much effort it requires. If anyone experiment this solution, it would be nice to post the results here to share this solution.

0
votes

An alternative is using (sAMAccountName={1}) based on this fix.