How to integrate Platform Security with your own Identity Manager with OAuth2 or OpenID?

Feature available since version 2.2.0-hyperblast

 

It is possible to delegate the authentication processes of the Onesait Platform to an existing Identity Manager that supports Oauth2 or OpenID connect, such as Keycloak, Google IM…, here’s how.

SSO Spring Boot Plugin

There’s a plugin developed by our team that is available at the Market Place of the platform. Simply go to your platform’s Market Place, and look for the “SSO Oauth 2 - Open ID PLUGIN FOR OSP MODULES“ asset, or download the zip from here.

 

Unzip the content, and open the project with an IDE.

Configuration Properties

First of all, you’ll need to configure the properties for the plugin. Go to src/main/resources and open sso_extras.properties. There are some endpoints and parameters to configure there:

Client Id and Client Secret of your IM.

Endpoints:

Oauth 2 - Open ID:

  • Authorization URI

  • Access token URI

  • Check token - Introspection URI

Pre established redirect URI and use current URI: these variables are used to force Oauth flow redirection to a specific URI. This avoid redirection problems when controlpanel is behind a reverse proxy, and the default redirect URI is mounted with http:// instead of https:// . If this happens to you, set useCurrentUri to false, and set the preEstablishedRedirectUri to something like below.

Finally, you will need to configure an ADMINISTRATOR API Key for user management purposes (i.e. when a user first logs in the platform, user will be imported into our database) You can find the administrator token by login with an user ‘administrator’ and going to /controlpanel/apimanager/token/list:

 

oauth2.client.clientId = hnrole oauth2.client.clientSecret = hnrole oauth2.client.accessTokenUri = http://weblogic.proyvalhnwl1.indra.es/auth/realms/hnrole/protocol/openid-connect/token oauth2.client.userAuthorizationUri = http://weblogic.proyvalhnwl1.indra.es/auth/realms/hnrole/protocol/openid-connect/auth oauth2.client.checkTokenEndpointUrl = http://weblogic.proyvalhnwl1.indra.es/auth/realms/hnrole/protocol/openid-connect/token/introspect oauth2.resource.userInfoUri = http://weblogic.proyvalhnwl1.indra.es/auth/realms/hnrole/protocol/openid-connect/userinfo oauth2.client.useCurrentUri: true oauth2.client.preEstablishedRedirectUri: https://development.onesaitplatform.com/controlpanel/login cache.eviction.time= 6000000 api-key = 2dd49e34e0524434ac760da212fb2a27

Alternatively, configuration properties can be provided via external file. For this to work, you need to set the environment variable PLUGIN_PROPERTIES to the file route, for example:

PLUGIN_PROPERTIES → /configuration/im/plugin.properties

Java Model and Mappers

There are several classes that you may adapt to fit your needs.

Model

First of all, the Java model is defined in the class “UserClaims.java” and its adapted to the OpenID standard, but you may need some other attributes. Feel free to adapt this class.

public class UserClaims { public String sub; @JsonProperty("practitioner_id") public String practitionerId; public List<Role> roles; public String name; @JsonProperty("preferred_username") public String preferredUsername; @JsonProperty("given_name") public String givenName; @JsonProperty("family_name") public String familyName; public String email; }

 

Authorities Extractor

To map your IM role to a onesait Platform ROLE, there is a class which manages this mapping: KeycloakAuthoritiesExtractor.java

By default, all imported users will be mapped to ROLE_USER, but you can change this behavior.

You can read any attribute retrieved by the Open ID user info endpoint (f.e. “role”) via the Map<String, Object> mapand then assign a role according to that attribute.

public class KeycloakAuthoritiesExtractor implements AuthoritiesExtractor { private static final String DEFAULT_ROLE = "ROLE_USER"; private static final String DEFAULT_ROLE_ADMIN = "ROLE_ADMINISTRATOR"; @Override public List<GrantedAuthority> extractAuthorities(Map<String, Object> map) { return AuthorityUtils.createAuthorityList(DEFAULT_ROLE); } public String extractRole(Map<String, Object> map) { return DEFAULT_ROLE; } }

 

Principal Extractor

You also need to provide an implementation of a Principal extractor to retrieve the principal’s name (i.e. the user’s unique ID). The default implementation can be found in the KeycloakPrincipalExtractor.java, and as you can see below, it is extracted from the “preferred_username” attribute.

public class KeycloakPrincipalExtractor implements PrincipalExtractor { private static final String USERNAME = "preferred_username"; public Object extractPrincipal(Map<String, Object> map) { return map.get(USERNAME); } }

 

OSP User entity mapping

Finally, there’s a @Component class “ClaimsExtractor.java”, which implements the logic to transform an OpenID profile to a OSP User entity. You may only need to adapt this component too if you changed the Java Model, to provide the following Java attributed correctly: fullName, username (userId), mail.

@Component public class ClaimsExtractor { private static final String MAIL_SUFFIX = "@keycloak.com"; private final KeycloakAuthoritiesExtractor authoritiesExtractor = new KeycloakAuthoritiesExtractor(); private static final ObjectMapper mapper = new ObjectMapper(); public User mapFromClaims(Map<String, Object> map) throws JsonProcessingException { final UserClaims claims = mapper.convertValue(map, UserClaims.class); final User user = new User(); user.setFullName(claims.getName()); user.setUsername(claims.getPreferredUsername()); user.setMail(StringUtils.isEmpty(claims.getEmail()) ? claims.getPreferredUsername() + MAIL_SUFFIX : claims.getEmail()); user.setExtraFields(mapper.writeValueAsString(claims)); user.setPassword(randomPassword()); user.setRole(authoritiesExtractor.extractRole(map)); return user; } private String randomPassword() { return RandomStringUtils.randomAlphabetic(1).toUpperCase() + UUID.randomUUID().toString().substring(0, 10) + "$"; } }

 

Compiling the JAR

Next step is to compile the JAR with maven.

Just run mvn clean install

 

Deploying the plugin to the onesait Platform

Via HTTP URL

Uploading the JAR to a nexus/git

If you use this method to deploy the plugin, you will need to upload the JAR to an accesible URI, in order for the OSP to download the plugin at startup.

In this example, we have uploaded the plugin to our nexus.

https://nexus.onesaitplatform.com/nexus/content/repositories/releases/com/minsait/onesait/platform/plugin-security-healthcare/1.0.0/plugin-security-healthcare-1.0.0.jar

As the last step to enable the plugin, you’ll need to upgrade the following services (if apply) in the CaaS (Rancher or Openshift) with the appropiate environment variables:

ControlPanel:

  • PLUGIN_URI: {plugin-uri}

  • OAUTH_SSO_ENABLED : true

API Manager:

  • PLUGIN_URI: {plugin-uri}

BPM Engine:

  • PLUGIN_URI: {plugin-uri}

Dashboard Engine:

  • PLUGIN_URI: {plugin-uri}

Monitoring UI:

  • PLUGIN_URI: {plugin-uri}

Rules Engine:

  • PLUGIN_URI: {plugin-uri}

Report Engine:

  • PLUGIN_URI: {plugin-uri}

 

Via docker volume

Alternatively, you can upload the JAR to a VM directory instead. Copy the JAR to a VM’s directory via SCP or WinSCP.

In this example, we will leave the JAR at path /oradata/onesaitplatform/plugin-security-healthcare-1.0.0.jar

Now you’ll need to map the plugin with a docker volumen. Go to Rancher, select service and click on ‘upgrade’.

In the ‘volumes’ section, add the following volume:

/oradata/onesaitplatform/plugin-security-healthcare-1.0.0.jar:/application/BOOT-INF/lib/plugin-security-healthcare-1.0.0.jar:rw

NOTE: Remember that the path in bold may change between VMs.

Repeat this process in the following services if needed:

ControlPanel

API Manager

BPM Engine

Dashboard Engine

Monitoring UI

Rules Engine

Report Engine

 

Also remember to add environment variable OAUTH_SSO_ENABLED : true in controlpanelservice when upgrading it:

 

Support

If you need any support for this feature, please contact support@onesaitplatform.com