Проблема безопасности с конечной точкой в ​​Spring Boot Security - PullRequest
0 голосов
/ 20 января 2020

Мы создаем в Spring загрузочный API отдыха, который должен взаимодействовать с веб-сайтом. Веб-сайт должен быть единственным потребителем наших конечных точек. Для этого Веб-сайт должен аутентифицировать себя через clientId & clientSecret при каждом запросе.

Это наш AuthorizationServerConfig:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {

        configurer.inMemory().withClient("myClientId").secret(passwordEncoder.encode("test123"))
                .accessTokenValiditySeconds(600)
                .refreshTokenValiditySeconds(2592000)
                .authorizedGrantTypes(authorizedGrantTypes).scopes("read", "write").resourceIds("users");
    }

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

А это WebSecurityConfig

@Order(1)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    public void configure(WebSecurity web) throws Exception {
        web.debug(true);
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.cors()
            .and().csrf().disable().authorizeRequests()
            .antMatchers(HttpMethod.POST, "/users/pre-register").authenticated()
            .and().authorizeRequests()
            .antMatchers(HttpMethod.POST, "/oauth/token").authenticated()
            .and().authorizeRequests().anyRequest().authenticated()
            .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

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

    @Bean
    public BCryptPasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }
}

У нас есть 2 конечные точки / пользователи / предварительная регистрация и / oauth / токен

Для вызова конечной точки / пользователи / предварительная регистрация необходимы только правильный clientId и clientSecret. Для вызова конечной точки / oauth / token необходимы правильный clientId и clientSecret и уже зарегистрированный пользователь + пароль.

Конечная точка / oauth / token работает как задумано. Если вы предоставите правильные учетные данные, вы получите токен в ответ.

Если вы отправите ложный clientSecret, вы получите эту ошибку.

<!doctype html>
<html lang="en">
<head>
    <title>HTTP Status 401 – Unauthorized</title>
</head>
<body>
    <h1>HTTP Status 401 – Unauthorized</h1>
    <hr class="line" />
    <p><b>Type</b> Status Report</p>
    <p><b>Message</b> Unauthorized</p>
    <p><b>Description</b> The request has not been applied because it lacks valid authentication credentials for the
        target resource.</p>
    <hr class="line" />
    <h3>Apache Tomcat/9.0.14</h3>
</body>
</html>

Если вы отправите ложный пароль для зарегистрированного пользователя Вы получаете эту ошибку.

{
  "error": "invalid_grant",
  "error_description": "Bad credentials"
}

Таким образом, кажется, что все в порядке с Endpoint /oauth/token.

Конечная точка / users / pre-register с другой стороны не работает должным образом .

Это мой запрос:

POST /users/pre-register HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Authorization: Basic bXlDbGllbnRJZDp0ZXN0MTIz

{
    "email":"harryHirsch@myCompany.de",
    "password":"Test1234"
}

Это ошибка, которую я получаю:

<html lang="en">
    <head>
        <title>HTTP Status 403 – Forbidden</title>
    </head>

    <body>
        <h1>HTTP Status 403 – Forbidden</h1>
        <hr class="line" />
        <p><b>Type</b> Status Report</p>
        <p><b>Message</b> Access Denied</p>
        <p><b>Description</b> The server understood the request but refuses to authorize it.</p>
        <hr class="line" />
        <h3>Apache Tomcat/9.0.14</h3>
    </body>
</html>

Thid ошибка, которую я вижу в моих лог-файлах:

[2020-01-20T15:43:40.040Z] [org.springframework.security.web.FilterChainProxy$VirtualFilterChain] [http-nio-8080-exec-2] [328] [DEBUG] /users/pre-register at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
[2020-01-20T15:43:40.040Z] [org.springframework.security.web.FilterChainProxy$VirtualFilterChain] [http-nio-8080-exec-2] [328] [DEBUG] /users/pre-register at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
[2020-01-20T15:43:40.040Z] [org.springframework.security.web.util.matcher.AntPathRequestMatcher] [http-nio-8080-exec-2] [176] [DEBUG] Checking match of request : '/users/pre-register'; against '/users/pre-register'
[2020-01-20T15:43:40.040Z] [org.springframework.security.access.intercept.AbstractSecurityInterceptor] [http-nio-8080-exec-2] [219] [DEBUG] Secure object: FilterInvocation: URL: /users/pre-register; Attributes: [authenticated]
[2020-01-20T15:43:40.040Z] [org.springframework.security.access.intercept.AbstractSecurityInterceptor] [http-nio-8080-exec-2] [348] [DEBUG] Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@55041127: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
[2020-01-20T15:43:40.040Z] [org.springframework.security.access.vote.AffirmativeBased] [http-nio-8080-exec-2] [66] [DEBUG] Voter: org.springframework.security.web.access.expression.WebExpressionVoter@31411a9b, returned: -1
[2020-01-20T15:43:40.040Z] [org.springframework.security.web.access.ExceptionTranslationFilter] [http-nio-8080-exec-2] [181] [DEBUG] Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]

Я подозреваю, что моя ошибка лежит в методе configure для http моего AuthneticationManager

.
.
@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors()
        .and().csrf().disable().authorizeRequests()
        .antMatchers(HttpMethod.POST, "/users/pre-register").authenticated()
        .and().authorizeRequests()
        .antMatchers(HttpMethod.POST, "/oauth/token").authenticated()
        .and().authorizeRequests().anyRequest().authenticated()
        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
.
.

Но я не уверен в этом. Любая помощь очень ценится!

PS Кто-нибудь знает хороший сайт, где подробно описаны antMatchers и как они правильно настроены?

РЕДАКТИРОВАТЬ: Я мог бы сузить ошибку немного вниз. В конечной точке / oauth / token, которая работает как задумано, Веб-сайт, использующий наш API, должен аутентифицировать себя через clientId + clientSecret (определенный в нашем AuthorizationServerConfig). А затем проверяются учетные данные пользователя, если они имеют git. Имя пользователя и его пароль (хэшированные через bcrypt) хранятся в нашей БД.

В конечной точке / пользователи / предварительно зарегистрируйте предоставленные учетные данные из моего запроса

.
Authorization: Basic bXlDbGllbnRJZDp0ZXN0MTIz
.

, которые не проверяются сравнивая его с clientID и clientSecret, я определил в моем AuthorizationServerConfig. Но вместо этого приложение пытается проверить учетные данные путем поиска пользователя в нашей БД. Это явно неправильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...