I would like to ask for your help regarding my problem in Spring Security. I have a requirement wherein I have to validate a login credential based on the option selected by the user. Option 1 would be validating the logged in user via third party service. Option 2 would be the normal validation using database authentication level. How can I implement this?
General Strategy
org.springframework.security.authentication.AuthenticationProvider that delegates authentication to the appropriate backend (third-party service, another AuthenticationProvider, etc.).AuthenticationProvider, enabling it to choose the correct authentication backend.AuthenticationProvider as the default authentication provider.Step 1: Implement
AuthenticationProvider
AuthenticationProvider is an interface with a single method. Therefore, a custom implementation may look like:
class DelegatingAuthenticationProvider implements AuthenticationProvider {
@Autowired
private ThirdPartyAuthenticationService service;
@Autowired
@Qualifier("anotherAuthenticationProvider")
private AuthenticationProvider provider;
@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
// Get the user selection.
String selection = (String) authentication.getDetails();
// Take action depending on the selection.
Authentication result;
if("ThirdParty".equals(selection)) {
// Authenticate using "service" and generate a new
// Authentication "result" appropriately.
}
else {
// Authenticate using "provider" and generate a new
// Authentication "result" appropriately.
}
return result;
}
}
Step 2: Pass the user selection to the
AuthenticationProvider
The AuthenticationProvider implementation above picks up the user selection from the details property of the Authentication object. Presumably, the user selection would have to be picked up from the HttpServletRequest and added to the Authentication object before the AuthenticationProvider is invoked. This means, another component that has access to both the Authentication and HttpServletRequest objects needs to be invoked before the AuthenticationProvider is called.
The Authentication object is created by an implementation of AbstractAuthenticationProcessingFilter. This class has a method named attemptAuthentication that accepts an HttpServletRequest object and returns an Authentication object. So it seems this would be a good candidate for implementing what is needed. For username-password based authentication, the implementation class is UsernamePasswordAuthenticationFilter. This class returns a new instance of UsernamePasswordAuthenticationToken, which is an implementation of Authentication. So, a class extending UsernamePasswordAuthenticationFilter should be sufficient.
class ExtendedUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
...
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, password);
authentication.setDetails(obtainUserSelection(request));
...
return authentication;
}
}
obtainUserSelection is a private method that gets the user selection out of the request.
Step 3: Configuration
Configure the AuthenticationProvider and filter implementations in the Spring Security configuration. The exact steps will vary depending on whether XML or Java configuration is used.
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