Spring Security Custom Authentication Provider
I recently had the requirement for user authentication in a spring boot application as follows:
Check if the user exist in local database user table
-> if the user exist, then authenticate it to external windows AD server.
In Spring Security, an Authentication request is processed by an AuthenticationProvider and a fully authenticated object with full credentials is returned. Some standard and common implementation of Authentication Provider are DaoAuthenticationProvider.
Here, we’ll define a custom Authentication Provider to achieve our authentication requirement.
Suppose the environment are as follows:
- Local db details :Postgresql 13.1, host- server1, port 5432, database — mydb1, users table — myuser
- Windows AD server details: domain — example.examplegroup.co.in, IP Address — 192.168.1.25
Steps:
- Add following dependencies to pom.xml file
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency><dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency><dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2. Modify application.properties files
spring.datasource.url=jdbc:postgresql://server1:5432/mydb1
spring.datasource.username=pguser
spring.datasource.password=pguser
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
3. Add domain class for user — Myuser.class
@Entity
public class Myuser {
@Id
private String username;
// constructor, getters, setter methods
}
4. Add Repo interface for user — MyuserRepo.class
@Repository
public interface MyuserRepo extends JpaRepository<Myuser, String> {
}
5. Add service class for user — MyuserService.class
@Service
@Transactional
public class MyuserService {
private final MyuserRepo myuserRepo;
public MyuserService(MyuserRepo myuserRepo) {
this.myuserRepo = myuserRepo;
}// methods to check whether user exist in the table
public boolean ifExist(String username) {
Optional<Myuser> myuser = myuserRepo.findById(username);
return myuser.isPresent();
}}
6. Create the custom authentication provider
Inside Custom Authentication provider first we will check whether user is present in myuser table and then will use ActiveDirectoryLdapAuthenticationProvider to perform windows AD authentication.
CustomAuthenticationProvider must override two methods
- Authentication authenticate(Authentication authentication)
- boolean supports(Class<?> authentication)
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final MyuserService myuserService;//constructor with field
public CustomAuthenticationProvider( MyuserService myuserService) {
super();
this.myuserService = myuserService;
}
//ActiveDirectoryLdapAuthenticationProvider Bean
@Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider(){
ActiveDirectoryLdapAuthenticationProvider adLdapProvider =
new ActiveDirectoryLdapAuthenticationProvider(
"example.examplegroup.co.in", "ldap://192.168.1.25");adLdapProvider.setConvertSubErrorCodesToExceptions(true); return adLdapProvider;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {// get username
String username = authentication.getName();//check whether user exist in myuser table
boolean ifPresent = epuserService.findOne(username);
if(ifPresent) {
return activeDirectoryLdapAuthenticationProvider()
.authenticate(authentication);
}
else throw new UsernameNotFoundException("User not found.");
}
@Override
public boolean supports(Class<?> authentication) {
return authentication
.equals(UsernamePasswordAuthenticationToken.class);
}
}
7. Define WebSecurityConfig class in which our custom authentication builder will be utilized.
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
private CustomAuthenticationProvider customAuthProvider;
//constructor
public WebSecurityConfig (CustomAuthenticationProvider customAuthProvider ) {
super();
this.customAuthProvider = customAuthProvider;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and()
.formLogin();
}
@Override
protected void configure( AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider( customAuthProvider);
}
}
Resources :
https://www.baeldung.com/spring-security-authentication-provider