0

I have created a Springboot application with Keycloak by following this tutorial Baeldung When I try to enter /api/foos it always returns 403 without any error messages.

// SecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
class SecurityConfig(
    private val unauthorizedHandler: JwtAuthenticationEntryPoint
) : WebSecurityConfigurerAdapter() {
    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        http
            .cors()
            .and()
            .csrf()
            .disable()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(unauthorizedHandler)
            .and()
            .authorizeRequests()
            .antMatchers(HttpMethod.GET, "/user/info", "/api/foos/**", "/api/foos")
            .hasAnyRole("free_user")
            .antMatchers(HttpMethod.POST, "/api/foos")
            .hasAnyRole("free_user")
            .anyRequest()
            .authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt()
    }
}


// Controller
@RestController
@RequestMapping(value = ["/api/foos"])
class SecurityTestController() {

    @GetMapping(value = ["/{id}"])
    fun findOne(@PathVariable id: Long?): String {
        return "fineOne with id $id"
    }

    @GetMapping
    fun findAll(): Message {
        return Message("findAll")
    }
}


// application.properties
# Resource server config
rest.security.issuer-uri=http://localhost:8081/auth/realms/dev
spring.security.oauth2.resourceserver.jwt.issuer-uri=${rest.security.issuer-uri}
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=${rest.security.issuer-uri}/protocol/openid-connect/certs


// build.gradle (app)
plugins {
     id("org.springframework.boot")
}
dependencies {
    implementation("org.springframework.boot:spring-boot-starter- oauth2-resource-server")
    implementation("org.springframework.boot:spring-boot-starter-security")
    testImplementation("org.springframework.security:spring-security-test")
}

Here is my user on Keycloak enter image description here

Postman result: enter image description here

What I have already tried

  1. disable csrf - Not working
  2. Comment SecurityConfig class - Working without security
Kanzt
  • 135
  • 1
  • 6
  • 13

2 Answers2

0

It looks like "free_user" is a client role.

Two solutions :

Either remove the current "free_user" client role, create a "free_user" realm role in the global Roles tab, and assign it to your user.

Or, add the property keycloak.use-resource-role-mappings=true to your Spring boot configuration to allow spring security to map your current client role.

Lucas Declercq
  • 1,534
  • 11
  • 17
  • It's still not working. Do I need to add more dependencies? I have added my build.gradle(app) to my post. – Kanzt Sep 19 '21 at 03:29
0

I found the answer here LINK

We need to create a custom mapping between Spring security and Keycloak roles.

public class KeycloakRealmRoleConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
@Override
public Collection<GrantedAuthority> convert(Jwt jwt) {
    final Map<String, Object> realmAccess = (Map<String, Object>) jwt.getClaims().get("realm_access");
    return ((List<String>)realmAccess.get("roles")).stream()
            .map(roleName -> "ROLE_" + roleName) // prefix to map to a Spring Security "role"
            .map(SimpleGrantedAuthority::new)
            .collect(Collectors.toList());
    }
}
Kanzt
  • 135
  • 1
  • 6
  • 13