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> map
and 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.
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