Security on Spring resources only works with '#PreAuthorize' - spring

I don't know what I'm doing wrong, but when I try to secure some REST resources using a ResourceServerConfigurerAdapter it doesn't work. I can only accomplish my goal using #PreAuthorize or setting the security on the WebSecurityConfigurerAdapter.
Actually, the WebSecurityConfigurerAdapter is stealing all possibilities on HttpSecurity settings. I believe that it have something to do with filtering order. I searched for information on the documentation but found it quite vague. I know that on the Spring Boot version 1.5+ the filtering order of ResourceServerConfigurerAdapter has been changed, and I only managed to get it to work after setting a new order on the properties: security.oauth2.resource.filter-order=3
Being more specific, this code (on ResourceServerConfigurerAdapter) doesn't have any result:
#Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatcher(new OAuthRequestedMatcher())
.anonymous().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/api/hello").access("hasAnyRole('USER')")
.antMatchers("/api/me").hasAnyRole("USER", "ADMIN");
}
It is only possible to protect "/api/hello" and "/api/me" annotating #PreAuthorize on the controller methods:
#PreAuthorize("hasAnyRole('USER','ADMIN')")
#GetMapping("/api/hello")
public ResponseEntity<?> hello() {
String name = SecurityContextHolder.getContext().getAuthentication().getName();
String msg = String.format("Hello %s", name);
return new ResponseEntity<Object>(msg, HttpStatus.OK);
}
It is working, however, I fear that it could be done in a better way. Any ideas?

After some digging, I found the solution. The problem is indeed related to the filtering order. The guys at Pivotal changed the Oauth2 Resource Filter Order, as you can see in this passage taken from Spring Boot 1.5 release note:
OAuth 2 Resource Filter
The default order of the OAuth2 resource filter has changed from 3 to
SecurityProperties.ACCESS_OVERRIDE_ORDER - 1. This places it after the
actuator endpoints but before the basic authentication filter chain.
The default can be restored by setting
security.oauth2.resource.filter-order = 3
However, as pointed by #ilovkatie on this thread, the order of the WebSecurityConfigurerAdapter was also changed to 100, taken precedence over ResourceServerConfigurerAdapter.
So, instead of changing ResourceServerConfigurerAdapter's order on properties, a more elegant solution would be to use #Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) on WebSecurityConfigurerAdapter.
This will make the resources configuration take precedence over WebSecurityConfigurerAdapter and it will be possible to set security using HttpSecurity on the ResourceServerConfigurerAdapter, making unnecessary to use #PreAuthorize annotation.

Related

Using two API Key on Swagger Security Scheme with Spring Boot

Is it possible to have two API Keys on Swagger and give them different privileges in my API?
For example:
API_KEY_1 : Has access to one Post method
API_KEY_2 : Has access to all of my API
Many thanks
In terms of Spring Security, that all depends on how you authenticate the API keys in your application. Once you've set up the application to validate an API key and create a SecurityContext, your best bet would be to map to one of two different roles, one for limited access, and one for all access. For example:
#Configuration
public static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.authorizeRequests()
.mvcMatchers(HttpMethod.POST, "/some/api").hasAnyRole("BASIC", "ADMIN")
.anyRequest().hasRole("ADMIN");
}
}
More information and examples of authorization can be found in the docs.

Keep session id in case of presence of special parameter in request. Spring Security

Does anybody know if there any way to configure Spring Security in the way that it doesn't change session id if there is some parameter in the request.
For example:
somesite.com/home.jsp?password=encrypted- change session id after
authentication
somesite.com/home.jsp?password=encrypted& keepsessionid - don't
change session id after authentication
I was thinking about filter chain, maybe removing conditionally SessionManagementFilter, but not sure if this is a proper way, and even if this will be working
For someone with the same question. I found the answer. Different session management strategy can be achieved by using multiple http security configuration (inner classes of main security classes). The special case http security configurer should be adjusted to some special request
#Configuration
#Order(1)
public class SpecialCaseSessionHandlingConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(request -> Check1(request))
.authorizeRequests()
.anyRequest().authenticated();
}
}

How to authenticate some URL and ignore anything else

I want to manage security policy like below. ( HTTP Basic Authorization)
Apply authentication following URLs.
"/foo/", "/bar/"
Ignore anything else URLs. ( Even though requests have Authorization field in header)
I know permitall(). But permitall() is not suitable because it apply security policy when request has Authorization field in headers.
If you want ignore particular url then you need to implement this method.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/static/**");
}
}
You can put your url in place of /static/** in which you want no authentication apply.
Your example means that Spring (Web) Security is ignoring URL patterns
that match the expression you have defined ("/static/**"). This URL is
skipped by Spring Security, therefore not secured.
Read the Spring Security reference for more details:
Click here for spring security details

Protect specific resources id with OAuth2 on Spring Boot

I have a working OAUTH2 implementation on Spring Boot, with AuthorizationServer and ResourceServer on the same implementation, using password grant.
About the server:
The TokenStore is custom and uses a WebService to store the token remotely.
I have a custom AuthenticationProvider.
This works for controlling access to resources based on given authorities, for instance, in the ResourceServer config:
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/resource/**")
.hasAnyAuthority("USER", "ADMIN")
.antMatchers("/api/admin/**")
.hasAnyAuthority("ADMIN");
}
Now, I need to control that USER can access to "/api/resource/1" but not "/api/resource/2", this IDs can change and I fetch the list during the authentication.
I've tried to add the ID's list to OAuth2AccessToken additional information and adding a custom filter in the ResourceServer configuration but it always comes empty.
So, How's the proper way for implementing this without using JWT?
After some thinking and research, If someone is trying to achieve something similar, this is what I'll do:
Map the allowed ID's to authorities, e.g. ID_201 and the modules as roles, so I will have a ROLE_ADMIN.
It's possible to refer to path variables in Web Security Expressions, as explained in here. So the idea is to pass the variable (resource id) and check whether it's allowed or not.
public class WebSecurity {
public boolean checkResourceId(Authentication authentication, int id) {
//check if the list of authorities contains ID_{id}.
}
}
And in the Web Security config:
http
.authorizeRequests()
.antMatchers("/resource/{resourceId}/**").access("#webSecurity.checkResourceId(authentication,#resourceId)")
...
If you're working on Spring Boot with spring-security 4.0.4 be sure to upgrade to 4.1.1 as reported in this bug.

Spring security antMatchers permitAll doesn't work

I know that there are topics with this problem, but the config which I made is correct and I compared it to a project where it works correctly.
I want to "unsecure" a /login endpoint for JWT security, but still the AuthenticationFilter runs before reaching the /login endpoint.
I'm confused why it is no working.
My Code Below :
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
http
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
}
Duplicate: How to add a filter only for one special path WebSecurityConfigurerAdapter
You can't do that with a single Configuration class. Take a look at this question: How to apply spring security filter only on secured endpoints?.
In this case, I think the better solution is to configure multiple HttpSecurity. From Spring IO documentation:
We can configure multiple HttpSecurity instances just as we can have
multiple blocks. The key is to extend the
WebSecurityConfigurationAdapter multiple times. For example, the
following is an example of having a different configuration for URL’s
that start with /api/.
The documentation has a full example with the necessary steps to accomplish this:
Configure Authentication as normal
Create an instance of WebSecurityConfigurerAdapter that contains
#Order to specify which WebSecurityConfigurerAdapter should be
considered first.
The http.antMatcher states that this HttpSecurity
will only be applicable to URLs that start with /api/
Create another instance of WebSecurityConfigurerAdapter. If the URL does not start with /api/ this configuration will be used. This
configuration is considered after ApiWebSecurityConfigurationAdapter
since it has an #Order value after 1 (no #Order defaults to last).
Good luck!

Resources