Reputation: 544
I have a spring application which uses a custom Authentication Filter say filter1 to authorize the request, this filter uses an authentication manager for authentication and is applicable for all urls in application.
Now, I want to implement a different Authentication Filter say filter2 which has to authorize special kind of request say with url (/api/). That is the all the request which has the url like (/api/**) has to use filter2.
Below is the code I've tried so far for this purpose.
public class SecurityAppConfig {
@Configuration
@Order(1)
public static class APISecurityConfig extends WebSecurityConfigurerAdapter {
private CustomAuthenticationManager1 manager1 = new CustomAuthenticationManager1();
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.formLogin().disable().csrf().disable().cors().disable().logout().disable();
if (manager1 != null) {
http.addFilterAfter(new Filter1(manager1),
AnonymousAuthenticationFilter.class);
}
}
}
@Configuration
@Order(2)
public static class OtherApiSecurityConfig extends WebSecurityConfigurerAdapter {
private AuthenticationManager2 manager2 = new AuthenticationManager2();
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.formLogin().disable().csrf().disable().cors().disable().logout().disable();
if (manager2 != null) {
http.antMatchers("/api/**").addFilterAfter(new Filter2(manager2),
AnonymousAuthenticationFilter.class);
}
}
}
}
At the time of app start up both the filter are getting registered with their manager but when this ("/api/**") request comes it goes to the first filter for authentication but never goes to the second filter. If I remove the first filter then it works properly but that would override the filters for other api request.
Below is how I've implemented managers and filters
public class Filter1 extends AbstractAuthenticationProcessingFilter {
//implementation omitted for brevity.
}
public class Filter2 extends AbstractAuthenticationProcessingFilter {
//implementation omitted for brevity.
}
public class AuthenticationManager1 implements AuthenticationManager {
//implementation omitted for brevity.
}
public class AuthenticationManager2 implements AuthenticationManager {
//implementation omitted for brevity.
}
Any thoughts on how can I get this working.
Upvotes: 1
Views: 4571
Reputation: 2030
I don't think that you need two configs for your case. And I don't see why you need to implement your own authentication manager, even two of them. I guess you should use shared authentication manager instead, implement your own AuthenticationProvider
(one for each type of authentication), and implement youe own authentication tokens. Besides that, since you're using AbstractAuthenticationProcessingFilter
as a base class for you filters - you can set filterProcessesUrl
into it, so your filter knows to which URL's it should be applied. So, in brief:
Authentication Tokens:
public class MyAuth1AuthenticationToken extends AbstractAuthenticationToken {
// Implementation depends on you auth scheme (you can look on
// `UsernamePasswordAuthenticationToken` for example)
}
public class MyAuth2AuthenticationToken extends AbstractAuthenticationToken {
// ...
}
Authentication Providers:
public class MyAuth1AuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Implementation really depends on you auth scheme (you can look on
// `AbstractUserDetailsAuthenticationProvider` for example)
}
@Override
public boolean supports(Class<?> authentication) {
// By this we're saying that this auth provider is responsible for our MyAuth1 auth request
return (MyAuth1AuthenticationToken.class.isAssignableFrom(authentication));
}
}
public class MyAuth2AuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// ...
}
@Override
public boolean supports(Class<?> authentication) {
return (MyAuth2AuthenticationToken.class.isAssignableFrom(authentication));
}
}
Filters:
public class Auth1Filter extends AbstractAuthenticationProcessingFilter {
public Auth1Filter(AuthenticationManager authManager, String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// extract user info here
// ...
// populate auth request with your info
MyAuth1AuthenticationToken authRequest = new MyAuth1AuthenticationToken(...);
// authenticate
return this.getAuthenticationManager().authenticate(authRequest);
}
}
public class Auth2Filter extends AbstractAuthenticationProcessingFilter {
public Auth2Filter(AuthenticationManager authManager, String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// extract user info here
// ...
// populate auth request with your info
MyAuth2AuthenticationToken authRequest = new MyAuth1AuthenticationToken(...);
// authenticate
return this.getAuthenticationManager().authenticate(authRequest);
}
}
Security Config:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception
{
// registering our providers
auth
.authenticationProvider(new MyAuth1AuthenticationProvider())
.authenticationProvider(new MyAuth2AuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.formLogin().disable()
.csrf().disable()
.cors().disable()
.logout().disable();
AuthenticationManager authManager = http.getSharedObject(AuthenticationManager.class);
http.addFilterAfter(new Auth1Filter(authManager, "/**"), BasicAuthenticationFilter.class);
http.addFilterAfter(new Auth2Filter(authManager, "/api/**"), BasicAuthenticationFilter.class);
}
}
Hope it helps.
Upvotes: 6