Spring Security применяет фильтр HttpSecurity перед созданием участника-пользователя

#spring-boot #spring-security #keycloak

#spring-boot #spring-безопасность #keycloak

Вопрос:

У меня есть приложение springboot, которое использует Keycloak для обработки аутентификации JWT. Если я использую @PreAuthorize в своем методе контроллера, все работает, как ожидалось, но HttpSecurity, основанный на шаблоне URL antMatcher, не является. Из того, что я могу сказать, Spring применяет фильтр безопасности ПЕРЕД созданием пользователя-участника. В журналах я вижу, что он тестируется на анонимность, даже если был передан действительный токен-носитель, и я могу видеть AuthenticationPrincipal внутри метода контроллера.

По сути, HttpSecurity выполняет свои правила против анонимных, хотя позже создается действительный участник, который может использоваться проверками @PreAuthorize.

 @Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
    @Autowired
    public void configureGlobal(
            AuthenticationManagerBuilder auth) throws Exception {

        KeycloakAuthenticationProvider keycloakAuthenticationProvider
                = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
                new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    public KeycloakConfigResolver KeycloakConfigResolver() {
        return new KeycloakConfigResolver() {
            @Override
            public KeycloakDeployment resolve(HttpFacade.Request request) {
                KeycloakDeployment deployment = null;
                AdapterConfig adapterConfig = new AdapterConfig();
                adapterConfig.setAuthServerUrl(System.getProperty("keycloak.auth-server-url"));
                adapterConfig.setRealm(System.getProperty("keycloak.realm"));
                adapterConfig.setResource(System.getProperty("keycloak.resource"));
//                adapterConfig.setUseResourceRoleMappings(true);
                adapterConfig.setSslRequired("external");
                adapterConfig.setPublicClient(true);
                deployment = KeycloakDeploymentBuilder.build(adapterConfig);
                return deployment;
            }
        };
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(
                new SessionRegistryImpl());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues())
            .and().csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/public/*").permitAll()
                .antMatchers("/api/admin/*").hasRole("admin")
                .antMatchers("/api/*").authenticated()
        ;
    }
}
 

Журналы безопасности Spring выглядят следующим образом

 2020-11-28 10:00:45.659 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/condition at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-11-28 10:00:45.659 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/condition at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-11-28 10:00:45.660 DEBUG 25655 --- [nio-8180-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2020-11-28 10:00:45.660 DEBUG 25655 --- [nio-8180-exec-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2020-11-28 10:00:45.662 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/medical-condition at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-11-28 10:00:45.663 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/medical-condition at position 4 of 11 in additional filter chain; firing Filter: 'CorsFilter'
2020-11-28 10:00:45.664 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/medical-condition at position 5 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2020-11-28 10:00:45.664 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', GET]
2020-11-28 10:00:45.664 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'POST /api/admin/condition' doesn't match 'GET /logout'
2020-11-28 10:00:45.664 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', POST]
2020-11-28 10:00:45.664 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/admin/condition'; against '/logout'
2020-11-28 10:00:45.664 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', PUT]
2020-11-28 10:00:45.664 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'POST /api/admin/condition' doesn't match 'PUT /logout'
2020-11-28 10:00:45.664 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', DELETE]
2020-11-28 10:00:45.665 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'POST /api/admin/condition' doesn't match 'DELETE /logout'
2020-11-28 10:00:45.665 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
2020-11-28 10:00:45.665 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/condition at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-11-28 10:00:45.665 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.s.HttpSessionRequestCache        : saved request doesn't match
2020-11-28 10:00:45.665 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/condition at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-11-28 10:00:45.666 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/condition at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-11-28 10:00:45.667 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@2aa3a4a: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2020-11-28 10:00:45.667 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/medical-condition at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-11-28 10:00:45.668 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.session.SessionManagementFilter  : Requested session ID 8C6524CDA3CD92F69B885542B2E5DF1C is invalid.
2020-11-28 10:00:45.668 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/condition at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-11-28 10:00:45.668 DEBUG 25655 --- [nio-8180-exec-1] o.s.security.web.FilterChainProxy        : /api/admin/condition at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-11-28 10:00:45.669 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/admin/condition'; against '/api/public/*'
2020-11-28 10:00:45.669 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/admin/condition'; against '/api/admin/*'
2020-11-28 10:00:45.669 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /api/admin/condition; Attributes: [hasRole('ROLE_admin')]
2020-11-28 10:00:45.669 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@2aa3a4a: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2020-11-28 10:00:45.673 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@4e7d07d7, returned: -1
2020-11-28 10:00:45.679 DEBUG 25655 --- [nio-8180-exec-1] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is anonymous); redirecting to authentication entry point
 

Ответ №1:

Прежде чем настраивать свою собственную конкретную конфигурацию, вам необходимо вызвать Keycloak-configuration

 @Override
protected void configure(HttpSecurity http) throws Exception {
      super.configure(http); // <----
      http.... // 
}
 

Ответ №2:

Метод configure должен вызываться первым, и лучшим вариантом user principal было бы добавить перехватчик, а не фильтры .. и, пожалуйста, добавьте super.configure(http); Спасибо!