In the first part we setup a local Keycloak instance. In this blog we will see how we can leverage Keycloak to secure our frontend. For this purpose we will create a small Spring Boot application that will serve a webpage. The next and last blog will show how authentication can be used between services.

Architecture overview

As mentioned we will create a small Spring Boot microservice and secure it using Spring Security and Keycloak. The service that we will create in this blog is the "frontend" Spring Service. It serves a simple web page that displays a hello message including the users email adres as registered in Keycloak. The next blog we will build the service and propagate the authorization from to frontend to service we cal. This way we build a complete Single Sign-On solution.

Keycloak context diagram

The Frontend service

Create a project

We start by creating a new Spring project using cURL.

curl -s start.spring.io/starter.tgz \
  -d type=gradle-project \
  -d groupId=net.vanweenen.keycloak \
  -d artifactId=frontend \
  -d language=java \
  -d dependencies=web,thymeleaf,keycloak,security \
  -d baseDir=keycloak-frontend | tar -xzvf -

keycloak dependency

By using the above project generation we have automatically added the Keycloak and Spring Security dependencies. You can look them up in the build.gradle  file. However for the purpose of this blog we will be using Keycloak 4.4.0 that was released on 6 September 2018.

ext {
	keycloakVersion = '4.4.0.Final'
}

Property Configuration

Next we need to configure where the Keycloak instance we started is located and what realm and client we use. Also we configure our frontend to run on port 8081 because Keycloak itself is already running on 8080. In the first blog we configured http://localhost:8081  as a valid redirect url in the login-app client. We can’t use the Keycloak login page from any other location. Lastly we enable the logging for Keycloak so we can see what it happens internally.

server.port=8081

keycloak.auth-server-url=http://localhost:8080/auth
keycloak.realm=springservice
keycloak.resource=login-app
keycloak.public-client=true

logging.level.org.keycloak=TRACE

Java configuration

After configuring the the Keycloak adapter we need to configure Spring Security to use the adapter. We also need to configure our security rules. To do that create a SecurityConfig  class. In here we configure Spring security to use Keycloak. This is done by setting the authenticationProvider  on the  AuthenticationManagerBuilder . For public or confidential applications we need to use a session authentication strategy applications so we can redirect to Keycloak. For bearer-only applications (typically api backend services) we provide a NullAuthenticatedSessionStrategy. Next we configure our websecurity to authorize requests to the /greetings endpoint for any user with the USER  role. Spring Security prefixes the role name with ROLE_ . That is the reason we created the ROLE_USER  role when configured Keycloak in part 1. Lastly we make our Keycloak Adapter Spring Boot aware. This way it won’t look for a keycloak.json configuration file but uses the adapter configuration.

@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
    /**
     * Registers the KeycloakAuthenticationProvider with the authentication manager.
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(keycloakAuthenticationProvider());
    }

    /**
     * Defines the session authentication strategy.
     */
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        super.configure(http);
        http
                .authorizeRequests()
                .antMatchers("/greetings*").hasRole("USER")
                .anyRequest().denyAll();
    }

    // Spring boot integration
    @Bean
    public KeycloakConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }
}

Avoid double Filter bean registration

Spring Boot attempts to eagerly register filter beans with the web application context. Therefore, when running the Keycloak Spring Security adapter in a Spring Boot environment, it may be necessary to add `FilterRegistrationBean`s to your security configuration to prevent the Keycloak filters from being registered twice.

@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
    ...

    @Bean
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            KeycloakAuthenticationProcessingFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            KeycloakPreAuthActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean(
            KeycloakAuthenticatedActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakSecurityContextRequestFilterBean(
            KeycloakSecurityContextRequestFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }
    ...
}

The web page

We configured that users with the USER role should be allowed to access the /greetings  endpoint. So now we need to provide a simpel page. Create a GreetingController that provides a GetMapping. Let Spring inject a Model and an Authentication. In the model we can put information needed to render the page. The Authentication can be used to get user information.

@Validated
@Controller
public class GreetingController {

    @GetMapping("/greetings")
    public String greeting(@NotNull Model model, @NotNull Authentication auth) {
        String email = ((SimpleKeycloakAccount) auth.getDetails())
                .getKeycloakSecurityContext()
                .getToken()
                .getEmail();

        model.addAttribute("name", email);
        return "greetings";
    }

}

This controller will add the email adres of the user to the model under the "name" attribute and render the page. The page is defined in the resources/templates  folder and takes the name of the return value. In this case it will be greetings.html. It contains the following contents:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
    <h1 th:text="'Hello, world! from ' + ${name}"/>
</body>
</html>

Visiting the site

Finally we can see that our page is successfully secured by http://localhost:8081/greetings. We should be redirected to the Keycloak Login page. Login with the following credentials that we used in part 1:

Username: user1
Password: ooR9ooha

Keycloak loginpage

If the login was successful then we are redirected back to frontend which should now display our page:

Greetings page

Accessing protected API’s protected by Keycloak

Next blog we will see how we can secure our backend API services with Keycloak and use the login token to access a service.

shadow-left