[JAVA] Introduction to Keycloak development

First Edition: 2018/8/1

Author: Toshimitsu Motegi, Hitachi, Ltd.

Introduction

Keycloak (https://www.keycloak.org/) is open source identity access management software. Anyone can contribute to the development of Keycloak because it is developed on a community basis, but I think that it is difficult to get started without knowing the development method and community rules. So, this time, I would like to share the knowledge I got through the contents of the patch development (# 5163) that I did. ..

You can find this information in README.md and HackingOnKeycloak.md in the Keycloak repository. com / keycloak / keycloak / blob / master / misc / HackingOnKeycloak.md), [HOW-TO-RUN.md](https://github.com/keycloak/keycloak/blob/master/testsuite/integration-arquillian/HOW -TO-RUN.md) is based on the contents.

This article is an addition to the content presented at the OSS Security Technology Association 3rd Study Group.

table of contents

-Development -[Feature Suggestion, Bug Report](#Feature Suggestion Bug Report) -[Preparation for implementation](#Preparation for implementation) -[Build method](# Build method) --[Import to IDE](Import to #ide) -[Debugging method with IDE (Eclipse)](Debugging method with #ideeclipse-) -[Modify code](#Modify code) -[Details of correction](#Details of correction) --[Identity Provider related file location](# identity-provider related file location) -[GUI change](#gui change) --[Modify DB Schema](Modify #db Schema) -[Implementation of Test](Implementation of #test) -[Post to GitHub](Post to #github) -Summary

What was developed

Keycloak has a function called Identity Brokering, and the result of authentication with an external OpenID Connect Provider can be used with Keycloak. Keycloak also has settings for connecting to popular providers such as Google and Facebook.

brokering.png

Since there was a requirement that the user authentication process including the screen be done by himself, we set it to redirect to the original authentication application using Identity Brokering. However, in this authentication application, it was necessary for the client to send parameters outside the specifications of OpenID Connect, but in Keycloak's Identity Brokering, the Query Parameter that you want to specify independently is transferred to the external Identity Provider (= authentication screen). did not.

To solve this, we implemented our own Identity Provider that transfers parameters using the Identity Provider SPI (an interface for extending Identity Brokering). However, I felt that there were other use cases that used parameters outside the OpenID Connect specification, so I decided to contribute to the community as a general function.

Feature suggestions, bug reports

Keycloak uses the following tools to suggest new features and report bugs.

If you find a bug, first create a ticket with details in JIRA and then create a Pull Request with the ticket ID in the title.

From here, we will introduce how to prepare the patch development environment, how to change the code, how to execute the test, etc. based on the knowledge of the actual patch development.

Preparation for implementation

First, fork the Keycloak Repository and clone the Repository.

$ git clone https://github.com/<username>/keycloak

We will prepare in this cloned directory.

How to build

When you bring the source code, build it first. JDK and Maven are required for building, so please set up each.

Build the source code with the following command.

$ mvn install -DskipTests=true
$ cd distribution
$ mvn install

Tests can fail depending on the environment, so it's a good idea to skip the tests at build time, fix them, and then run only the relevant tests. When the above command is executed, the build (.tar.gz, .zip) will be output under distribution / server-dist / target. You can also run Keycloak by unpacking these and running bin / standalone.sh.

Import into IDE

Next, we will prepare for development in the IDE. This time, I used Eclipse (Oxygen) as the IDE. Import the Maven project into Eclipse by specifying the pom.xml file (which will be the project keycloak-parent) directly under the Keycloak repository.

Due to the large number of projects (300+), the import will take some time.

How to debug in IDE (Eclipse)

To start Keycloak under development, run mvn -f testsuite / utils / pom.xml exec: java -Pkeycloak-server as described in README.md. After starting the Keycloak server, you can access the Keycloak GUI from localhost: 8081 / auth /.

As mentioned above, it is possible to execute with Maven from the command line, but since we are using Eclipse, we will be able to debug there. If you look at the pom.xml specified in the above command, you can see that the class ʻorg.keycloak.testsuite.KeycloakServer of the keycloak-testsuite-utils` project is running, so specify this class for debugging. To execute. The settings are as shown in the figure below.

debug_config.png

You can now use Eclipse to debug Keycloak.

Further configure the database settings. InMemoryDB of H2DB is used by default setting, but if it is left as it is, the setting will be deleted every time it is restarted. Since it is troublesome to reset it many times, set it to save to a file. Specify -Dkeycloak.connectionsJpa.url = jdbc: h2: ./keycloak; AUTO_SERVER = TRUE as a startup argument. The setting method in Eclipse is as shown in the figure below.

persist_settings.png

Now that we are ready for development, including debugging, we will modify the code.

Code fix

From here, we will explain the architecture of Keycloak based on the implementation of the function "Transfer custom parameters to an external Identity Provider with the Identity Brokering function".

Details of the correction

The parameter values when Keycloak's Authorization Endpoint was accessed were stored in a model called AuthorizationSession, including non-specification parameters. So, in the part that creates RedirectURL to the external Identity Provider, I modified to get the non-specification parameter from AuthorizationSession and add it to the URL.

Also, instead of forwarding all parameters, only the parameters specified in the Identity Brokering settings are forwarded.

Location of Identity Provider related files

Basic functions such as authentication and authorization, and Identity Brokering functions are implemented in a project called keycloak-services. This project implements the SPI defined by keycloak-spi, keycloak-spi-private. As in the case of developing a plug-in using SPI, Provider and ProviderFactory are implemented in pairs.

The OpenID Connect Identity Provider is implemented in a class called ʻorg.keycloak.broker.oidc.OIDCIdentityProvider. The Redirect URL to the external Identity Provider was created by the method createAuthorizationUrl of ʻorg.keycloak.broker.oidc.AbstractOauth2IdentityProvider inherited by this class, so I modified this method. It was.

GUI changes

In order to transfer only specific external parameters, an item to set the parameters to be transferred has been added to the setting item of Identity Provider.

label.png

The Keycloak GUI is made with AngularJS (1.6). There is a template and Javascript code under the project keycloak-themes. Since the setting items of the Idenity Provider were designed to send all the contents of the Form to the API, it could be implemented simply by adding the Form and Tooltip to the template realm-identity-provider-oidc.html.

As of July 2018, a folder called keycloak-preview was created under keycloak-themes. It seems that the GUI of Keycloak's Admin Console is newly created, and when I looked at it lightly, it seemed that it was created with Angular 5. I've seen pull requests such as responsive support, so I'd like to expect and wait.

DB schema modification

Since I increased the setting items of Identity Provider, I thought that it was necessary to change the DB schema. However, since the setting items were registered in the table ʻIDENTITY_PROVIDER_CONFIGin the form of key-value, there was no need to change the schema. It is also managed byMap <String, String>` in the code. Considering that there are many changes in the setting items, I thought it was rational to make this so that it can be handled without the need for schema changes.

I didn't need to change the schema this time, but if I need to make any DB related changes, I'll change them because the models are in the keycloak-model-jpa project.

Test implementation

Keycloak uses a test framework called Arquiilian to perform integration tests. Identity Brokering tests are included in a project called ʻintegration-arquiilian-tests-base (testsuite \ integration-arquillian \ tests \ base`).

As for how to test the external Identity Provider, it was supported by using two Realms, consumer and provider, as shown in the figure.

provider-consumer.png

Looking at the existing tests, there was a test that checked the query parameters, so I used it to describe the test.

To run the implemented test, run the following command.

$ mvn -f testsuite/integration-arquillian/tests/base/pom.xml test

This will run the basic function tests, but each test will take a long time, and due to the number of tests, it will take a considerable amount of time to complete all the tests. To run a specific test, specify the class name with -Dtest.

$ mvn -f testsuite/integration-arquillian/tests/base/pom.xml test -Dtest=org.keycloak.testsuite.broker.KcOidcBrokerParameterForwardTest

You can also specify a test using a regular expression with -Dtest. For example, the following command can only run Identity Broker related tests.

$ mvn -f testsuite/integration-arquillian/tests/base/pom.xml test -Dtest=org.keycloak.testsuite.broker.Kc*

This Base test was only a basic function test, but various tests such as adapter test and UI test are implemented. For more information, see [HOW-TO-RUN.md](https://github.com/keycloak/keycloak/blob/master/testsuite/integration-arquillian/HOW-TO-RUN. in the keycloak-testsuite project. See md).

This completes the necessary code modifications. I will finally post the fix on GitHub.

Post to GitHub

Push the modified code to GitHub and issue a Pull Request, and Travis CI will run the integration test. It takes about 20 minutes to complete all the tests. If all Tests pass, they will be reviewed.

The code review was well viewed (assertThat is easier to read than assertTrue / assertFalse, etc.). At first I wrote a unit test, but since the function was already covered by the integration test, I got a comment that "If the contents overlap between the integration test and the unit test, the maintenance cost will increase" and decided that it is unnecessary. became.

The integration test is solid, so it seems that the policy is that unit tests are not necessary if it can be covered.

I was told that the changes would eventually be combined into one commit, so I combined the commits with git rebase -i and pushed with git push -f.

It took a while to be merged, but it was merged successfully. https://github.com/keycloak/keycloak/pull/5163

Summary

Keycloak is an active community, new features are being developed one after another, and we are actively incorporating improvements from outside the community.

Let's release more and more patches from Japan and make it a good OSS.

Recommended Posts

Introduction to Keycloak development
Introduction to Android application development
Introduction to Ruby 2
Introduction to SWING
Introduction to web3j
Introduction to Micronaut 1 ~ Introduction ~
[Java] Introduction to Java
Introduction to migration
Introduction to java
Introduction to Doma
Introduction to Slay the Spire Mod Development (1) Introduction
Introduction to Docker / Kubernetes Practical Container Development
Introduction to JAR files
Introduction to Ratpack (8)-Session
Introduction to RSpec 1. Test, RSpec
Introduction to bit operation
Introduction to Ratpack (9) --Thymeleaf
Introduction to Android Layout
Introduction to design patterns (introduction)
Introduction to Practical Programming
Introduction to javadoc command
Introduction to jar command
Introduction to Ratpack (2)-Architecture
Introduction to java command
Introduction to RSpec 2. RSpec setup
Introduction to Robot Battle with Robocode (Beginner Development)
Introduction to javac command
Introduction to Slay the Spire Mod Development (2) Development Environment Construction
[Introduction to Android application development] Let's make a counter
Introduction to Design Patterns (Builder)
Introduction to RSpec 6. System specifications
Introduction to RSpec 3. Model specs
Introduction to Ratpack (5) --Json & Registry
Introduction to Metabase ~ Environment Construction ~
Introduction to Ratpack (7) --Guice & Spring
Introduction to Design Patterns (Composite)
Introduction to Micronaut 2 ~ Unit test ~
Introduction to JUnit (study memo)
Introduction to Spring Boot ① ~ DI ~
Introduction to design patterns (Flyweight)
[Java] Introduction to lambda expressions
Introduction to Spring Boot ② ~ AOP ~
Introduction to Apache Beam (2) ~ ParDo ~
[Ruby] Introduction to Ruby Error statement
Introduction to EHRbase 2-REST API
Introduction to design patterns Prototype
GitHub Actions Introduction to self-made actions
[Java] Introduction to Stream API
Introduction to Design Patterns (Iterator)
Introduction to Spring Boot Part 1
Introduction to Ratpack (1) --What is Ratpack?
XVim2 introduction memo to Xcode12.3
Introduction to RSpec-Everyday Rails Summary-
Introduction to Design Patterns (Strategy)
[Introduction to rock-paper-scissors games] Java
Run the sample "Introduction to TensorFlow Development" on Jetson nano
Introduction to Slay the Spire Mod Development (3) Original Card Definition
[Introduction to Java] About lambda expressions
Introduction to algorithms in java-cumulative sum
Introduction to Functional Programming (Java, Javascript)
Introduction to Ruby processing system self-made