SpringBoot 1.5.x + Безопасность + OAuth2
У меня есть Spring Boot REST API с защитой OAuth2.
Сегодня я обновил мою версию spring-boot-starter-parent
от 1.4.2
до 1.5.2
.
Изменения полностью смутили меня.
Раньше я мог тестировать свой REST API с Postman. Когда мой токен доступа был неправильным или у меня не было прав на определенные ресурсы, ответ сервера был следующим:
{
"error": "access_denied",
"error_description": "Access is denied"
}
Теперь он перенаправляет меня на страницу /login
... Когда я вхожу в систему - он показывает мой ресурс без аутентификации OAuth2...
Я попытался отключить его, и я нашел это волшебное свойство:
security.oauth2.resource.filter-order = 3
Эта строка отключена, перенаправляется на страницу входа.
Однако мои вопросы:
- что произошло между этими 2 релизами с точки зрения безопасности?
- эта "странная" строка является единственным допустимым исправлением?
- Какова цель этой страницы входа и какая она используется (я проверил запросы и ответы в Google Chrome, и я не вижу никаких токенов доступа и файлов oauth2, поэтому он использует только репозиторий пользователя?)
Некоторые более важные части моего кода:
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();
}
}
Ответы
Ответ 1
Хорошо, я понял это сейчас.
@Клето Гадельха указал мне очень полезную информацию.
Тем не менее, я думаю, что примечание к выпуску довольно неясное или отсутствует какая-либо информация Помимо того, что фильтр ресурсов OAuth2 изменен с 3 на SecurityProperties.ACCESS_OVERRIDE_ORDER - 1
, важной информацией является то, что порядок WebSecurityConfigurerAdapter
умолчанию WebSecurityConfigurerAdapter
100 (источник).
Итак, до выпуска 1.5.x порядок сервера ресурсов OAuth2 был 3, который имел более высокий приоритет, чем WebSecurityConfigurerAdapter
.
После выпуска 1.5.x порядок сервера ресурсов OAuth2 устанавливается равным SecurityProperties.ACCESS_OVERRIDE_ORDER - 1
(я думаю, это Integer.MAX_VALUE - 8
), который теперь определенно имеет более низкий приоритет, чем базовый порядок WebSecurityConfigurerAdapter
.
Поэтому после входа с 1.4.x в 1.5.x у меня появляется страница входа.
Итак, более элегантное решение в стиле java - установить @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
в классе WebSecurityConfigurerAdapter
Ответ 2
Ответ на ваш первый и второй вопрос: Spring Примечания к выпуску версии 1.5:
Фильтр ресурсов OAuth 2
Порядок по умолчанию для фильтра ресурсов OAuth2 изменился с 3 на SecurityProperties.ACCESS_OVERRIDE_ORDER - 1. Это помещает его после конечных точек исполнительного механизма, но до основной цепи фильтра аутентификации. Значение по умолчанию можно восстановить, установив security.oauth2.resource.filter-order = 3
Страница/login - это только путь, по которому spring перенаправляет неавторизованных пользователей. Поскольку вы не используете пользовательскую форму входа в систему, а ваш фильтр Oauth2 находился в неправильном положении, возможно, использовал Basic Auth.
Ответ 3
Это может быть связано с неправильной настройкой сервера ресурсов.
@Override
public void configure(final HttpSecurity http) throws Exception {
// @formatter:off
http.csrf().disable().authorizeRequests()
// This is needed to enable swagger-ui interface.
.antMatchers("/swagger-ui.html","/swagger-resources/**","/webjars/**", "/v2/api-docs/**").permitAll()
.antMatchers("/api/v1/**").hasRole("TRUSTED_CLIENT")
.antMatchers("/api/v1/**").hasRole("USER")
.antMatchers("/api/v1/**").hasAuthority("ROLE_TRUSTED_CLIENT");
// @formatter:on
}