Keycloak - Our Journey on How to Contribute to the Project

Keycloak Overview and Our Usecase

Keycloak is an open-source identity and access management solution. Some of the features that it provides out-of-the-box are the easy deployment of application authentication, single-sign on, identity brokering from various sources like social media applications, user federation by creating a facade for LDAP, Active Directory, etc., and all of this using standard protocols like SAML, OpenID Connect (OIDC), etc.

CanDIG uses Keycloak (one deployment on each site in a project), to create a uniform interface for authentication and authorization infrastructure (AAI). This helps alleviate the issue of supporting a variety of authentication tools and protocols. This uniformity allows CanDIG instances in a project to ask for authentication and authorization for an incoming request, from the appropriate site much more easily.

CanDIG uses OIDC and its related tokens to achieve authentication and authorization in a distributed manner. This is a critical use case for CanDIG. CanDIG’s AAI implementation extends OIDC by using the Global Alliance for Genomic Health (GA4GH). GA4GH defines the claims carried within the OIDC token (renamed Passport in the GA4GH spec) that help with upstream authorization. Any claim in the token (which is a JSON Web Token) is merely a key-value pair within its payload section.

The Roadblock

While the OIDC allows the creation of custom claims (the key-value pairs) in the tokens, it does not impose any limit on the size of the fields. To make the claims and their values self-sufficient, the GA4GH standard decided to add relevant details like cryptographic keys, etc., which make the claim values large. At the same time, the claim value can also be a list of items. This makes them even larger, depending on how many items are on the list.

As noted in the last section, for CanDIG to work as a distributed and federated system, it needs to have a facility to check for authorization. The core of that is checking for these Passports and claims within them. This Passport comes from an OIDC defined endpoint called “userinfo”.

Diagram showing the use of userinfo endpoint of the OpenID Connect protocol to fetch the Identity Token.
Figure 1: Identity Brokering in Keycloak using OpenID Connect's userinfo endpoint to get Identity Token from the user's institute

In Keycloak, the said userinfo endpoint was not working. When a user goes through logging in via their site in a CanDIG federation project to access a resource on another site, this userinfo endpoint was not being called by the Keycloak on the foreign site to fetch the details of the user. As a result, the authorization information was missing and no access was given even though this user may have had valid access.

Screenshot of the settings page in Keycloak for an Identity Broker with markers to show the userinfo toggle.
Figure 2: Settings page in Keycloak for an Identity Broker with markers to show the userinfo toggle

The screenshot above shows that even if the toggle to Disable User Info is off, the userinfo endpoint was still never called.

The Fix

The line that is responsible for this issue is as follows -

if (userInfoUrl != null && !userInfoUrl.isEmpty() && (id == null || name == null || preferredUsername == null || email == null)) {

and the fixed version is -

if (userInfoUrl != null && !userInfoUrl.isEmpty()) {

Deleting the unneeded conditional checks was the only thing required to fix this.

Contributing to Keycloak Codebase

Setting up to a point where we can finally test the changes, add tests, confirm nothing else breaks, and contribute the PR, all of this was the cumbersome part. This fix needed to be manually checked first and that required setting up two Keycloak servers with the right configuration.

Reasons Bootstrapping is Tough

Broker testing

One detail in this entire story is that fetching userinfo internally Keycloak has a feature called Mappers which helps in mapping or converting the incoming external claims to internal user attributes. This is important to pass the incoming claim to the user’s session so that the local application can use that user attributes to make the decisions.

When using Keycloak’s user interface, it is easy to check these mappers, change them, and set them. However, when you have to write unit tests, you need to find a way to do that programmatically and figure out which class to extend. In this case, the main two classes were -

Once you figure out the correct classes to extend, your test writing is much more smooth. Writing tests gives you confidence and makes the maintainers’ lives easier. It is to be noted that you may not have to write a ton of tests. The original PR had ten (10) tests but the maintainers suggested only tests were sufficient because they likely cover the cases that need focus.

You can see the pull request - KEYCLOAK-14039 - UserInfo claims from external OIDC identity provider are not imported #7214.

Final Word and Recap

Every open-source project has its peculiarities and it may seem daunting at first.

References