Securing Spring Boot Microservices with Keycloak (Identity and Access management tool)

The main problem that Keycloak solves is to provide a secure and convenient way for users to access multiple applications, without having to repeatedly enter their credentials

What is Keycloak?

It is a tool for “Identity and Access Management”, Keycloak is an open-source tool currently licensed with Apache License 2.0. It is also an upstream project for Red Hat SSO.

Keycloak Features

  1. Multiple Protocols Support : As for now Keycloak supports three different protocols, namely - OpenID Connect, OAuth 2.0 and SAML 2.0.

  2. SSO : Keycloak has full support for Single Sign-On and Single Sign-Out.

  3. Admin Console : Keycloak offers web-based GUI where you can “click out” all configurations required by your instance to work as you desire.

  4. User Identity and Accesses : Keycloak can be used as a standalone user identity and access manager by allowing us to create users database with custom roles and groups. This information can be further used to authenticate users within our application and secure parts of it based on pre-defined roles.

  5. Social Identity Providers : Additionally, Keycloak allows us to use Social Identity Providers. It has built-in support Google, Twitter, Facebook, Stack Overflow but, in the end, you have to configure all of them manually from admin panel. The full list of supported social identity providers and their configuration manual can be found in Keycloak documentation.

  6. features of keycloak


Distributions of Keycloak

  1. Server : Standalone application is downloadable from Keycloak page in form of a tar or zip archive with all scripts, docs, and assets needed to work normally. As for now, there are two main versions of this distribution: one is powered by WildFly server while the other is powered by Quarkus. It is now in preview stage so some unexpected error may occur.

  2. Docker Image : Distribution appropriate for Docker, Podman, Kubernetes, and OpenShift. There are two official docker images for Keycloak: one is held in Quay Container Registry - quay.io/keycloak/keycloak, the second one is held in Docker Hub - jboss/keycloak. You can download both of them with a simple docker pull command.

  3. Operator : Distribution for Kubernetes and OpenShift based on Operator SDK.

Hands On!

1. Download Keyclock server https://www.keycloak.org/downloads

start keycloak shell script file using dev access

Note : for windows download ZIP package

2. Start Keyclock server

unzip the package and hit the following command : sh bin/kc.sh start-dev

home page of keycloak app
admin console

3. Create Admin user

user created
user creaetd success

4. go to Administration console and login with created user

loged in with created user

5. create a realm (a component that holds user, role and role based authentications)

create a realm
realm created

6. create a client (a component that we use in our springboot app to communicate)

create a client

7. create a role

create a role

8. create a user and set username and password using credential tab

create a user and set username and password using credential tab
create a user and set username and password using credential tab - 2

9. map user and roles

map user and roles

10. add keycloak dependencies

              <dependency>
                  <groupId>org.keycloak</groupId>
                  <artifactId>keycloak-spring-boot-starter</artifactId>
              </dependency>
            
              <dependencyManagement>
                <dependencies>
                  <dependency>
                    <groupId>org.keycloak.bom</groupId>
                    <artifactId>keycloak-adapter-bom</artifactId>
                    <version>19.0.0</version>
                    <type>pom</type>
                    <scope>import</scope>
                  </dependency>
                </dependencies>
              </dependencyManagement>
              

11. add properties

                keycloak:
                  realm: demo-realm
                  auth-server-url: http://localhost:8080/auth
                  resource: keycloak-demo #client-id
                  public-client: true
                  bearer-only: true
            

12. create configuration class

              package com.javatechie.keycloak.config;

              import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
              import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
              import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
              import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
              import org.springframework.beans.factory.annotation.Autowired;
              import org.springframework.context.annotation.Bean;
              import org.springframework.context.annotation.Import;
              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.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;

              @KeycloakConfiguration
              @EnableGlobalMethodSecurity(jsr250Enabled = true) //jsr250Enabled will allow us to write @RolesAllowed()
              @Import(KeycloakSpringBootConfigResolver.class)
              public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
                  /**
                   * Registers the KeycloakAuthenticationProvider with the authentication manager.
                   */
                  @Autowired
                  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
                      KeycloakAuthenticationProvider authenticationProvider = new KeycloakAuthenticationProvider();
                      authenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
                      auth.authenticationProvider(authenticationProvider);
                  }

                  /**
                   * 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()
                              .anyRequest().permitAll();
                  }
              }
          

13. configuring role in our code

            package com.javatechie.keycloak;

            import com.javatechie.keycloak.entity.Employee;
            import com.javatechie.keycloak.service.EmployeeService;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.boot.SpringApplication;
            import org.springframework.boot.autoconfigure.SpringBootApplication;
            import org.springframework.http.ResponseEntity;
            import org.springframework.web.bind.annotation.GetMapping;
            import org.springframework.web.bind.annotation.PathVariable;
            import org.springframework.web.bind.annotation.RequestMapping;
            import org.springframework.web.bind.annotation.RestController;

            import javax.annotation.security.RolesAllowed;
            import java.util.List;

            @SpringBootApplication
            @RestController
            @RequestMapping("/employees")
            public class SpringBootKeycloakExampleApplication {

                @Autowired
                private EmployeeService service;

                //this method can be accessed by user whose role is user
                @GetMapping("/{employeeId}")
                @RolesAllowed("user")   // only user role can allow this method
                public ResponseEntity<Employee> getEmployee(@PathVariable int employeeId) {
                    return ResponseEntity.ok(service.getEmployee(employeeId));
                }

                //this method can be accessed by user whose role is admin
                @GetMapping
                @RolesAllowed("admin") // only admin role can allow this method
                public ResponseEntity<List<Employee>> findALlEmployees() {
                    return ResponseEntity.ok(service.getAllEmployees());
                }

                public static void main(String[] args) {
                    SpringApplication.run(SpringBootKeycloakExampleApplication.class, args);
                }

            }

            

14. testing our code using postman with following parameters

                Note - in postman's authorization type select OAuth 2.0
                Access Token Url : http://localhost:8080/auth/realms/demo-realm/protocol/openid-connect/token
                Client ID : keycloak-demo
                Scope : openid
                Grant Type : Password Credentials
                Username : <username>
                Password : <password>
                Access token : <access token>
            
testing our code using postman
testing our code using postman - 2
testing our code using postman - 3

source : https://www.keycloak.org/

source code : https://github.com/viveksoni100/keycloak_learning

Get in touch

Let’s work together

Reach out if you have a concept for a website or mobile app or require guidance with product design. contact me.
  info@whywhytechnova.com
  +(91) 88661 28862