Search code examples
springsecurityspring-securitykeycloakkeycloak-services

Spring Boot & Keycloak - only working for get method


The following is working fine:

@GetMapping(path = "/onlyforAdmins")
    @Secured("ROLE_ADMIN")
    public ResponseEntity<?> secureHello(Principal principal)  {
        return new ResponseEntity<String>("hello " + principal.getName(), HttpStatus.OK);
    }

However, I am always getting 403 when I try the following:

@RequestMapping(path = "/setupCase", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method=RequestMethod.POST)
    @Secured("ROLE_ADMIN")
    public MyCase setupCase(@RequestParam(required = false) String loggedInUser) throws Exception {

When I switch the method to method=RequestMethod.GET, everything works fine.

I have the following configuration:

import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer.AuthorizedUrl;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;

@ConditionalOnClass(
    name = {"org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter"}
)
@ConditionalOnProperty(
    value = {"keycloak.enabled"},
    matchIfMissing = true
)
@EnableWebSecurity
@EnableGlobalMethodSecurity(
    securedEnabled = true
)
@ComponentScan(
    basePackageClasses = {KeycloakSecurityComponents.class}
)
public class MockWebSecurityConfigurerAdapter extends KeycloakWebSecurityConfigurerAdapter {
    public MockWebSecurityConfigurerAdapter() {
    }

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


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

    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        ((AuthorizedUrl)((AuthorizedUrl)((AuthorizedUrl)((AuthorizedUrl)http.authorizeRequests().antMatchers(new String[]{"/togglz-console/*"})).hasRole("ADMIN").antMatchers(new String[]{"/swagger-ui.html"})).hasRole("ADMIN").antMatchers(new String[]{"/admin/*"})).hasRole("ADMIN").anyRequest()).permitAll();
    }

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

And the following dependencies:

    <dependency>
                <groupId>org.keycloak</groupId>
                <artifactId>keycloak-spring-boot-starter</artifactId>
                <optional>true</optional>
            </dependency>

<dependency>
                <groupId>org.keycloak.bom</groupId>
                <artifactId>keycloak-adapter-bom</artifactId>
                <version>4.1.0.Final</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

So how do I make the post method be treated the same as the get? And avoid permanent 403 even though I am logged in with the role admin.

Update

I enabled the logging and I see the following:

 o.s.security.web.csrf.CsrfFilter         : Invalid CSRF token found for http://localhost:8092/setupCase

Solution

  • The problem was related to the default spring CSRF protection.

    Post requests need to supply a CSRF token.

    Adding the following temporarily to the config, made the 403 go away:

    http.csrf().disable();