This question already has answers here:
Filter invoke twice when register as Spring bean
(3 answers)
Closed 1 year ago.
I use Spring Boot 2.5.6. I want to skip specific URL (/doc.html).
I have created a JwtAuthenticationTokenFilter extending OncePerRequestFilter
#Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
//the logic of authentication
}
And then I create SecurityConfig extending WebSecurityConfigurerAdapter
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web)
throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/doc.html");
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/doc.html").anonymous()
.and()
.requestMatchers().antMatchers("/doc.html");
but when I access localhost:8080/doc.html, the /doc.html didn't skip;
and I also try to override shouldNotFilter in JwtAuthenticationTokenFilter.java, but it did't work also:
#Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return (
new AntPathMatcher().match("/doc.html", request.getServletPath()));
}
You can create a simple array inside JwtAuthenticationTokenFilter if you want to bypass for multiple Urls.
For example:
private static final String[] excluded_urls = {
"/login",
"**/doc.html"
};
And then override shouldNotFilter method:
#Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String url = request.getRequestURI();
return Stream.of(excluded_urls).anyMatch(x -> pathMatcher.match(x, url));
}
Where
pathMatcher = new AntPathMatcher();
//can be injected or create wherever required
Your JwtAuthenticationTokenFilter will be picked up by Spring as a component and will be included in the filter chain and will not be automatically excluded through your SecurityConfig.
So overwriting shouldNotFilter seems like a valid approach and should work as expected.
You could try to use request.getRequestURI() instead of request.getServletPath() in order to ensure to match the actual request path. See this for further details.
Related
I need to develop the security of a rest service wirh Spring Security (version 4.0.3. RELEASE).
The scenario is:
authenticate the client performing the request (client id + client
token on custom header)
in case of errors, a JSON response needs to be sent
I created a custom OncePerRequestFilter that does the job of reading a custom token just as if it was a basic auth token.
public class MyClientAuthorizationFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// omitting implementation
}
}
Then I created my own AuthenticationEntryPoint that does the job of writing the JSON error in the response.
public class MyAuthorizationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
// omitting implementation
}
}
Then I wired them up like that:
#Configuration
#EnableWebSecurity
public class WebApiSecurityConfig extends WebSecurityConfigurerAdapter implements TogatherWebApiCostants {
private static final Logger log = LoggerFactory.getLogger(WebApiSecurityConfig.class);
private #Inject Environment environment;
#Bean
protected AuthenticationEntryPoint clientAuthorizationEntryPoint() {
return new MyAuthorizationEntryPoint();
}
#Bean
protected Filter clientAuthorizationFilter() {
return new MyAuthorizationFilter();
}
/**
* #see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
log.debug("Configuring HTTP security");
// #formatter:on
http
.addFilterBefore(clientAuthorizationFilter(), BasicAuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(clientAuthorizationEntryPoint());
// #formatter:off
}
}
Everything works, except the custom entry point. It doesn't get fired and it seems Spring is still using the default one. I've also tried to switch to XML config (I'm much more used to it rather than with JavaConfig approach) but the behavior remains the same.
Can anyone tell me what I'm doing wrong?
NOTE: I tried to debug Spring Security by adding a logger org.springframework.security with level set to debug, but I dont see any log message
~~~~~~~~~~~~~~
EDIT: Adding current workaround
As of now, lacking an elegant solution, I just explicitly called the entry point from the filter.
public class MyClientAuthorizationFilter extends OncePerRequestFilter {
...
private #Inject AuthenticationEntryPoint entryPoint;
...
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
// omitting logic
} catch(AuthenticationException ae) {
SecurityContextHolder.clearContext();
entryPoint.commence(request, response, ae);
return;
}
}
}
It looks that you are passing wrong object in authenticationEntryPoint() of WebApiSecurityConfig implementation class, pass AuthenticationEntryPoint implementation class object which is here TogatherWebApiClientAuthorizationEntryPoint and check if you are getting custom error.
You should paste your filter after ExceptionTranslationFilter
#Override
protected void configure(HttpSecurity http) throws Exception {
log.debug("Configuring HTTP security");
// #formatter:on
http
.addFilterAfter(clientAuthorizationFilter(), ExceptionTranslationFilter.class)
.exceptionHandling().authenticationEntryPoint(clientAuthorizationEntryPoint());
// #formatter:off
}
I have the following configuration for my app:
#EnableTransactionManagement
#EnableWebSecurity
public class SecurityApiConfiguration
extends WebSecurityConfigurerAdapter {
...
}
And I wanted to add an HandlerInterceptorAdapter. Is that possible using WebSecurityConfigurerAdapter? I just see examples using WebMvcConfigurerAdapter.
I was also faced same issue with Spring-boot 2.0, Since the reason behind why it doesn't support as name itself says HandleInterceptor, always associated with WebMVCConfigurationAdpater. And in other hand as we have extent support filter with WebSecurityConfigureAdapter we make an use of OncePerRequestFilter
public class SampleInterceptorFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//Your custom logic
}
}
#Bean
public SampleInterceptorFilter sampleInterceptorFilter() {
return new SampleInterceptorFilter();
}
#Bean
protected FilterRegistrationBean sampleInterceptorFilterRegistor() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(sampleInterceptorFilter()());
bean.setName("SOME_NAME_FILTER");
bean.setEnabled(false);
return bean;
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf().disable();
//Here we need to configure accordingly order of filter plays vital role
http.addFilterAfter(cyzfilter(), ExceptionTranslationFilter.class).addFilterAfter(xyzFilter(),
ServiceUserPreAuthFilter.class).addFilterBefore(SampleInterceptorFilter(), ServiceUserPreAuthFilter.class);
}
How can I configure Spring Security to use a custom filter for all requests except the ones I whitelist in the same level, e.g. "/login" skips my filter but every thing else "/**" goes through the filter.
As a workaround I could use different prefixes, "/secured/**" vs "/whitelist/**" or ignore the whitelisted ones in the filter, but that does not seem to be a clean solution.
I already tried setting up two configurations with #Order(1 and 2) but it didn't work.
#EnableWebSecurity
public class SpringSecurityConfig {
#Configuration
#Order(1)
#EnableGlobalMethodSecurity(securedEnabled = true)
public static class JwsSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Autowired
private StatelessAuthenticationFilter statelessAuthenticationFilter;
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/login");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").authenticated()
.anyRequest().authenticated()
.and().addFilterBefore(statelessAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return authenticationManager();
}
}
}
In the spring-boot app, I have created few API calls. I want to add a filter only for few urls. The security config is as follows:
#Configuration
#EnableWebMvc
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.addFilterBefore(authenticationFilter(), BasicAuthenticationFilter.class)
.authorizeRequests().anyRequest().denyAll();
http.authorizeRequests().antMatchers("/api/user").permitAll();
}
AuthenticationFilter authenticationFilter() throws Exception
{
AuthenticationFilter filter = new AuthenticationFilter();
return filter;
}
}
I don't want filter to be applied for any api call except /api/user , so I denied for all urls and permitted for /api/user.
AuthorizationFilter class is as follows:
public class AuthenticationFilter extends OncePerRequestFilter
{
public AuthenticationFilter()
{
super();
}
#Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException
{
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String headerName = headerNames.nextElement();
System.out.println("headerName " + headerName);
System.out.println("headerVal " + request.getHeader(headerName));
}
chain.doFilter(request,response);
}
}
This just prints all header information. Currently it is printing header information on all api calls but I want this to be printed only in case of /api/user and not on any other api call. Please suggest what changes shall I made?
Got a working solution
#Configuration
#EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**");
// add security constraints for /api/... here
}
/* rest of config */
}
How to ignore Spring Security config for every thing except a pattern
I am developing an application with Spring Boot + spring security. For the same i have defined a filter as.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/authtoken").permitAll()
.antMatchers("/authenticate**").permitAll()
.antMatchers("/authfailure").permitAll()
.antMatchers("/**").authenticated()
.and()
.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(accessFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(tokenAuthenticationProvider)
.antMatcher("/**").exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
}
Where tokenFilter is an instance of AuthTokenFilter(class that has code for authentication and is injected to using #inject) .
AuthTokenFilter implements methods of Filter interface as.
public class AuthTokenFilter implements Filter {
ServletContext sc ;
#Override
public void init(FilterConfig fc) throws ServletException {
sc = fc.getServletContext();
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
-------
-------
}
My issue is when I run the app using SpringBoot , it runs fine. But when I create a war out of it and run the same in a tomcat, neither the init nor the doFilter are invoked for the request. Hence it returns unauthorized.
Same happens for accessFilter.
Does anyone know the reason behind this behavior? or What changes I need to make to get my app working on tomcat?
What Tomcat version you use?
I am not sure, but try this:
In declaration of class AuthTokenFilter, add the anotation #Component
I have one project with filter and only write:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter ...
.