En una de las plataformas de nuestro cliente, hemos incorporado Keycloak , un servidor para la gestión de identidad y acceso basado en código abierto.
Actualmente se está utilizando para securizar los servicios de la API Rest de la plataforma, invocada tanto para integradores como en las aplicaciones de movilidad.
Por defecto Keycloak crea su propia base de datos y dado que queremos utilizar los usuarios y roles de la base de datos de la plataforma del cliente, o mantenemos sincronizadas ambas bases de datos o creamos un conector en Keycloak para acceder a la base de datos de la plataforma. Inicialmente utilizamos la primera solución y manteníamos sincronizados ambos sistemas utilizando la Java API SDK de Keycloak pero posteriormente implementamos una extensión utilizando User Storage SPI.
Antes de explicar cómo realizar la extensión, veremos unos ejemplos de cómo utilizar la librería keycloak-server-spi. para la gestión de los roles del realm, cliente y usuario.
Gestionando el Usuario
Vamos a ver los roles de un usuario concretos, los cuales se vinculan al mapear con el realm y/o los clientes.
Ver los roles asignados al usuario de todos los roles de clientes
// > Users > User > Role Mapping > Client Roles > Client > Assigned Roles // We see all assigned roles from all Client Roles LOGGER.info(">>> UserAdaptor.getRoleMappings"); try { Set<RoleModel> roles = userAdapter.getRoleMappings(); Iterator<RoleModel> iterator = roles.iterator(); if (iterator != null) { while (iterator.hasNext()) { RoleModel roleModel = (RoleModel) iterator.next(); LOGGER.info("RoleModel [ containerId = " + roleModel.getContainerId() + ", id = " + roleModel.getId() + ", name = " + roleModel.getName() + " ]"); } } } catch (Exception e) {}
Ver los roles asignados al usuario de todos los roles de realm
// > Users > User > Role Mapping > Realm Roles > Assigned Roles LOGGER.info(">>> UserAdaptor.getRealmRoleMappings"); try { Set<RoleModel> roles = userAdapter.getRealmRoleMappings(); Iterator<RoleModel> iterator = roles.iterator(); if (iterator != null) { while (iterator.hasNext()) { RoleModel roleModel = (RoleModel) iterator.next(); LOGGER.info("RoleModel [ containerId = " + roleModel.getContainerId() + ", id = " + roleModel.getId() + ", name = " + roleModel.getName() + " ]"); } } } catch (Exception e) {}
Ver los roles de un cliente mapeado al usuario
LOGGER.info(">>> UserAdaptor.getClientRoleMappings"); try { ClientModel clientModel = realm.getClientByClientId("service-subscriber-api"); Set<RoleModel> roles = userAdapter.getClientRoleMappings(clientModel); Iterator<RoleModel> iterator = roles.iterator(); if (iterator != null) { while (iterator.hasNext()) { RoleModel roleModel = (RoleModel) iterator.next(); LOGGER.info("RoleModel [ containerId = " + roleModel.getContainerId() + ", id = " + roleModel.getId() + ", name = " + roleModel.getName() + " ]"); } } } catch (Exception e) {}
Gestionando el Realm
Para añadir roles al realm
// Users > User > Role Mappings // Realm Roles / Available Roles try { realm.addDefaultRole("AddDefaultRoleToRealm"); } catch (Exception e) {} // Realm Roles / Assigned Roles try { RoleModel roleModel = realm.addRole("AddRoleToRealm"); } catch (Exception e) {} try { realm.updateDefaultRoles("UpdateDefaultRolesToRealm"); } catch (Exception e) {}
Para ver los roles por defecto del Realm
// > Roles > Default Roles > Realm Default Roles LOGGER.info(">>> Realm.getDefaultRoles"); try { List<String> roles = realm.getDefaultRoles(); Iterator<String> iterator = roles.iterator(); if (iterator != null) { while (iterator.hasNext()) { String rol = (String) iterator.next(); LOGGER.info("Rol [ " + rol + " ]"); } } } catch (Exception e) {}
Para ver los roles del Realm
// > Roles > Realm Roles LOGGER.info(">>> Realm.getRoles"); try { Set<RoleModel> roles = realm.getRoles(); Iterator<RoleModel> iterator = roles.iterator(); if (iterator != null) { while (iterator.hasNext()) { RoleModel roleModel = (RoleModel) iterator.next(); LOGGER.info("RolModel [ containerId = " + roleModel.getContainerId() + ", id = " + roleModel.getId() + ", name = " + roleModel.getName() + " ]"); } } } catch (Exception e) {}
Para ver los clientes del Realm
// > Clients LOGGER.info(">>> Realm.getClients"); try { List<ClientModel> clients = realm.getClients(); Iterator<ClientModel> iterator = clients.iterator(); if (iterator != null) { while (iterator.hasNext()) { ClientModel clientModel = (ClientModel) iterator.next(); LOGGER.info("ClientModel [ clientId = " + clientModel.getClientId() + ", id = " + clientModel.getId() + " ]"); } } } catch (Exception e) {}
Gestionando el Cliente
Para añadir roles al cliente
// Users > User > Role Mappings ClientModel clientModel = realm.getClientByClientId("service-subscriber-api"); // Client Roles / Available Roles try { clientModel.addDefaultRole("AddDefaultRoleToClient"); } catch (Exception e) {} try { clientModel.addRole("AddRoleToClient"); } catch (Exception e) {} // Client Roles / Assigned Roles try { clientModel.updateDefaultRoles("UpdateDefaultRolesToClient"); } catch (Exception e) {}
Para ver los roles por defecto del cliente
ClientModel clientModel = realm.getClientByClientId("service-subscriber-api"); // > Roles > Default Roles > Client Roles > service-subscriber-api > Client Default Roles LOGGER.info(">>> Client.getDefaultRoles"); try { List<String> roles = clientModel.getDefaultRoles(); Iterator<String> iterator = roles.iterator(); if (iterator != null) { while (iterator.hasNext()) { String rol = (String) iterator.next(); LOGGER.info("Rol [ " + rol + " ]"); } } } catch (Exception e) {}
Para ver los roles disponibles del cliente
// > Roles > Default Roles > Client Roles > service-subscriber-api > Available Roles LOGGER.info(">>> Client.getRoles"); try { Set<RoleModel> roles = clientModel.getRoles(); Iterator<RoleModel> iterator = roles.iterator(); if (iterator != null) { while (iterator.hasNext()) { RoleModel roleModel = (RoleModel) iterator.next(); LOGGER.info("RoleModel [ containerId = " + roleModel.getContainerId() + ", id = " + roleModel.getId() + ", name = " + roleModel.getName() + " ]"); } } } catch (Exception e) {}
Con esto ya podemos entrar a implementar la extensión del User Storage SPI de Keycloak y que ataque por JPA al datasource externo de la plataforma del cliente… Próximamente.
Excelente post, muy bien explicado, gracias por la instrucción , espero que la segunda parte sea pronto.
Gracias por tu comentario Chris. Pronto tendrás la segunda parte. Un saludo 🙂