Securing the root URL in Spring Boot

Viewed 862

I'm trying to secure a Spring Boot application using Keycloak and configuring it via Java instead of XML. My SecurityConfig class looks like this:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class,
        excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.keycloak.adapters.springsecurity.management.HttpSessionManager"))
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests()
                .anyRequest().hasRole("admin");
    }
}

In my understanding, the call to anyRequest should ensure that all requests are redirected to the KeyCloak login page if the user is not currently logged in. However, this only seems to work for URLs that are not the root URL. The project currently has two endpoints, "/" "/sync". Trying to access the sync-endpoint properly redirects to the login page. Trying to access the root page does not, so it seems to be ignored. I've also tried using antMatchers("*", "**", "/", "/*", "/**").hasRole("admin"), but none of those patterns seem to cause the root URL to be secured.

The culprit seems to be the call to super.configure(http). However, this executes some relatively important things, like CSRF protection, login/out endpoints etc. Here's the equivalent code extracted into the method, instead of the super-call:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().requireCsrfProtectionMatcher(this.keycloakCsrfRequestMatcher())
                .and().sessionManagement().sessionAuthenticationStrategy(this.sessionAuthenticationStrategy())
                .and().addFilterBefore(this.keycloakPreAuthActionsFilter(), LogoutFilter.class)
                .addFilterBefore(this.keycloakAuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
                .addFilterBefore(this.keycloakAuthenticatedActionsFilter(), BasicAuthenticationFilter.class)
                .addFilterAfter(this.keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
                .exceptionHandling().authenticationEntryPoint(this.authenticationEntryPoint())
                .and().logout().addLogoutHandler(this.keycloakLogoutHandler()).logoutUrl("/sso/logout").permitAll().logoutSuccessUrl("/");

        http.authorizeRequests()
                .anyRequest().hasRole("admin");
    }

Reversing the order between the super-call and my own authorization code has also not resulted in ther root URL being protected.

2 Answers

By default logoutSuccessUrl is "/", so is unsecured, in order to secure "/" you need to change it.

.and().logout().logoutSuccessUrl("/logout-success")

I also recommend you to use keycloak-spring-boot-starter

I just had same issue, you need to change logoutSuccessUrl to something else than "/" which you want to protect.

.and().logout().addLogoutHandler(this.keycloakLogoutHandler()).logoutUrl("/sso/logout").permitAll().logoutSuccessUrl("/");

to

.and().logout().addLogoutHandler(this.keycloakLogoutHandler()).logoutUrl("/sso/logout").permitAll().logoutSuccessUrl("/somethingelse");
Related