Integración de keycloak con Spring Boot


En esta nueva entrada vamos a ver como realizar la integración de Keycloak con Spring Boot através de un ejemplo. Este tipo de integración es de vital importancia en arquitectura de microservicios, en el que delegas la autenticación a un tercero.

¿Qué es Keycloak?

Como nos dice su página web, keycloak es un Open Source Identity and Access Management.

Keycloak esta escrito en Java y es compatible con los protocolos SAML v2 y OpenID Connect (OIDC)/OAuth2. Además se encuentra soportado por la RedHat y se encuentra bajo licencia de Apache.

La idea detrás de Keycloak es asegurar la protección de las aplicaciones modernas facilitando la integración con las mismas.

Keycloak nos proporciona características tales como SSO, centralizar los diferentes métodos de autenticación, control sobre las identidades digitales, control y gestión de usuarios. Y además permite centrarse en el desarrollo del servicio sin tener que enfocarse en la autenticación.

A continuación veremos como integrar nuestra aplicación de Spring Boot con keycloak.

Arrancar y configurar Keycloak

La manera más rápida de arrancar keycloak es mediante su imágen docker por lo que vamos a introducir el siguiente comando:

docker run -p 8081:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=password jboss/keycloak -Dkeycloak.profile.feature.docker=enabled -b 0.0.0.0 

Una vez se ha descargado la imagen y arranca en el puerto 8081 (o el que prefieras), vamos a ir a la consola de administración mediante la siguiente url:

http://localhost:8081/auth/admin/master/console/

Pantalla Login Keycloak | Integración de keycloak con Spring Boot
Pantalla Login Keycloak

Para poder acceder, utiliza admin y password como usuario y contraseña.

En la pantalla de keycloak que veremos nos vamos a logar con admin y la contraseña password, que son con las que hemos arrancado la imagen de keycloak.

Crear un Realm

Un Realm en Keycloak se refiere a un objeto que gestion un conjunto de usuarios con sus credenciales roles y grupos.

Al arrancar keycloak nos hemos logado con el default Master realm, así que vamos a crar uno propio.

Despues de logarnos vamos a navegar hasta la parte superior izquierda y situar el ratón sobre Master, por encima de Realm Settings, y aparecerá el botón Add realm:

Añadir realm en Keycloak | Integración de keycloak con Spring Boot
Añadir realm en Keycloak

Al pulsar sobre ese botón aparecerá la pantalla para añadir un nuevo realm, vamos a crear uno nuevo que se llave SpringBootExample.

Crear nuevo realm
Crear nuevo realm

Al pulsar sobre create, un nuevo realm será creado, y las próximas operaciones que vamos a realizar se harán sobre este realm.

Crear un client

Aunque keycloak viene con algunos clientes ya creados vamos a crear uno nuevo, que llamaremos login. Para ello vamos a pulsar sobre client y add client:

Creación  de nuevo cliente en Keycloak
Creación de nuevo cliente en Keycloak

Nuestro nuevo cliente se llamará login

Url de redirección despues del Login en Keycloak | Integración de keycloak con Spring Boot
Url de redirección despues del Login en Keycloak

Una vez que hemos creado el login, además estableceros la url de redirección después del login en nuestro caso será la de nuestra aplicación Spring Boot que hemos arrancado, que se encontrará en el puerto 8082.

Crear un rol y usuario

El sistema de keycloak esta basado en un sistema de acceso basado en roles por usuario. Por lo que vamos a crear un rol y asociarselo a un usuario. Para crear un nuevo rol vamos a pulsar sobre role, y add Role.

Creación de role User
Creación de role User
Añadir rol de usuario
Añadir rol de usuario

A continuación vamos a crear un usuario al que le asociaremos los roles que hemos generado.

Creación usuario
Creación usuario

A continuación le creamos la password al usuario, será con la clave 12345.

Creación de la Password del usuario | Integración de keycloak con Spring Boot
Creación de la Password del usuario

Al crear la password del usuario tenemos la opción de dejar Temporary, en On o Off que significa que se le obligará a cambiar el usuario cuando se conecte por primera vez.

A continuación vamos a asociar los roles que hemos creado, en este caso admin y user a nuestro user1.

Asociar rol a usuario
Asociar rol a usuario
Asociar roles a un usuario | Integración de keycloak con Spring Boot
Asociar roles a un usuario

Si hemos seguido todos los pasos keycloak ha quedado configurado, para poder generar un token de autenticación.

Generar Access Token

Una vez hemos completado todo el procesos de generación de realm, clients, roles y usuarios, es el momento de generar el token, que lo haremos mediante un POST con una llamada HTTP:

'http://{IP}:{PORT}/auth/realms/{REALM_NAME}/protocol/openid-connect/token' 
{
    'client_id': 'client',
    'username': 'username',
    'password': 'password',
    'grant_type': 'password'
}

Para ello vamos a realizar el siguiente curl:

curl --example --request POST 'http://{IP}:{PORT}/auth/realms/{REALM_NAME}/protocol/openid-connect/token' 
--header 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'grant_type=password' 
--data-urlencode 'client_id=login' --data-urlencode 'username={user_name}' 
--data-urlencode 'password={user_pwd}'

A continuación realizamos un POST con nuestro ejemplo:

curl --location --request POST 'http://localhost:8081/auth/realms/SpringBootExample/protocol/openid-connect/token' --header 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'grant_type=password' --data-urlencode 'client_id=login' --data-urlencode 'username=user1' --data-urlencode 'password=12345'
{
    'client_id': 'client',
    'username': 'your_username',
    'password': 'your_password',
    'grant_type': 'password'
}

Si te es más comodo puedes usar Postman para realizar la llamada HTTPS.

Una vez realizada la petición obtendremos un access_token y un refresh_token. En el caso en el que el token se nos expire podremos realizar una invocación a la misma url pero con el refresh token en la petición:

{
    'client_id': 'client_id',
    'refresh_token': refresh_token,
    'grant_type': 'refresh_token'
}

Ejemplo Spring Boot con Keycloak para mostrar la Integración de keycloak con Spring Boot

A continuación vamos a realizar un ejemplo en el mediante el acceso con roles permitiremos que un usuario pueda acceder a una aplicación.

Configuración Maven de Spring Boot con Keycloak

Keycloak nos proporciona un starter para aprovechar la autoconfiguración añadiendolo como dependencia maven:

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

y además hay que añadir el distributionManagement de keycloak:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.keycloak.bom</groupId>
            <artifactId>keycloak-adapter-bom</artifactId>
            <version>12.0.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Configuración de la Seguridad

La dependencia que hemos añadido de Keycloak, nos va a proporcionar un WebSecurityConfigurer, a través de la clase KeycloakWebSecurityConfigurerAdapter. De todos modos, esta clase no es imprescindible ya que la autoconfiguración que nos proporciona será en un principio suficiente para establecer una autenticación. De todos modos, esta clase nos facilita el contexto de seguridad sobre escribiendo algunas clases. En nuestro ejemplo vamos a sobre escribirla para verlo mejor y poder dar autorización a nuestros endpoints mediante roles.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity( prePostEnabled = true,
        securedEnabled = true,
        jsr250Enabled = true)
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests()
                .anyRequest()
                .permitAll();
        http.csrf().disable();
    }

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

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

@EnableGlobalMethodSecurity: prePostEnable activa las anotaciones pre y post. La anotación SecuredEnable determina si la anotación @Secured estara actvia. Jsr250Enabled, nos permitirá usar la anotación @RoleAllowed.

KeycloakConfigResolver: Para cargar el Spring Boot Adapter porporcionado por Keycloak generamos este bean.

ConfigureGlobal: Se encarga de registrar el KeycloakAuthenticationProvider con el autentication manager.

Configuración de Keycloak en Spring Boot

Para poder conectarnos con el servidor de keycloak que tengamos levantado es necesario realizar la siguiente configuración en nuestro application.properties o yml que se encuentra en src/main/resources.

A continuación vamos a definir la configuración imprescindible que se necesita para que nuestra aplicación Spring Boot se conecte con Keycloak:

keycloak.auth-server-url=http://localhost:8081/auth
keycloak.realm=SpringBootExample
keycloak.resource=login
keycloak.public-client=true

Creación del controlador

A continuación crearemos el controlador de acceso a la aplicación mediante el acceso con Roles. A excepción del endpoint primero /anonymous, el cual no tendrá acceso por rol, simplemente por autenticación:

@RestController
@RequestMapping("/api/v1/access")
public class UserController {

    @RequestMapping(value = "/anonymous", method = RequestMethod.GET)
    public ResponseEntity<String> getAnonymous() {
        return ResponseEntity.ok("Hello Anonymous");
    }

    @RolesAllowed("user")
    @GetMapping(value = "/user")
    public ResponseEntity<String> getUser(@RequestHeader String Authorization) {
        return ResponseEntity.ok("Hello User");
    }

    @RolesAllowed("admin")
    @RequestMapping(value = "/admin", method = RequestMethod.GET)
    public ResponseEntity<String> getAdmin(@RequestHeader String Authorization) {
        return ResponseEntity.ok("Hello Admin");
    }

    @RolesAllowed({ "admin", "user" })
    @RequestMapping(value = "/all-user", method = RequestMethod.GET)
    public ResponseEntity<String> getAllUser(@RequestHeader String Authorization) {
        return ResponseEntity.ok("Hello All User");
    }
}

Una vez hemos terminado la configuración podemos probar nuestro servicio añadiendo el token generado en la cabecera como HTTP Header:

--header 'Authorization: bearer <ACCESS_TOKEN>'

Si tu usuario tiene acceso (Roles Allowed), podrá acceder al sistema en otro caso obtendrá un 403 de Forbidden.

Vamos a probar con unos curl, si prefieres puedes usar postman.

curl -X GET 'http://localhost:8082/api/v1/access/anonymous'
Respuesta:
Autenticación correcta, Hello Anónimo

curl -X GET 'http://localhost:8082/api/v1/access/user' --header 'Authorization: bearer <Access-token>'
Respuesta:
Rol permitido, Hello User

Conclusión

En esta entrada de Integración de keycloak con Spring Boot, hemos visto como realizar la autenticación apoyándonos en Keycloak, y la autorización basada en roles, a través de Spring Security.

La delegación de la autenticación en un sistema de Identity Access Management como Keycloak, es de vital importancia cuando se realizar una arquitectura orientada a microservicios.

Si quieres ver el ejemplo completo puedes verlo en nuestro github, pulsando aquí.

No te olvides de seguirnos en nuestras
redes sociales Facebook o Twitter!

Si necesitas más información puedes escribirnos un comentario o un correo electrónico a refactorizando.web@gmail.com y te ayudaremos encantados!


2 pensamientos sobre “Integración de keycloak con Spring Boot

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *