I have read almost everything about Spring/Security/Ldap and ActiveDirectory on stackoverflow. Even if I found useful tips and hints, I wasn\'t able to solve my problem.
I sort of ran into similar issue and did some research. In our AD with the domain "my.company.com" we seemed to have two sets of users, one set with UPN in the format user1@my.company.com and in other case it is in the form of user2@somethingelse.com.
And when I use org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider and try to authenticate users with user1@my.company.com and user2@somethingelse.com - only one of them works depending on what I pass to the constructor for the domain name.
I am no AD expert, but looking at Microsoft tech net article: https://technet.microsoft.com/en-us/library/cc739093(v=ws.10).aspx it appears like while UPN suffix normally is same as domain name, it is not a must and could be suffixed with something else. Quoting that article
The second part of the UPN, the UPN suffix, identifies the domain in which the user account is located. This UPN suffix can be the DNS domain name, the DNS name of any domain in the forest, or it can be an alternative name created by an administrator and used just for log on purposes. This alternative UPN suffix does not need to be a valid DNS name.
In Active Directory, the default UPN suffix is the DNS name of the domain in which user account created. In most cases, this is the domain name registered as the enterprise domain on the Internet. Using alternative domain names as the UPN suffix can provide additional logon security and simplify the names used to log on to another domain in the forest.
For example, if your organization uses a deep domain tree, organized by department and region, domain names can get quite long. The default user UPN for a user in that domain might be sales.westcoast.microsoft.com. The logon name for a user in that domain would be user@sales.westcoast.microsoft.com. Creating a UPN suffix of "microsoft" would allow that same user to log on using the much simpler logon name of user@microsoft. For more information about user accounts, see User and computer accounts and Object names.
But I think ActiveDirectoryLdapAuthenticationProvider.java seems to be making an assumption that domain name is same as UPN suffix. I made a local fix to ActiveDirectoryLdapAuthenticationProvider.java to not make that assumption:
String createBindPrincipal(String username) {
if (domain == null || username.toLowerCase().endsWith(domain) || username.contains("@")) {
return username;
}
return username + "@" + domain;
}
Now both users with their different UPN suffixes are searchable. If my assumptions are correct, I may open a bug with Spring security.
I was not able to solve this problem using Context.REFERRAL = "follow" in fact the problem lies in the code of method searchForUser() of the class ActiveDirectoryLdapProvider. In this method, the method SpringSecurityLdapTemplate.searchForSingleEntryInternal() is called with the bindPrincipal which is in fact the userPrincipalName composed from the arguments passed to the constructor in the first argument and the username. So, even if you set your search filter to anything else than userPrincipalName, it will be passed a userPrincipalName as argument 0. Hence, the filter with sAMAccountName will not work with a UPN and throw an exception.
Either searchForUser() should be modified or augmented to detect the searchFilter is needing a username and not a UPN, either extra setters are provided to set the arguments using patterns for the searchFilter.
But there is no way to make this class working correctly in such situation without modifying the code. That's what I finally did. I wrote my own class basically a carbon copy of the original ActiveDirectoryLdapAUthenticationProvider with one single and simple modification to searchForUser() passing the username instead of the bindPrincipal to searchForSingleEntryInternal().
It is bit a nonsense you can enter whatever search filter you want but forced to use only a single argument which is actually the userPrincipalName and nothing else.
In Spring Security 4.1.1 / SpringBoot 1.4.0 environment, I do this like that (in Java):
@Configuration
public class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter
{
public void init (AuthenticationManagerBuilder aAuth) throws Exception
{
ActiveDirectoryLdapAuthenticationProvider
myProvider = new ActiveDirectoryLdapAuthenticationProvider (ldapDomain, ldapUrl);
aAuth.authenticationProvider (myProvider);
aAuth.eraseCredentials (false);
}
}
I don't run into any problem and the user can logon using the sAMAccountName
.