i am new to spring security,problem is that filter is applied to all request urls i-e. /api/user/signup
. i want to exclude /api/user/signup
path to go through the filter. i even tried following
web.ignoring()
.antMatchers("/api/user/**")
.antMatchers("/api/user/signup")
but filter again applied to it. Filter requires authkey token and signup request obvously will have no token. and it will through exception when it don't finds the token.Following is spring security java config class
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
AuthenticationTokenProcessingFilter authenticationTokenFilter;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/api/user/**")
.antMatchers("/api/user/signup")
;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
//allow anonymous POSTs to login
.antMatchers("/api/user/signup").permitAll()
//allow anonymous GETs to API
.antMatchers(HttpMethod.GET, "/api/**").permitAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
;
}
and here is my token filter class
@Component
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
// @Autowired UserService userService;
@Autowired
TokenHandler tokenUtils;
@Autowired
AuthenticationManager authManager;
public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) {
this.authManager = authManager;
}
public AuthenticationTokenProcessingFilter() {
super();
// TODO Auto-generated constructor stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
@SuppressWarnings("unchecked")
HttpServletRequest req = (HttpServletRequest) request;
SecurityContext context = SecurityContextHolder.getContext();
if (context.getAuthentication() != null && context.getAuthentication().isAuthenticated()) {
// do nothing
}else {
//System.out.println("Not Authenticated");
if(req != null && req.getHeader("authKey") != null && req.getHeader("authKey").length() >0 ) {
String token = req.getHeader("authKey");
System.out.println("Found Token:"+req.getHeader("authKey"));
// validate the token
User userDetails = tokenUtils.parseUserFromToken(token);
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication authentication =
new UsernamePasswordAuthenticationToken(userDetails.getEmail(), userDetails.getPassword(),grantedAuths);
// set the authentication into the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
System.out.println("Is Authenticated:?"+ context.getAuthentication().isAuthenticated());
// continue thru the filter chain
chain.doFilter(request, response);
System.out.println(" request is delegeted");
}else{
// Do your business stuff here for all paths other than /specialpath.
System.out.println(" Token Not Found");
throw new ServletException("Token not found in Request");
}
}
}
following is error log when /api/user/signup
comes
Token Not Found
2015-05-17 09:38:36.742 ERROR 5096 --- [nio-8090-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Token not found in Request] with root cause
javax.servlet.ServletException: Token not found in Request
at com.bitsparlour.sadaf.cloud.application.AuthenticationTokenProcessingFilter.doFilter(AuthenticationTokenProcessingFilter.java:93)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
The solution is to mimic the good old namespace way of having multiple <http ...>
blocks. With Java configuration, you can also have multiple classes extending WebSecurityConfigurerAdapter
. Spring Security Reference Manual has an example for that. Extracts :
@EnableWebSecurity
public class MultiHttpSecurityConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) { 1
...
}
@Configuration
@Order(1) 2
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**") 3
...
}
}
@Configuration 4
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
...
}
}
}
Notes :
Authentication
as normalWebSecurityConfigurerAdapter
that contains @Order
to specify which WebSecurityConfigurerAdapter
should be considered first.http.antMatcher
states that this HttpSecurity
will only be applicable to URLs that start with /api/
WebSecurityConfigurerAdapter
. If the URL does not start with /api/
this configuration will be used (no @Order
defaults to last)