If you're working on a Spring Security (and especially an OAuth) implementation, definitely have a look at the Learn Spring Security course:
>> LEARN SPRING SECURITYMocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.
Get started with mocking and improve your application tests using our Mockito guide:
Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.
Get started with understanding multi-threaded applications with our Java Concurrency guide:
Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:
Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
But these can also be overused and fall into some common pitfalls.
To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:
Get started with Spring and Spring Boot, through the Learn Spring course:
>> LEARN SPRINGExplore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:
Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.
I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.
You can explore the course here:
Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.
Get started with Spring Data JPA through the guided reference course:
Refactor Java code safely β and automatically β with OpenRewrite.
Refactoring big codebases by hand is slow, risky, and easy to put off. Thatβs where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.
Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions β one for newcomers and one for experienced users. Youβll see how recipes work, how to apply them across projects, and how to modernize code with confidence.
Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.
1. Overview
In this tutorial, weβll learn how to set up an Authentication Provider in Spring Security, allowing for additional flexibility compared to the standard scenario using a simple UserDetailsService.
2. The Authentication Provider
Spring Security provides a variety of options for performing authentication. These options follow a simple contract: an AuthenticationProvider processes an Authentication request, and a fully authenticated object with full credentials is returned.
The standard and most common implementation is the DaoAuthenticationProvider, which retrieves the user details from a simple, read-only user DAO, the UserDetailsService. This User Details Service only has access to the username in order to retrieve the full user entity, which is enough for most scenarios.
More custom scenarios will still need to access the full Authentication request to be able to perform the authentication process. For example, when authenticating against some external, third-party service (such as Crowd), both the username and password from the authentication request will be necessary.
For these more advanced scenarios, weβll need to define a custom Authentication Provider:
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
final String name = authentication.getName();
final String password = authentication.getCredentials().toString();
if (!"admin".equals(name) || !"system".equals(password)) {
return null;
}
return authenticateAgainstThirdPartyAndGetAuthentication(name, password);
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
Here, we have a generic method that returns an Authentication object. Its implementation can vary based on how we want to authenticate. As an example, we can write an example of a fixed credentials method:
private static UsernamePasswordAuthenticationToken authenticateAgainstThirdPartyAndGetAuthentication(String name, String password) {
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
final UserDetails principal = new User(name, password, grantedAuths);
return new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
}
It is worth noting that we also add an authority to our UserDetails object. In real-world scenarios, implementing the method above according to your needs is necessary as the short article may not cover all situations.
3. Register the Auth Provider
Now that weβve defined the Authentication Provider, we need to specify it in the XML Security Configuration using the available namespace support:
<http use-expressions="true">
<intercept-url pattern="/**" access="isAuthenticated()"/>
<http-basic/>
</http>
<authentication-manager>
<authentication-provider
ref="customAuthenticationProvider" />
</authentication-manager>
4. Java Configuration
Next, weβll take a look at the corresponding Java configuration:
@Configuration
@EnableWebSecurity
@ComponentScan("com.baeldung.security")
public class SecurityConfig {
@Autowired
private CustomAuthenticationProvider authProvider;
@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder =
http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(authProvider);
return authenticationManagerBuilder.build();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests(request -> request.anyRequest()
.authenticated())
.httpBasic(Customizer.withDefaults())
.build();
}
}
Here, we configure the authentication mandatory for all the requests and configure the Http basic authentication as well.
5. Performing Authentication
Requesting Authentication from the Client is basically the same with or without this custom authentication provider on the back end.
Weβll use a simple curl command to send an authenticated request:
curl --header "Accept:application/json" -i --user user1:user1Pass
http://localhost:8080/spring-security-custom/api/foo/1
For this example, we secured the REST API with Basic Authentication.
And we get back the expected 200 OK from the server:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=B8F0EFA81B78DE968088EBB9AFD85A60; Path=/spring-security-custom/; HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 02 Jun 2013 17:50:40 GMT
6. Conclusion
In this article, we explored an example of a custom authentication provider for Spring Security.
