I was recently working on a project where there
was a need to create custom web services that would connect to my-company and
other back end systems. For a variety of reasons, it was decided to use Spring
Boot as the framework for implementing these web services. One of the
requirements was to use HTTP basic authentication when calling the web services
and authenticate the user against Active Directory (AD) making sure that the
user was also a member of specific group(s). This seems like a very simple
requirement and my first thought was to use Spring Security with annotations to
do this.
The key to
implementing this was to create a new
ActiveDirectoryLdapAuthenticationProvider
when configuring
the AuthenticationManagerBuilder
and applying that
with the correct settings. This is done by creating a class to extend WebSecurityConfigurerAdapter
and overriding the configure(AuthenticationManagerBuilder auth)
method. The setSearchFilter()
method is used to change the LDAP query from the default
to whatever is set in the application.properties
.
The
default user search filter is:
(&(objectClass=user)(userPrincipalName={0})
The user search filter
can be changed as needed. It is an LDAP query that replaces the
userPrincipalName substitution {0} with username@domain. In this case, a
check was added to see if the user is also a member of a specific group using a
“memberof” attribute. This may be different depending on how you have set
up Active Directory. Use a tool like Apache Directory Studio to test your query.
(&(objectClass=user)(userPrincipalName={0})(memberof=CN=ServiceAccounts,OU=alfresco,DC=mycompany,DC=com))
A final change made in the overriding method was to set erase
credentials to false (“auth.eraseCredentials(false);” ) in order to make the password available for
later use in the web service. The user name and password were needed to make
web services calls to my-company. By default, the password is cleared.
The below code snippet shows how the user name and
password were obtained. This is used within the service that makes calls to my-company.
Authentication auth =
SecurityContextHolder.getContext().getAuthentication();
String userName = auth.getName();
String password =
(String)auth.getCredentials();
Complete class used to configure Spring Security for the
project.
package com.ActiveDirectoryLdap;
import
org.springframework.beans.factory.annotation.Value;
import
org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import
org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;
@Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter
{
@Value("${ldap.url:ldap://mycompany.com:389}") private String url;
@Value("${ldap.domain}:mycompany.com") private String domain;
@Value("${ldap.userDNPattern:}") private String userDNPattern;
@Override
protected void
configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.httpBasic();
}
@Override
public void
configure(AuthenticationManagerBuilder auth) throws Exception
{
ActiveDirectoryLdapAuthenticationProvider adProvider =
new
ActiveDirectoryLdapAuthenticationProvider(domain,url);
adProvider.setConvertSubErrorCodesToExceptions(true);
adProvider.setUseAuthenticationRequestCredentials(true);
// set pattern
if it exists
// The
following example would authenticate a user if they were a member
// of the
ServiceAccounts group
//
(&(objectClass=user)(userPrincipalName={0})
//
(memberof=CN=ServiceAccounts,OU=my-company,DC=mycompany,DC=com))
if
(userDNPattern != null && userDNPattern.trim().length() > 0)
{
adProvider.setSearchFilter(userDNPattern);
}
auth.authenticationProvider(adProvider);
// don't erase
credentials if you plan to get them later
// (e.g using
them for another web service call)
auth.eraseCredentials(false);
}
}
Using Spring Security makes it very easy to add Active
Directory support with HTTP basic authentication.