Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpringBoot 1.5.x + Security + OAuth2

I have a Spring Boot REST API with OAuth2 Security.

Today I have upgraded my version of spring-boot-starter-parent from 1.4.2 to 1.5.2.

Changes completely confused me.

Before, I could test my REST API with Postman. When my access token was incorrect or I didnt have a rights for specific resources, server response was like:

{
  "error": "access_denied",
  "error_description": "Access is denied"
}

Now it keeps redirect me to /login page... When I log in - it show my resource without any OAuth2 authentication...

I have tried to disable it and I found this magic property:

security.oauth2.resource.filter-order = 3

This line turned off redirects to login page.

However, my questions are:

  • what happened between these 2 releases in term of security?
  • is this "strange" line is an only valid fix?
  • what is a purpose of this login page and what authentication it is using (I checked a requests and responses in Google Chrome and I can't see any access tokens and oauth2 stuff so it is using user repository then only?)

Some more important parts of my code:

pom.xml

<!--- .... -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.2.RELEASE</version>
</parent>
<properties>
    <!--- .... -->
    <spring-security-oauth.version>2.1.0.RELEASE</spring-security-oauth.version>
    <!--- .... -->
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Monitor features -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
    </dependency>
    <!-- Security + OAuth2 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId>
        <version>${spring-security-oauth.version}</version>
    </dependency>
<!--- .... -->

application.properties

#other properties
security.oauth2.resource.filter-order = 3

OAuth2.java

public class OAuth2 {
@EnableAuthorizationServer
@Configuration
@ComponentScan
public static class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManagerBean;
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("trusted_client")
                .authorizedGrantTypes("password", "refresh_token")
                .scopes("read", "write");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManagerBean).userDetailsService(userDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
    }
}

@EnableResourceServer
@Configuration
@ComponentScan
public static class ResourceServer extends ResourceServerConfigurerAdapter {

    @Autowired
    private RoleHierarchy roleHierarchy;

    private SecurityExpressionHandler<FilterInvocation> webExpressionHandler() {
        DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
        defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy);
        return defaultWebSecurityExpressionHandler;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests().expressionHandler(webExpressionHandler())
                .antMatchers("/api/**").hasRole("DEVELOPER");
    }
}
}

Security.java

@EnableWebSecurity
@Configuration
@ComponentScan
public class Security extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;

@Bean
public JpaAccountDetailsService userDetailsService(AccountsRepository accountsRepository) {
    return new JpaAccountDetailsService(accountsRepository);
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Bean
public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
}
}
like image 730
countryroadscat Avatar asked Mar 15 '17 23:03

countryroadscat


2 Answers

Ok, I got it now.

@Cleto Gadelha pointed me very usefull info.

However I think release note is pretty unclear or miss some information. Beside that OAuth2 resource filter is changed from 3 to SecurityProperties.ACCESS_OVERRIDE_ORDER - 1, crucial information is that default WebSecurityConfigurerAdapter order is 100 (source).

So, before release 1.5.x OAuth2 resource server order was 3 which had higher priority then WebSecurityConfigurerAdapter.

After release 1.5.x OAuth2 resource server order is set to SecurityProperties.ACCESS_OVERRIDE_ORDER - 1 (it is Integer.MAX_VALUE - 8 I think) which has now definitely lower priority then basic WebSecurityConfigurerAdapter order.

That's why login page appears for me after migrate from 1.4.x to 1.5.x

So, more elegant and java-like style solution is to set @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) on WebSecurityConfigurerAdapter class

like image 114
countryroadscat Avatar answered Sep 21 '22 13:09

countryroadscat


The answer for your first and second question is at Spring Boot 1.5 Release Notes:

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

The /login page is just a path that spring redirects unauthorized users. Since you are not using a Custom Login Form and your Oauth2 filter was in a wrong position, probably was using a Basic Auth.

like image 25
Cleto Gadelha Avatar answered Sep 20 '22 13:09

Cleto Gadelha