0

I'm trying to configure a Spring Boot application with Keycloak to have an endpoint that is both accessible for authenticated and unauthenticated users. For authenticated users, I want to return some extra information. Here is a simple example of what I'm trying to achieve:

@RestController
public class HelloController {

    @GetMapping("/")
    public String index(Principal principal) {
        KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal) principal;
        if (keycloakPrincipal != null) {
            return "Hello " + keycloakPrincipal.getKeycloakSecurityContext().getToken().getPreferredUsername();
        } else {
            return "Hello";
        }

    }
}

application.properties:

keycloak.securityConstraints[0].authRoles[0] = *
keycloak.securityConstraints[0].securityCollections[0].name = Hello
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /*

So far, I only got it to work for one of both cases. If I protect the endpoint using the security constraint above, the endpoint is only accessible to authenticated users. If I remove the security constraint, the endpoint is accessible for everyone, but then the principal will always be null.

Is it possible to achieve the intended behavior?

Stijn
  • 67
  • 3
  • What was your guide/tutorial or research? How do following answers help you? [How does Spring Security inject principal into Controller?](https://stackoverflow.com/questions/60751605/how-does-spring-security-inject-principal-into-controller) or [How to get Principal from a Keycloak secured Spring Boot application](https://stackoverflow.com/questions/53586558/how-to-get-principal-from-a-keycloak-secured-spring-boot-application) – hc_dev Jun 14 '22 at 17:27
  • @hc_dev I was following the [Keycloak documentation](https://www.keycloak.org/docs/latest/securing_apps/#_spring_boot_adapter) for the Spring Boot adapter and [a guide on Baeldung](https://www.baeldung.com/spring-boot-keycloak#controller). Note that I'm not using Spring Security, just the Keycloak Spring Adapter. If the endpoint is protected with a security constraint, I'm able to get the principal with the provided code. But then an unauthenticated user cannot access the page. – Stijn Jun 16 '22 at 07:52

2 Answers2

0

Have you tried something like Principal principal = SecurityContextHolder.getContext().getAuthentication();?

I believe the Principal as method parameter is only populated on secured endpoints but am unsure if it would exist in the SecurityContext. If not, you need to add a Filter to add it yourself.

grekier
  • 2,322
  • 1
  • 16
  • 23
  • I'm not using Spring Security, so the `SecurityContextHolder` is not available to me. But indeed, the user principal is only populated on secured endpoints. – Stijn Jun 30 '22 at 06:13
0

I was able to solve the problem by calling the authenticate() method on the HttpServletRequest object. This will trigger the authentication process and will populate the user principal whenever possible. From the docs:

Triggers the same authentication process as would be triggered if the request is for a resource that is protected by a security constraint.

To avoid triggering an authentication challenge, I pass in a dummy response object to the authenticate() call.

Stijn
  • 67
  • 3