First of all I want to say I don't understand LDAP fully, so if I need to provide more information about the LDAP, please say so.
I have a spring boot application (Java 17, spring boot 3.2.0) which has LDAP authentication configured:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserSearchFilter("(userPrincipalName={0})");
factory.setUserDnPatterns("userPrincipalName={0}");
return factory.createAuthenticationManager();
}
So far so good. Authentication is working and is very quick.
But now I want to retrieve what groups/authorities the user is member of.
If viewing the LDAP from an LDAP-client (the one I am using is called LDAP Admin and I am using the same user to authenticate there as I am in the spring boot app) I can see the following:

And if I run the the query (member=cn=Eriksson, Viktor - e-bolvier,ou=External Users,ou=....,dc=internal) I get this:

So I add these lines:
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource, LdapAuthoritiesPopulator authorities) {
.....
factory.setLdapAuthoritiesPopulator(authorities);
.....
}
@Bean
LdapAuthoritiesPopulator authorities(BaseLdapPathContextSource contextSource) {
String groupSearchBase = "";
DefaultLdapAuthoritiesPopulator authorities =
new DefaultLdapAuthoritiesPopulator(contextSource, groupSearchBase);
authorities.setGroupSearchFilter("(member=cn=Eriksson\\, Viktor - e-bolvier,ou=External Users,ou=.....)");
return authorities;
}
I know that the filter should be like this (member={0}) but for some reason it encodes my distinguishedName to this: member=cn=Eriksson\5c, Viktor..., so just to be sure it uses the correct value I typed it manually, I dont know how to skip the encoding.
After adding those lines it starts crashing and saying:
org.springframework.ldap.PartialResultException: Unprocessed Continuation Reference(s)
at
org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:218) ~[spring-ldap-core-3.2.0.jar:3.2.0]
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:375) ~[spring-ldap-core-3.2.0.jar:3.2.0]
....
After some googling I found a couple of answers that suggested to set referral to 'follow'. So I added these lines to the Application-class:
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
private void setReferralForContext() {
LdapTemplate ldapTemplate = applicationContext.getBean(LdapTemplate.class);// necessary for LdapContextSource to be created
LdapContextSource ldapContextSource = applicationContext.getBean(LdapContextSource.class);
ldapContextSource.setReferral("follow");
ldapContextSource.afterPropertiesSet();
}
Now the authentication takes a looooong time, at least 60 seconds. The log is saying something like this:
2023-11-25T23:10:11.600+01:00 DEBUG 27484 : Failed to bind with any user DNs [[email protected]]
2023-11-25T23:10:11.600+01:00 TRACE 27484 : Searching for user using FilterBasedLdapUserSearch [searchFilter=(userPrincipalName={0}); searchBase=; scope=subtree; searchTimeLimit=0; derefLinkFlag=false ]
2023-11-25T23:10:11.600+01:00 TRACE 27484 : Searching for user '[email protected]', with FilterBasedLdapUserSearch [searchFilter=(userPrincipalName={0}); searchBase=; scope=subtree; searchTimeLimit=0; derefLinkFlag=false ]
2023-11-25T23:10:11.640+01:00 TRACE 27484 : Searching for entry under DN 'dc=xxx,dc=internal', base = '', filter = '(userPrincipalName={0})'
2023-11-25T23:10:11.647+01:00 DEBUG 27484 : Found DN: CN=Eriksson\, Viktor - e-bolvier,OU=External Users,OU=xxx,OU=Sweden,OU=Newxxx
2023-11-25T23:10:33.146+01:00 DEBUG 27484 : Found user '[email protected]', with FilterBasedLdapUserSearch [searchFilter=(userPrincipalName={0}); searchBase=; scope=subtree; searchTimeLimit=0; derefLinkFlag=false ]
2023-11-25T23:10:33.146+01:00 TRACE 27484 : Attempting to bind as cn=Eriksson\, Viktor - e-bolvier,ou=External Users,ou=xxx,ou=Sweden,ou=Newxxx,dc=xxx,dc=internal
2023-11-25T23:10:33.183+01:00 DEBUG 27484 : Bound cn=Eriksson\, Viktor - e-bolvier,ou=External Users,ou=xxx,ou=Sweden,ou=Newxxx,dc=xxx,dc=internal
2023-11-25T23:10:33.184+01:00 TRACE 27484 : Searching for roles for user [email protected] with DN cn=Eriksson\, Viktor - e-bolvier,ou=External Users,ou=xxx,ou=Sweden,ou=Newxxx,dc=xxx,dc=internal and filter (member=cn=Eriksson\, Viktor - e-bolvier,ou=External Users,ou=xxx,ou=Sweden,ou=Newxxx,dc=xxx,dc=internal) in search base
2023-11-25T23:10:33.185+01:00 TRACE 27484 : Using filter: (member=cn=Eriksson\, Viktor - e-bolvier,ou=External Users,ou=xxx,ou=Sweden,ou=Newxxx,dc=xxx,dc=internal)
2023-11-25T23:10:54.453+01:00 DEBUG 27484 : Found roles from search []
2023-11-25T23:10:54.454+01:00 DEBUG 27484 : Retrieved authorities for user cn=Eriksson\, Viktor - e-bolvier,ou=External Users,ou=xxx,ou=Sweden,ou=Newxxx,dc=xxx,dc=internal
2023-11-25T23:10:54.454+01:00 DEBUG 27484 : Mapping user details from context with DN cn=Eriksson\, Viktor - e-bolvier,ou=External Users,ou=xxx,ou=Sweden,ou=Newxxx,dc=xxx,dc=internal
2023-11-25T23:10:54.455+01:00 DEBUG 27484 : Authenticated user
But despite taking a long time it doesnt seem to find any roles.
So my questions.
Why is the LDAP-client so fast and seems to get me the result I want but the code is suuuper slow and doesnt return anything?
Why is my dn encoded with weird characters in it?
Not sure what this parameter does but everything started working when I changed it.
authorities.setSearchSubtree(true);
I also added setIgnorePartialResultException(true);
And removed referral=follow.
So now it is fast and maps roles correctly.
My code: