Automatisiertes Testing von Keycloak-Erweiterungen

von Tobias Kraft
Automatisiertes Testing von Keycloak-Erweiterungen

Wird ein Identity & Access Management (IAM) System eingeführt, startet dies selten isoliert, sondern wird meist in die bestehende Infrastruktur integriert. Insbesondere im Zusammenhang mit Service-Portalen ist es notwendig, Informationen und Verbindungen für bestehende Systeme zu integrieren. Dies gilt auch primär für das Benutzer-Management eines Service-Portals. Eine Out-of-the-box-Lösung für das IAM funktioniert selten ohne Anpassungen, aber mit einem Open-Source-Produkt wie Keycloak sind entsprechende individuelle Erweiterungen möglich.

Individuelle Keycloak Lösungen

Keycloak bietet die Flexibilität für Individualisierungen über sogenannte Custom Erweiterungen. Das erfordert entsprechende Implementierungsarbeit.

Typische Beispiele für individuelle Anpassungen und Integrationen sind:

  • Neue REST-Endpunkte, um Benutzer-Management-Funktionalitäten durchzuführen, wie beispielsweise Duplizierung der Benutzer mit anschließendem E-Mail-Versand
  • Protocol Mapper zur Definition eigener Claims im JWT-Token
  • Eigene User-Federation für die Integration externer Benutzer-Datenquellen
  • Event Listener über die Event SPI (Service Provider Interfaces), um nach dem Login eines Benutzers Benachrichtigungen zu verschicken
  • Nutzung der Authenticator SPI, um Captchas zu integrieren
  • Login- und Passwort-Vergessen Seiten, die an die Corporate Identity des Unternehmens angepasst sind.

Die konkrete Umsetzung von Erweiterungen haben wir bereits in den beiden Blogposts Keycloak-Customizing leicht gemacht und Keycloak-Integration leicht gemacht gezeigt.

Eigene Erweiterungen erstellen

Keycloak basiert auf Java und dementsprechend werden tiefergehende Anpassungen, die nicht über Konfigurationen möglich sind, in der Programmiersprache Java umgesetzt. Die Keycloak Java API stellt diverse Interfaces bereit, die abhängig von der angestrebten Erweiterung implementiert werden.

Nach der Umsetzung wird der Code in eine JAR-Datei gepackt und Keycloak über ein Verzeichnis zur Verfügung gestellt. Nach dem Starten des Keycloak-Servers können die Erweiterungen genutzt werden. Keycloak wird häufig als Container-Image – z. B. mit Docker – bereitgestellt. In diesem Fall wird gewöhnlich so vorgegangen, dass die JAR-Datei Teil des Images ist. Hierfür wird beim Bau des Images, die JAR-Datei in das Keycloak-Verzeichnis kopiert.
In Keycloak selbst müssen abhängig von der Erweiterung noch entsprechende Konfigurationen für REALMS oder Gruppen angelegt werden.

Nach der Bereitstellung erfolgt der Test und da die Integrationen oftmals eine entsprechende Komplexität haben, funktioniert in der Regel nicht alles auf Anhieb bzw. es werden nach und nach Erweiterungen hinzugefügt. Dies bedeutet aber auch, dass jedes Mal der Bereitstellungs-Prozess durchgeführt werden muss, welcher, wie oben aufgeführt, zeitintensiv und umständlich ist. Wie lässt sich dieser Prozess verbessern?

So funktioniert automatisiertes Testing für Keycloak-Erweiterungen

Generell gilt, dass mit automatisierten Tests Code schneller und außerdem wiederholt überprüft werden kann. Es ist ein Grundaufwand für die Erstellung der Tests notwendig, der sich jedoch in den meisten Fällen schnell auszahlt und insbesondere bei zukünftigen Erweiterungen entsprechende Sicherheiten durch die Regressionstests bietet.

Für die Keycloak Erweiterungen ist es mit einem Standard JUnit-Test jedoch nicht getan, da der gesamte Kontext überprüft werden soll. In diesem Fall müssen die Erweiterungen in einem konfigurierten Keycloak-Server getestet werden.

Mithilfe des Frameworks Testcontainers, das es ermöglicht, für automatisierte Tests leichtgewichtige, temporäre Docker-Container mit Datenbanken, Message-Brokern oder beliebigen Services bereitzustellen, kann hier Abhilfe geschaffen werden. Für Testcontainers gibt es eine Keycloak-Erweiterung, mit deren Hilfe Integrations-Tests realisiert werden können.

Hierfür muss in der Testklasse zunächst die Keycloak-Instanz bereitgestellt werden. Für diese Instanz erfolgt dann auch vor der Testdurchführung die Konfiguration von Keycloak. Der nachfolgende Code zeigt die Konfiguration eines einfachen REALMS.

@Container
private static final KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:26.3");

@BeforeAll
static void beforeAll() {
    Keycloak kcAdmin = keycloak.getKeycloakAdminClient();

    RealmRepresentation realm = new RealmRepresentation();
    realm.setRealm("myRealm");
    realm.setEnabled(true);
    realm.setLoginWithEmailAllowed(true);
    realm.setResetPasswordAllowed(true);
}

Mit dem Starten des JUnit-Tests fährt Testcontainer den Keycloak-Server hoch. Damit die selbst geschriebenen Erweiterungen getestet werden können, müssen diese für die Keycloak-Instanz automatisiert zur Verfügung gestellt werden. In unserem Fall wird die mit gradle gebaute JAR-Datei adapter-federation.jar an den Container übergeben und steht damit der Keycloak-Instanz zur Verfügung

@Container
private static final KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:26.3")
    .withProviderLibsFrom(List.of(new File("build/adapter-federation.jar")))
    .withNetwork(network);

Die Testdurchführung erfolgt über die JUnit-Methoden. Ein Beispiel hierfür skizziert der folgende Code-Abschnitt. Hier wird Authentifizierung von verschiedenen Benutzern durch Aufruf der Login-Methode abgetestet. In diesem Fall wird eine Custom User Federation getestet. Dies bedeutet, die Benutzer sind nicht in Keycloak selbst hinterlegt, sondern in einer externen Applikation auf die über die Custom User Federation zugegriffen wird. Der durch den Test aufgerufene Login-Prozess durchläuft die entsprechenden Code-Erweiterungen und validiert erfolgreiche Login-Vorgänge.

@ParameterizedTest
@ValueSource(strings = {"admin", "user"})
public void testLoginAsUserWithInvalidPassword(String username) {
    String tokenEndpoint = getTokenEndpointURL();
    given()
        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
        .formParam(OAuth2Constants.USERNAME, username)
        .formParam(OAuth2Constants.PASSWORD, "valid-password")
        .formParam(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
        .formParam(OAuth2Constants.CLIENT_ID, KeycloakContainer.ADMIN_CLI_CLIENT)
        .when()
            .post(tokenEndpoint)
        .then()
            .statusCode(200);
}

Logfiles für Problem-Analysen

Zu Beginn der Implementierung kommt es bei der Erstellung des Grundgerüstes oft zu Problemen und die Tests liefern nicht die erwarteten Ergebnisse.
Greifen wir wieder das Beispiel einer externen User Federation auf, kann es durchaus passieren, dass wir im Test nicht den erwarteten HTTP-Status zurückbekommen. Man sieht natürlich im Test-Case, an welcher Stelle der Test schiefgegangen ist, aber der Grund ist teilweise nicht sichtbar. Anhand des nicht erwarteten HTTP-Status-Code kommt man selten weiter, wenn man in der JUnit-Log-Ausgabe nichts Weiteres sieht.

Was kann hier getan werden? Es bietet sich an, die Docker Container Logdateien zu schauen. Da der Container aber nach dem Test verworfen wird, ist dies auf den ersten Blick gar nicht so einfach.

Greift man, wie im nächsten Code-Snippet zu sehen, nach dem Ausführen des Tests in der Methode mit der JUnit Annotation @AfterAll auf die Container-Instanz zu, ist eine Ausgabe der Container-Logs möglich. Dies erleichtert die Fehlerfindung deutlich. In unserem Beispiel werden die Log-Daten des von Keycloak ausgegeben und auch die des MySQL-Containers, auf den die User Federation zugreift.

@Container
private static final MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0.43")
	.withNetwork(network)
    .withNetworkAliases("mysql");

@Container
private static final KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:26.3")
    .withProviderLibsFrom(List.of(new File("build/adapter-federation.jar")))
    .withNetwork(network);

@AfterAll
static void afterAll() {
    System.out.println("\n=====FINAL CONTAINER LOGS=====");

    System.out.println("\n=====MySQL LOGS=====");
    System.out.println(mysql.getLogs());

    System.out.println("\n=====Keycloak LOGS=====");
    System.out.println(keycloak.getLogs());

    System.out.println("\n=====END CONTAINER LOGS=====");
}

Fazit

Durch die Erstellung von automatisierten Tests mithilfe der Testcontainer kann die Entwicklung von Custom Erweiterungen für Keycloak deutlich schneller erfolgen, weil die zeitintensiven und umständlich durchzuführenden manuellen Tests auf ein Minimum reduziert werden. Auch für zukünftige Erweiterungen ist ein Projekt durch die Regressions-Fähigkeit der Tests gut gerüstet.

Gerade in hochsensiblen Bereichen wie der Pharma-Branche sind automatisierte Tests eine unverzichtbare Grundlage, um IAM-Projekte erfolgreich umzusetzen und Auditierungen zuverlässig zu bestehen.

Zurück

© 2006-2026 exensio GmbH
Einstellungen gespeichert
Datenschutzeinstellungen

Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell, während andere uns helfen, diese Website und Ihre Erfahrung zu verbessern.

Sie können Ihre Einwilligung jederzeit ändern oder widerrufen, indem Sie auf den Link in der Datenschutzerklärung klicken.

Zu den gesetzlichen Rechenschaftspflichten gehört die Einwilligung (Opt-In) zu protokollieren und archivieren. Aus diesem Grund wird Ihre Opt-In Entscheidung in eine LOG-Datei geschrieben. In dieser Datei werden folgende Daten gespeichert:

 

  • IP-Adresse des Besuchers
  • Vom Besucher gewählte Datenschutzeinstellung (Privacy Level)
  • Datum und Zeit des Speicherns
  • Domain
×
Irving Tschepke
Irving Tschepke
Dipl.-Wirtsch.-Ing.
Peter Soth
Peter Soth
Dipl.-Inform. (FH)
Wir antworten in wenigen Stunden.
Oder rufen Sie einfach an:
×
Irving Tschepke
Irving Tschepke
Dipl.-Wirtsch.-Ing.
Peter Soth
Peter Soth
Dipl.-Inform. (FH)
Wir antworten in wenigen Stunden.
Oder rufen Sie einfach an:
You are using an outdated browser. The website may not be displayed correctly. Close