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