Combination of HTTP Filter not working with ignore() method from WebSecurity - spring

I have made Filter which is added like that in Spring Security:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/", "/#/", "resources/static/**").permitAll().anyRequest().permitAll()
.antMatchers(HttpMethod.POST, "/api/auth").permitAll().anyRequest().permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/api/auth", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in header
.addFilterBefore(new JWTAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
Unfortunately request /api/auth has no controller in my Spring Boot app. It only works in filter. So the frontend hit this api to authenticate yourself.
In my app I also had to add
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/static/**").anyRequest();
}
to ignore static files because the first method doesn't exclude it properly. And the ignore() cause the problem because it calls /api/auth which has no equivalent in backend but only exists in .js files. What is more ignore() method ignore all requests from the path in which /api/auth is - this api returns 404 when I want to call when ignore() method is uncommented. So the question is how to make a work around to make it work properly?

Related

Spring security - create 2 filter chains with specific matchers

I'm in the process of implementing ADFS support to an existing spring project.
Since we already have our own JWT authentication, which we want to work in parallel to ADFS authentication, I want to implement a new filter chain that will handle only certain API request paths.
By this I mean I want to create:
ADFS filter chain that will handle all the /adfs/saml/** API calls
Leave the default filter chain that will handle all the rest API calls
I'm using the ADFS spring security lib that defines the filter chain like this:
public abstract class SAMLWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
//some code
protected final HttpSecurity samlizedConfig(final HttpSecurity http) throws Exception {
http.httpBasic().authenticationEntryPoint(samlEntryPoint())
.and()
.csrf().ignoringAntMatchers("/saml/**")
.and()
.authorizeRequests().antMatchers("/saml/**").permitAll()
.and()
.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class)
.addFilterAfter(filterChainProxy(), BasicAuthenticationFilter.class);
// store CSRF token in cookie
if (samlConfigBean().getStoreCsrfTokenInCookie()) {
http.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
}
return http;
}
}
And I extend this class:
#EnableWebSecurity
#Configuration
#Order(15)
#RequiredArgsConstructor
public class ADFSSecurityConfiguration extends SAMLWebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
samlizedConfig(http)
.authorizeRequests()
.antMatchers("/adfs")
.authenticated();
}
}
But when debugging I see that this new filter chain is set to match "any" request.
So I'm probably setting the matchers wrong.
Actually, after reading the official docs the answer was a simple one:
(see "Creating and Customizing Filter Chains" section)
#Override
protected void configure(final HttpSecurity http) throws Exception {
samlizedConfig(http)
.antMatcher("/adfs/**");
}
It should not be put after .authorizeRequests() but strait on the first matcher.

Spring HttpSecurity: Custom web security expressions

I am trying to configure the security of a new spring web application to check requests done against some of my urls.
Since none of the built-in expressions were valid for my logic, I decided to write my own, but it is not working at all.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().cacheControl();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**/actuator/**").permitAll()
.antMatchers("/**/instances/**").permitAll()
//Custom expresion to check against
.antMatchers("/(?!login|user-profiles)/**").access("#checkAccess.hasRoleSelected()")
.anyRequest().authenticated()
.and()
.httpBasic().disable()
.addFilterBefore(new JWTLoginFilter(jwtConfig.getUri(), authenticationManager(), tokenService), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JwtTokenAuthenticationFilter(tokenService), UsernamePasswordAuthenticationFilter.class);
}
#Service
public class CheckAccess {
public boolean hasRoleSelected() {
return true;
}
}
As you can see in the documentation, to get this done you need a bean with a method returning a boolean value. While I do have both, the method is never called and no error is thrown.
What am I missing?
Btw, I am running 5.2.2 version of spring security.
Your antMatcher is invalid.
.antMatchers("/(?!login|user-profiles)/**").
Have a look at the allowed patterns in the AntPathMatcher doc.
It is basically, "?", "*" and "**".
You might want to give the regexMatcher a try, instead.

How to allow Swagger to bypass WebSecurityConfig?

I have a basic config like this
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
protected void configure(HttpSecurity httpSecurity) throws Exception {
// We don't need CSRF for this example
httpSecurity.csrf().disable()
// dont authenticate this particular request
.authorizeRequests().antMatchers("/authenticate").permitAll().
// all other requests need to be authenticated
anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
So basically it allows /authenticate through but everything else needs token. How do I allow it to bypass Swagger as well? It's make development difficult because the team relies on Swagger to see the API docs.
Add the swagger endpoints in antMatchers with permitAll(). OR you can use configure(WebSecurity WebSecurity) and use .ignoring() see here
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests()
.antMatchers("/authenticate").permitAll()
.antMatchers("/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**").permitAll()
.anyRequest().authenticated().and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}

Spring Boot + Spring Security permitAll() and addFilter() configuration does not have effect

URL patter with /login should go through the LoginFilter where the user id and password is validated - working fine
URL pattern with /users/register should not go through any of the filer but it is always passing through the JWTAuthentication filter - not working fine
All other URL pattern should go through the JWTAuthentication filter for authorization - working fine
Below is my code for Security Configuration. Kindly help me with what I am missing in this code. How do I configure the filter such that JWT authentication happens for the URL pattern other than /login and /register
Spring-security-core:4.2.3, spring-boot:1.5.4
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.antMatchers(HttpMethod.POST, "/users/register").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new LoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in header
.addFilterBefore(new NoLoginAuthenticationFilter("/users/register"), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter("/**", authenticationManager()),
UsernamePasswordAuthenticationFilter.class);
}
What you want is to ignore certain URLs.
For this override the configure method that takes WebSecurity object and ignore the pattern.
Try adding below method override to your config class.
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/users/register/**");
}

Spring Security permitAll() for one URL under some pattern

I have /my-app/login url and I want to permitAll() for this URL. But this page under /my-app/** pattern which permit access only for registered user.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/**").access("hasRole('USER')")
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
How to do it?
Add .antMatchers("/my-app/login").permitAll() BEFORE .antMatchers("/my-app/**")... . The request matchers are stored in an list (ordered by the order in which they are defined), and Spring security will use the first rule thats matchers match to the current request. So put the most specific first and the common rules afterwards.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/login").permitAll()
.antMatchers("/my-app/**").access("hasRole('USER')")
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
If my-app is the name of your application, and therefore the url that is by your application server (Tomcat) to map the url to the application, then you have to ommit it in the antMatcher because the antMatcher is configured "only" by the application relative url: /my-app/login become /login and /my-app/** become /**
add .anyRequest().permitAll() as last "matcher" of authorizeRequests()
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/my-app/**").access("hasRole('USER')")
.anyRequest().permitAll()
.and()
.httpBasic()
.authenticationEntryPoint(entryPoint());
}
But to be honest: you use some kind of black listing (allow all URLs except some black listed) - and this is not the recommended way (from some security perspective). Because if you forget to add or misspell one URL that should been protected, then it is accessible for every body. The more secure way is to deny every url and allow only some (white list).

Resources