Web ignoring using spring-webflux - java

In spring-mvc is possible to extends from WebSecurityConfigurerAdapter , override configure(WebSecurity web) and do somethink like this:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(AUTH_WHITE_LIST);
}
The main benefit of this approach is that spring-security even will not try to decode passed token. Is it possible to do pretty much the same but using webflux?
I know that i can do like this:
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeExchange().pathMatchers(AUTH_WHITE_LIST).permitAll()
.anyExchange().authenticated();
return http.build();
}
But this way, as far as i know, spring-security will try to parse provided token first.

As far as I know, the equivalent of making sure paths (and tokens) are ignored by spring security in webflux is to use the securityMatcher() method on ServerHttpSecurity. I.e. it should be the same as using the WebSecurity#ignoring() method with antMatchers.
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http.securityMatcher(new NegatedServerWebExchangeMatcher(
ServerWebExchangeMatchers.pathMatchers("/ignore/this/path")))
.authorizeExchange()
.anyExchange().authenticated()
.and()
.csrf().disable()
.build();
}

Related

InvalidTokenException for "unsecured" routes in Spring Security

Since I have updated Spring Boot Version to 2.6.7 I get logs that the way I define unsecured routes is not recommended anymore.
Log message:
You are asking Spring Security to ignore Ant [pattern='/actuator/**']. This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.
The way I was describing the config that Spring Security has to ignore these patterns was done by defining a WebSecurityConfiguration and ignoring those routes. What happens in this case is, that the whole security chain is skipped and the above mentioned logs are written. It's okay for me, but not for Spring ;).
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/actuator/**"
);
}
}
When defining these route as part of the httpSecurity as mentioned in the log. The problem occurs that an expired/invalid token cause an error (401 unauthorized) as well for unsecured routes like /actuator/health.
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Getter
private String[] unsecuredPathList;
#PostConstruct
public void postConstruct() {
this.unsecuredPathList = new String[] {
"/actuator/**"};
}
#Bean
public JwtTokenStore jwtTokenStore() {
return new JwtTokenStore(new CustomJwtAccessTokenConverter(true));
}
#Override
public void configure(ResourceServerSecurityConfigurer resourceServer) throws Exception {
resourceServer.tokenStore(jwtTokenStore());
resourceServer.tokenExtractor(new SessionCookieTokenExtractor());
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.authorities("ANONYMOUS")
.and()
.authorizeRequests()
.antMatchers(unsecuredPathList)
.permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
The goal I want to reach is:
For an unsecure resource the token will not be evaluated/the result is ignored and there is no 401-Unauthorized-Error.
Is there anything I can do in httpSecurity?
Or is there any other recommended way to reach that goal?
Thanks in advance for your help.
There is a group of methods in HttpSecurity class, which allows you to apply defined security rules only to specific paths, and thus create different security filter chains with different rules for different urls.
For example, you can exclude some urls like this:
// convert your String array into a List of RequestMatcher
List<RequestMatcher> excludedPathMatchers = Arrays.stream(unsecuredPathList)
.map(AntPathRequestMatcher::new)
.collect(Collectors.toList());
// configure HttpSecurity to apply filter chain only on paths, that don't match any of the excluded paths
http.requestMatcher(new NegatedRequestMatcher(new OrRequestMatcher(excludedPathMatchers)));
Or you can write something like this, if you have only 1 unsecured endpoint:
http.requestMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/some_url/**")));

Spring 2 security: 403 Forbidden [duplicate]

This question already has answers here:
Spring Security configuration: HTTP 403 error
(8 answers)
Closed 1 year ago.
I have an app that previously was running tests using Spring Boot 1 and which I have updated to 2.0.9.RELEASE.
There are now issues with Spring Security. I know this is the case because if I remove
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<scope>test</scope>
</dependency>
(and any new WebSecurityConfigurerAdapter classes) the tests still succeed. The tests are essentially going to a project controller 'HomeController' and from there going to a service and using a RestTemplate to perform various operations. In reality this is a different app, and if I were writing it from scratch, I would probably do a wiremock but for now and the purposes of this question there is a controller in the test package simulating the required behaviour.
By adding this simple class, I have got past the 403 on the local controller
#TestConfiguration
#EnableWebSecurity
#Order(500)
public class DefaultSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure( HttpSecurity http) throws Exception{
http.authorizeRequests().antMatchers("/").permitAll();
}
}
However, I'm struggling to get past the security on using the RestTemplate. The restTemplate bean is created with basic user and password (simplified a little here)
#Bean
public RestTemplate restTemplate( RestTemplateBuilder restTemplateBuilder ) {
return restTemplateBuilder
.basicAuthorization( "user", "password" )
.build();
}
I can tell by debugging and looking at the interceptors that these are being set.
Now I have added a new configuration class
#TestConfiguration
#EnableWebSecurity
#Order (50)
public class RestTemplateSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure( AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("user")
.password(encoder.encode("password"))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/otherpath/**")
.authenticated()
.and()
.httpBasic();
}
}
But this seems to have no effect on the RestTemplate calls which are consistently called with basic security of user and password and consistently return 403 Forbidden.
The test class is annotated like this
#AutoConfigureMockMvc
#RunWith( SpringRunner.class )
#SpringBootTest( classes = { DefaultSecurityConfiguration.class, ResttemplateSecurityConfiguration.class }, webEnvironment = DEFINED_PORT )
#TestPropertySource( "classpath:test.properties" )
public class HomeControllerTest {
...
And triggered with a 'standard' mockMvc.perform( ...
With the DefaultSecurityConfiguration class in place these fire without issue it is the later calls in the app code using the restTemplate that fail
Is there anything obvious?
Replace:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/otherpath/**")
.authenticated()
.and()
.httpBasic();
}
By this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/otherpath/**")
.authenticated()
.and()
.httpBasic();
http.csrf().disable();
}

Spring Boot 2 security - pre-authenticated token - allow healthcheck

My Spring Boot Actuator healthCheck is blocked because of a (pre_authenticated) token is missing.
There are many answers available, BUT this is question has interference with pre-authenticated security. As far as I searched, this is NOT a duplicate.
How can I allow the health check in a pre-authenticated security environment?
My question is also, do I need more settings (in e.g. the application.properties)?
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(new XyzPreAuthenticatedGrantedAuthoritiesUserDetailsService());
auth.authenticationProvider(provider);
}
// Try-1, see below
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(xyzTokenRequestHeaderAuthenticationFilter(), RequestHeaderAuthenticationFilter.class)
.csrf().disable()
.authorizeRequests()
.antMatchers("/actuator/**").permitAll()
.anyRequest().authenticated();
}
#Bean
public XyzTokenRequestHeaderAuthenticationFilter xyzTokenRequestHeaderAuthenticationFilter() throws Exception {
XyzTokenRequestHeaderAuthenticationFilter filter = new XyzTokenRequestHeaderAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager());
return filter;
}
}
My second try was:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(xyzTokenRequestHeaderAuthenticationFilter(), RequestHeaderAuthenticationFilter.class)
.csrf().disable()
.authorizeRequests()
.antMatchers("/actuator/**").permitAll();
}
It looks like the xyz filter is not implemented in the 'perfect' way.
This way will help you get things workin':
1 - use the management port:
management.server.port=8081
management.security.enabled=false
management.server.address=127.0.0.1
management.server.ssl.enabled=false
management.endpoints.health.sensitive=false
management.endpoint.health.show-details=always
2 - configure both ways web and api. Use this beyond the standard parts:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(STATELESS);
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/actuator/**").permitAll()
.antMatchers("/**").authenticated();
http.addFilterBefore(xyzTokenRequestHeaderAuthenticationFilter(), AbstractPreAuthenticatedProcessingFilter.class);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/actuator/**");
}
3 - Inside the Docker container, use the 8081 port for the healthCheck.
Try to add in .ignoring() and add #EnableGlobalMethodSecurity(prePostEnabled = true), #Configuration at class
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer{
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/actuator/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(xyzTokenRequestHeaderAuthenticationFilter(), RequestHeaderAuthenticationFilter.class);
}
}
The problem seems to be with your XyzTokenRequestHeaderAuthenticationFilter implementation. If you wrote that by extending RequestHeaderAuthenticationFilter, then you must set the property exceptionIfHeaderMissing to false.
If you didn't extend that Spring Security pre auth core class then you need to show the implementation.

HttpSecurity Regex matcher not working as expected

I'm configuring HttpSecurity for a Spring Boot rest server, and I need to make the create user end point not require authentication.
The mapping for the controller method is POST /users/{username}?action=create
I produced the following regex which I tested with online tools to make sure it matched correctly:
(\/users\/)([^\/]+)(\?action=create)
My only rule for usernames was that they cannot contain /, and so I believe that regex fufills that.
However, despite adding the following to the httpsecurity config:
.authorizeRequests()
.regexMatchers(HttpMethod.POST,"(\\/users\\/)([^\\/]+)(\\?action=create)")
.permitAll()
I am still unable to hit my endpoint and am unsure why.
Thanks!
UPDATE:
Apparently my custom filters would be applied unless I configured the WebSecurity object to ignore it completely, like so:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", "/swagger-ui.html", "/webjars/**")
.and().ignoring().regexMatchers(HttpMethod.POST, "(\\/users\\/)([^\\/]+)(\\?action=create)");
}
But now spring is complaining about not being able to find an authentication object...
My original solution was authorizing requests that had been authenticated, the following makes it so ALL requests (anonymous or not) are good to go!
Add this to your custom WebSecurityConfigurerAdapter
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", "/swagger-ui.html", "/webjars/**")
.and().ignoring().regexMatchers(HttpMethod.POST, "(\\/users\\/)([^\\/]+)(\\?action=create)");
}
And just for clarity, this is the controller method it is applied to:
#RequestMapping(value = "/users/{username}",params = {"action="+Action.CREATE}, method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public UserModel createUser(#PathVariable(value="username") String username, #RequestBody UserModel user) {
user.setUsername(username);
return userService.createUser(user);
}

Spring webSecurity.ignoring() doesn't ignore custom filter

I have a set a custom authentication filter in my Spring 4 MVC + Security + Boot project. The filter does it's job well and now I want to disable the security for some URI (like /api/**). Here is my configuration:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/api/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(filter, BasicAuthenticationFilter.class);
}
}
Unfortunately, when I call a resource under /api/... the filter is still chained. I've added println in my filter and it's written to the console on every call. Do you know what's wrong with my configuration?
UPDATE
Filter code:
#Component
public class EAccessAuthenticationFilter extends RequestHeaderAuthenticationFilter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("FILTER");
if(SecurityContextHolder.getContext().getAuthentication() == null){
//Do my authentication stuff
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(user, credential, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
super.doFilter(request, response, chain);
}
#Override
#Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
}
remove #Component on class EAccessAuthenticationFilter,and like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(new EAccessAuthenticationFilter(), BasicAuthenticationFilter.class);
}
https://github.com/spring-projects/spring-security/issues/3958
I don't have enough reputation to add a comment, but for anyone like me who was looking for a little more of an explanation for kimhom's answer, WebSecurityConfigurerAdapter will tell Spring Security to ignore any filters added through it. The filter was then still being invoked because the #Component (or any flavor of #Bean) annotation told Spring to add the filter (again) outside of the security chain. So while the filter was being ignored in the security chain, it was not being ignored by the other (non-security?) chain.
This solved two weeks of headaches for me. In my case my custom filter needed the Authentication object given by the SecurityContext where it kept coming up as null because the security chain was never executed.
I had the correct configuration to ignore some context path in the web security configuration as below..
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v1/api1").antMatchers("/v1/api2");
}
But I mistakenly had added #PreAuthorize(...) on my controller method and it seems like that method level security was overriding any security configuration set up at the start.
After few tests I realized that in fact my configurations are ok and it's just a comprehension problem. The spring.security.ignored=/api/** doesn't bypass or turn off the filter. In reality every request still pass through my custom filter, but the difference is that Spring Security doesn't mind of the authentication status nor the granted authority coming from the custom filter.
I was wondering that the "ignored" property simply bypass the spring security filters. It sounds like I was totally wrong...
I always found the easiest way to do this is to put this configuration in your application.properties:
security.ignored=/api/**
I think you also need it in the Filter class as well (extends RequestHeaderAuthenticationFilter) i.e.
public class EAccessAuthenticationFilter extends RequestHeaderAuthenticationFilter {
public EAccessAuthenticationFilter() {
super(new RequestMatcher() {
RequestMatcher matcher = new AntPathRequestMatcher("/v1/api1");
return matcher.matches(request);
});
}
}

Categories

Resources