Limitations of Migrating from OpenMRS ID to a new SSO System

1 minute is definitely too short for a Keycloak session. Practically, what’s going to happen is that someone goes, works in Jira for a bit and is logged out of their OpenMRS Keycloak session during that time because they spent longer than a minute and they will have no active communication with the Keycloak server. (With SAML and unlike OAuth2, there’s usually no communication between the SP and IdP after the initial login, though SAML does sometimes have a mechanism for shared logout).

The more common pattern with SAML flows is to setup the flow to prompt the user to login every time. This would mean modifying the login flow for Atlassian to just not automatically sign users in. That should be achievable in Keycloak with just configuration.

We want to control usernames within the OpenMRS ID space so, for example, you are @raff across Atlassian, Talk, Add-Ons, Atlas, and any other service we connect to our SSO. The primary goals are (1) to make it easier for people to be recognized across community services and (2) to reduce the burden of supporting accounts across multiple services.

If Atlassian supports (now or later) calling our endpoint for logout, that’d be great.

I would rather be lengthening the session instead of limiting it – e.g., an hour- or day-long session by default with a “remember me” option that provides a week- or month-long session for use on personal devices. With password managers, it’s less of a nuisance, but I’d rather not bother people with unnecessary logins. If you log into Talk or JIRA on your laptop in the morning, why should we bother you with a login when you open the wiki that afternoon?

We’re asking people to write code & save lives, not do their banking or manage their medical records. :stuck_out_tongue:

Is this where we stand now?

We’ll also need to decide on a domain for SSO. I believe Atlassian tools will show names, not email addresses, in most cases, so the domain wouldn’t be seen often; however, it will forever be associated with the user’s content and not something we could change in the future. My assumption is we’d want a subdomain unobtrusive (short) and it’d be more future-proof to not be Atlassian-specific (e.g., not @atlassian.openmrs.org).

My thoughts are something like:

  • @sso.openmrs.org
  • @idp.openmrs.org
  • @is.openmrs.org (as in jayasanka@is.openmrs.org)
  • @user.openmrs.org
  • @u.openmrs.org

Given the purpose of the subdomain (solely to be used for SSO… not for email), I’m leaning toward @sso.openmrs.org or @idp.openmrs.org.

Hey Burke,

I have written a Keycloak extension, which can be found using this link: /jayasanka-sack/openmrs-keycloak-ldap/…/OpenmrsIdMapper.java.

The extension generates the NameID in the necessary format,.This is the cleanest solution I found to address the issue. Additionally, we can eliminate the interceptor, making the process even simpler. The extension will be deployed automatically during the Docker build.

Here is a screenshot of the extension in action, all you have to do is provide the domain we use for SSO.

Also, I did some theming work for fun over the weekend to make it visually appealing :grin:.

Here are some screenshots:

Lastly, I attempted to configure reCaptcha for registration. cc: @grace

I need your help with the following:

  • choose an SMTP service. Do we already use one?
  • access to a server for deploying the setup.
  • access to the current JIRA/wiki dump to test with Atlassian.

This is the whole setup: GitHub - jayasanka-sack/openmrs-keycloak-ldap (need to do a bit of cleanup).

Regarding the domain, I would also prefer @sso.openmrs.org @idp.openmrs.org and @id.openmrs.org.

@cintiadr @ibacher @raff @grace @dkayiwa @dkigen feel free to provide your inputs too.

Demo

Visit https://jayasanka.me/login and register yourself.

Where are we now?

  1. :white_check_mark: Design a solution, pick tools & technologies
  2. :white_check_mark: Create a POC
  3. :white_check_mark: Improve the POC
  4. :white_check_mark: Whitelisting and theming
  5. :arrow_forward: Deploy
  6. :construction: Test Atlassian Cloud migration with a dump
  7. :construction: Integrate with TALK
  8. :construction: Migrate data to Atlassian cloud
  9. :construction: Go Live!
1 Like

Awesome progress on this @jayasanka :clap: Amazing dedication.

Yes, MailChimp.

Ultimately, this setup should probably live on adaba (LDAP / Crowd / ID). Maybe we need a test server (I think we used to have ldap-stg, but I don’t see that any more). Note that we use Ansible for actually deploying things as much as possible, so ideally don’t manually deploy things, if possible.

Anything that can be written up as a Docker Compose stack can go in this repo: GitHub - openmrs/openmrs-contrib-ansible-docker-compose: An OpenMRS ansible role responsible for deploying all the docker-compose files required by OpenMRS infrastructure.. Ideally, anything that needs to get built (e.g. a Keycloak distro?) gets done via Bamboo from an OpenMRS repo and then we just deploy that image via Ansible. If we need something non-Docker-based though, we should talk through the options.

What do we actually need here?

This is my preference, but id.openmrs.org is already in use. Alternatively, I’d probably favor @users.openmrs.org; everything else seems kinda implementation-specific.

1 Like

Actually, we are using id.openmrs.org ports 80 & 443 for the ID website, but not the MX records. So, I believe we could use @id.openmrs.org for a SSO email address subdomain while the website is used by KeyCloak.

How configurable are these pages? Any chance we could include announcements on the SSO page (e.g., “Planned downtime for OpenMRS Talk this Friday 22:00-23:00 UTC.” or “Tickets for #OMRS30 in Jayasanka City on Mars going fast! Get yours today!”).

Atlassian tools (e.g., Confluence & JIRA) offer backup & restore functionality that generates a zipped XML file. We’ll need to be very careful before trying this, since a backup of either of these with attachments included is gong to be very big and could easily exceed available disk space. It may also strain CPU and/or memory and I wouldn’t expect the service to be available during an export.

Atlassian offers a migration assistant app for both Confluence and JIRA to avoid the need to download & upload. It looks like the default approach during migration is to use the email addresses of users (not usernames). So, we may need an extra step to translate all emails to @id.openmrs.org.

What @ibacher said. Ideally, we would add this KeyCloak setup through a PR to openmrs-contrib-ansible-docker-compose — as a replacement for files/id-stg. Then we can arrange to get that installed on a staging server. As @ibacher points out, thanks to @cintiadr’s leadership, we use infrastructure-as-code and avoid making any manual changes to our servers.

1 Like

@jayasanka let’s work together to move your work to our infrastructure, make it production ready and migrate data and services. To start with we need to have a staging environment in our infrastructure. We need to do the following:

  1. Move your openmrs-keycloak-ldap repo to e.g. github.org/openmrs/openmrs-contrib-itsm-sso
  2. Create a plan on Bamboo to build the Keycloak image with the extension and push that to our dockerhub. Use specific image versions and not latest.
  3. Move postfix Dockerfile and postfix-config under postfix dir. Create a plan on Bamboo to build the postfix image and push that to our dockerhub. Let’s base the postfix image on a lightweight image like alpine instead of ubuntu. Use a specific version and not latest. Let’s not run it as root (add USER 1001 to Dockerfile). See Why non-root containers are important for security
  4. Replace https://github.com/openmrs/openmrs-contrib-ansible-docker-compose/tree/master/files/id-stg with docker-compose from your repo. Make it use the Keycloak and Postfix docker images that we create via Bamboo.
  5. We won’t be deploying nginx via docker-compose since we have a shared instance, which can be configured via ansible at https://github.com/openmrs/openmrs-contrib-itsmresources/blob/master/ansible/host_vars/gode.openmrs.org/vars (I think we can place id-stg on gode as it seems to have enough free resources).
  6. We will use openldap from https://github.com/openmrs/openmrs-contrib-ansible-docker-compose/tree/master/files/ldap-stg instead of including it in Keycloak docker-compose. It’s not currently running so we will need to resurrect it and deploy on gode.
  7. We need to add backup service for Keycloak’s postgres (see e.g. https://github.com/openmrs/openmrs-contrib-ansible-docker-compose/blob/5e31f06063c7c0f0626aa098f4c84b3202205f2c/files/ldap/docker-compose.yml#L29C1-L42C21) We’ll need to adjust the backup service to not only tar DIRs, but call pg_dump first for proper DB backup. Does postfix store any data that we need to backup?

Once we have a staging environment up and running we need to have a migration plan in place that we will first try against the staging environment, but let’s first focus on creating the staging environment.

2 Likes

Thanks @ibacher , @burke and @raff for your input!

Keycloak themes are basically a collection of ftl files and CSS (check this). Each page can be edited easily. I’ve documented this in the theme readme file based on your suggestion.

@raff I’ll make the necessary changes and get back to you soon.

Thanks all.

1 Like

Is the message there something set in Keycloak? That’s quite cool!

1 Like

We cannot directly set messages through the Keycloak dashboard [1]; however, we do have the flexibility to manually edit each page using a custom theme. Each tfl file, as demonstrated in this [link], corresponds to a specific screen.

I have documented the process of adding an announcement in the readme file .

It would be nice if we could do it within the dashboard, I think we can achieve such things by writing a small extension in the future.

[1] : Is it possible to show a custom message on the login form? - #4 by xgp - Getting advice - Keycloak

See I had assumed you had done something with this part of the template: https://github.com/jayasanka-sack/openmrs-keycloak-ldap/blob/a98b053649d2e28768365f0cabfe160218af270c/keycloak/theme/theme/keywind/login/template.ftl#L41, but I guess not.

Ah, no that is to display messages generated depending on the context. Ex:

There’s a super easy hack to display announcements, but I personally don’t prefer using it :laughing:

That is to utilize the value of the HTML Display name field. Normally, this field is used to provide a custom HTML code for displaying a logo or other elements instead of the Display name. We can access this value in the template. I removed it and hardcoded the logo in the template. The hack is to displaying the text provided in the field as an announcement :smile:

1 Like

Speaking of Bamboo. We’ll also need to migrate from Bamboo Server to Bamboo Data Center. It looks like this will finally allow for Bamboo to use SSO as well.

It would be preferable to be able to set/change/remove an announcement without having to edit theme pages, whether it’s through this hack or if we discover a better way to allow an admin to manage the announcement through KeyCloak’s admin pages.

1 Like

Hi @raff,

I’ve made the necessary changes to the repo and moved it here: GitHub - openmrs/openmrs-contrib-itsm-id

Also I created the bamboo plan and the images are pushing to the openmrs docker hub repository

Also, I made a PR to the openmrs-contrib-ansible-docker-compose repository:

By the way, Postfix needs root privileges to run. I have gone through a couple of forums, and they mention that Postfix does not support non-root users, and I couldn’t find a workaround. Let me know what you think.

Sure, I’ll make necessary changes.

These should actually be pushed to the openmrsinfra organisation rather than openmrs.

1 Like

Thanks @jayasanka. I’ll review your changes.

It’s okay then.

Could you please include a backup for postgres DB? For backups we use this image, but the backup script needs to be modified to call pgdump instead of just backing up a directory. You will need to install pgdump in the image and then adjust the backup script to accept DB connection details. The image can then be used as for example here. Once files are in /backup on the host, they are copied over to S3 by a host cron task so you don’t need to handle that.

Do we need to backup anything else from the setup?

For Keycloak it would be good to export realm and have it automatically imported on initial startup. Please see https://github.com/OpenConceptLab/oclsso/blob/main/Dockerfile#L25-L29 for an example.

This way we don’t have to configure it manually in case we ever have to start from scratch.

Also please get rid of https://github.com/openmrs/openmrs-contrib-itsm-id/blob/9243a5388f9e21965faf6ec3d74301f37c9f8bce/keycloak/Dockerfile#L42 We will always want to generate SSL keys, which will make Keycloak happy for local access, but hide it behind nginx with proper SSL setup for public access.

@jayasanka meanwhile it’s time to write down specific steps to complete migration assuming we have new SSO up and running on staging. Do you have a migration plan in your head already? Could you please list the steps that you think we should follow to migrate users and services with the least disruption possible? We could exercise that on the staging environment.

1 Like

Hi @raff, since we store users in LDAP there’s nothing to back up from keycloak side, exporting the realm as you mentioned would be enough.

Regarding this, the DEV_MODE argument was a mistake. I will remove it. I assume you mention about line 45?

We can use this guide as a reference, apart from that we need to do an intermediate step to convert emails as mentioned here:

I’ll try to come up with a detailed one.