I've configured the Spring Boot Security as per: https://spring.io/guides/gs/securing-web/
I am able to login using my credentials perfectly. However, I need to add a checking that the AD user must also belong to a specific AD group (ie. AD-this-is-a-specific-group). On login, if the user does not belong to the specific AD group, then it should return a login error.
I've been searching for hours now and cannot seem to find a clear way to do this in the WebSecurityConfigurerAdapter
, am I using the auth.groupSearchFilter
correctly?
Here is my code:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
Environment env;
public LdapContextSource contextSource () {
LdapContextSource contextSource= new LdapContextSource();
contextSource.setUrl(env.getRequiredProperty("ldap.url"));
contextSource.setBase(env.getRequiredProperty("ldap.baseDn"));
contextSource.setUserDn(env.getRequiredProperty("ldap.bindDn"));
contextSource.setPassword(env.getRequiredProperty("ldap.batchPassword"));
contextSource.afterPropertiesSet();
return contextSource;
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.ldapAuthentication()
.userSearchFilter("(cn={0})")
.groupSearchBase("OU=Account Groups,OU=ITS Security")
.groupSearchFilter("(cn=AD-this-is-a-specific-group)")
.contextSource(contextSource());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().fullyAuthenticated()
.and()
.formLogin();
}
In order to authenticate a user with an LDAP directory you first need to obtain their DN as well as their password. With a login form, people typically enter a simple identifier such as their username or email address. You don't expect them to memorise the DN of their directory entry.
I am sorry for beeing 5 years late for the party but I had the exact same problem with my very simple LDAP authentication implemented in Spring Boot.
I only wanted this: - Is it the correct username? - Is it the correct password? - If yes, is the usr in group MYGROUP?
So my configure method now looks really small. I added the populator in a separate bean, just realize that I needed to add it in "auth.ldapAuthentication" so it would be called.
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userSearchFilter("uid={0}")
.ldapAuthoritiesPopulator(ldapAuthoritiesPopulator())
.groupSearchFilter("(member={0})")
.contextSource(contextSource());
}
@Bean
public LdapAuthoritiesPopulator ldapAuthoritiesPopulator() {
DefaultLdapAuthoritiesPopulator populi = new DefaultLdapAuthoritiesPopulator(contextSource(), "") {
@Override
public Set<GrantedAuthority> getGroupMembershipRoles(String userDn, String username) {
Set<GrantedAuthority> groupMembershipRoles = super.getGroupMembershipRoles(userDn, username);
boolean isMemberOfSpecificAdGroup = false;
for (GrantedAuthority grantedAuthority : groupMembershipRoles) {
if ("ROLE_MYGROUP".equals(grantedAuthority.toString())) {
isMemberOfSpecificAdGroup = true;
break;
}
}
if (!isMemberOfSpecificAdGroup) {
throw new BadCredentialsException("User must be a member of " + "ROLE_MYGROUP");
}
return groupMembershipRoles;
}
};
return populi;
}
@Bean
public DefaultSpringSecurityContextSource contextSource() {
return new DefaultSpringSecurityContextSource("ldap://blabla-some-url:389/dc=something,dc=something,dc=ch");
}
And by the way: The url did not work like mentioned in the Spring Boot guide it only worked like this, like everything in one line:
return new DefaultSpringSecurityContextSource("ldap://blabla-some-url:389/dc=something,dc=something,dc=ch");
And by the way for everyone following that guide: If you connect to an already existing LDAP server you don't need all those "spring.ldap.embedded" application properties.
So thank you alot for your help!
Not sure if this is the best way to do this (in terms of Spring Security's lifecycle), but basically I provided my own DefaultLdapAuthoritiesPopulator
, where I only override the getGroupMembershipRoles
.
First thing though, I have wrong auth.groupSearchFilter
above, it should be:
.groupSearchFilter("(member={0})")
Second, I've created an anonymous class with overridden method (that calls the super and checks for a the membership in the list of roles):
auth
.ldapAuthentication()
.ldapAuthoritiesPopulator(new DefaultLdapAuthoritiesPopulator(contextSource, "OU=Account Groups,OU=ITS Security") {
@Override
public Set<GrantedAuthority> getGroupMembershipRoles(String userDn, String username) {
Set<GrantedAuthority> groupMembershipRoles = super.getGroupMembershipRoles(userDn, username);
boolean isMemberOfSpecificAdGroup = false;
for (GrantedAuthority grantedAuthority : groupMembershipRoles) {
if ("ROLE_AD-this-is-a-specific-group".equals(grantedAuthority.toString())) {
isMemberOfSpecificAdGroup = true;
break;
}
}
if (!isMemberOfSpecificAdGroup ) {
throw new BadCredentialsException("User must be a member of " + "AD-this-is-a-specific-group");
}
return groupMembershipRoles;
}
})
.userSearchFilter("(cn={0})")
.groupSearchBase("OU=Account Groups,OU=ITS Security")
.groupSearchFilter("(member={0})")
.contextSource(contextSource);
I'll put this here since I think it's the easier way without overriding any method.
In user search filter (i'll use yours) add the following if it corresponds to your LDAP structure
Original:
.userSearchFilter("(cn={0})")
Modified to search roles:
.userSearchFilter("(&(cn={0})(memberOf=CN=MYGROUP,OU=GROUP,DC=com,DC=company)")
This searches both the user and the membership
In my case I had to do this because I have 3 possible roles:
(&(cn={0})(|(group1)(group2)(group3)))
As you can see it searches user AND 1 OR more roles
Credit to this question's answer: Spring Security Ldap, log in only users in specified group
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With