Heute werfen wir einen Blick unter die Haube von Keycloak und tauchen ein in die Welt der benutzerdefinierten Zuordnungen, Erweiterungen und Integrationen. Schnallt euch an, denn diese Fahrt wird wild!
TL;DR
Wir tauchen tief in die Anpassung von Keycloak ein und behandeln:
- Benutzerdefinierte Benutzerattribut-Zuordnungen
- Erstellen von Keycloak-Erweiterungen (SPIs)
- Implementierung benutzerdefinierter Authentifizierungsabläufe
- Integration mit externen Systemen
Wenn du bereit bist, Keycloak zu deinem persönlichen Auth-Spielplatz zu machen, lies weiter!
Benutzerdefinierte Benutzerattribut-Zuordnungen: Weil eine Größe nicht für alle passt
Seien wir ehrlich, die Standard-Benutzerattribute in Keycloak sind so aufregend wie Vanilleeis. Aber keine Sorge! Wir können mit benutzerdefinierten Attribut-Zuordnungen etwas Würze hinzufügen.
Hinzufügen benutzerdefinierter Attribute
Fangen wir an, ein benutzerdefiniertes Attribut zu unseren Benutzern hinzuzufügen. In der Keycloak-Admin-Konsole:
- Gehe zu Benutzer > Attribute
- Füge ein neues Attribut hinzu, zum Beispiel "favoriteProgLanguage"
Jetzt ordnen wir dies einem Anspruch im JWT-Token zu. Gehe zu Clients > [Dein Client] > Client Scopes > Dedizierter Scope > Mapper hinzufügen > Nach Konfiguration > Benutzerattribut.
Fülle die Details aus:
- Name: Lieblingsprogrammiersprache
- Benutzerattribut: favoriteProgLanguage
- Token-Anspruchsname: fav_lang
Voilà! Jetzt wird beim Einloggen eines Benutzers seine Lieblingsprogrammiersprache im JWT enthalten sein. Warum auch nicht?
Benutzerdefinierter Protokoll-Mapper
Aber warte, es gibt noch mehr! Was, wenn wir unsere Attribute vor der Token-Übertragung noch etwas aufpeppen wollen? Hier kommen benutzerdefinierte Protokoll-Mapper ins Spiel.
Lass uns einen Mapper erstellen, der unsere Lieblingssprache in Großbuchstaben umwandelt (weil es völlig normal ist, unsere Liebe zu Python herauszuschreien).
public class UppercaseLanguageMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
public static final String PROVIDER_ID = "uppercase-language-mapper";
@Override
public String getDisplayCategory() {
return TOKEN_MAPPER_CATEGORY;
}
@Override
public String getDisplayType() {
return "Uppercase Language Mapper";
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
UserModel user = userSession.getUser();
String favLang = user.getFirstAttribute("favoriteProgLanguage");
if (favLang != null) {
token.getOtherClaims().put("FAV_LANG", favLang.toUpperCase());
}
}
}
Das nenne ich eine benutzerdefinierte Zuordnung! Deine Lieblingssprache wird von den Dächern geschrien (oder zumindest von deinem JWT).
Keycloak-Erweiterungen: Weil man manchmal die Regeln brechen muss
Die Erweiterbarkeit von Keycloak ist wie ein Spielplatz für Auth-Nerds. Lass uns ein einfaches SPI (Service Provider Interface) erstellen, das eine benutzerdefinierte Aktion zum Authentifizierungsablauf hinzufügt.
Erstellen eines benutzerdefinierten Authentifikators
Stell dir vor, wir möchten einen Authentifikator hinzufügen, der überprüft, ob das Passwort des Benutzers seinen Benutzernamen enthält (ein Sicherheits-No-Go). Hier ist eine vereinfachte Version:
public class UsernamePasswordValidator implements Authenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
UserModel user = context.getUser();
CredentialInput input = context.getHttpRequest().getDecodedFormParameters().getFirst(CredentialForm.PASSWORD);
if (input.getValue().contains(user.getUsername())) {
context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS,
context.form().setError("passwordContainsUsername").createErrorPage());
return;
}
context.success();
}
// ... andere erforderliche Methoden
}
Jetzt musst du diesen Authentifikator bei Keycloak registrieren und ihn zu deinem Authentifizierungsablauf hinzufügen. Deine Benutzer werden es dir später danken (oder dich jetzt verfluchen, das ist ungewiss).
Benutzerdefinierte Authentifizierungslogik: Weil man manchmal ein besonderes Schneeflöckchen sein muss
Angenommen, dein Unternehmen hat eine supergeheime Authentifizierungsmethode, die eine magische 8-Kugel und eine Tasse Kaffee beinhaltet. Keine Sorge, Keycloak hat dich im Griff!
Implementierung eines benutzerdefinierten Authentifizierungsablaufs
Hier ist ein Vorgeschmack darauf, wie ein benutzerdefinierter Authentifizierungsablauf aussehen könnte:
public class CoffeeAuthenticator implements Authenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
if (isCoffeeBrewed() && magicBallSaysYes()) {
context.success();
} else {
context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS,
context.form().setError("needMoreCoffee").createErrorPage());
}
}
private boolean isCoffeeBrewed() {
// Implementiere deine Kaffee-Überprüfungslogik hier
return true; // Optimisten, vereinigt euch!
}
private boolean magicBallSaysYes() {
// Konsultiere die magische 8-Kugel
return Math.random() > 0.5; // 50/50 Chance, klingt legitim
}
// ... andere erforderliche Methoden
}
Denk daran, mit großer Macht kommt große Verantwortung. Nutze dieses Wissen weise, sonst endest du mit einem Authentifizierungssystem, das nur funktioniert, bevor der Kaffee ausgeht.
Integration mit externen Systemen: Gut mit anderen auskommen
Keycloak muss kein Einzelgänger sein. Schauen wir uns an, wie wir es mit externen Systemen verbinden können.
Benutzerdefinierter Benutzerspeicheranbieter
Stell dir vor, du hast Benutzerdaten in einem Altsystem gespeichert, das Lochkarten verwendet (weil warum nicht?). Hier ist ein vereinfachtes Beispiel, wie du das mit Keycloak integrieren könntest:
public class PunchCardUserStorageProvider implements UserStorageProvider, UserLookupProvider, CredentialInputValidator {
private PunchCardSystem punchCardSystem;
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
PunchCardUser punchCardUser = punchCardSystem.findUserByHoles(username);
if (punchCardUser != null) {
return new UserAdapter(session, realm, model, punchCardUser);
}
return null;
}
@Override
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
if (!supportsCredentialType(input.getType())) return false;
return punchCardSystem.validateCard(user.getUsername(), input.getChallengeResponse());
}
// ... andere erforderliche Methoden
}
Jetzt kann dein Vintage-Lochkartensystem Benutzer in Keycloak authentifizieren. Willkommen im 21. Jahrhundert... irgendwie.
Fazit: Keycloak ist deine Auster
Wir haben nur an der Oberfläche dessen gekratzt, was mit der Anpassung von Keycloak möglich ist. Von der Anpassung von Benutzerattributen bis hin zum Aufbau vollständiger Authentifizierungsanbieter bietet Keycloak eine robuste Plattform, um dein Authentifizierungssystem nach deinen Wünschen zu gestalten.
Denk daran, mit großer Macht kommt große Verantwortung (und potenziell große Kopfschmerzen). Teste gründlich, dokumentiere gewissenhaft und möge der Auth-Gott dir wohlgesonnen sein.
Wichtige Erkenntnisse:
- Benutzerdefinierte Attribut-Zuordnungen verleihen deinen Tokens Flair
- SPIs eröffnen eine Welt der Erweiterbarkeit
- Benutzerdefinierte Authentifizierungsabläufe ermöglichen einzigartige (und potenziell koffeinhaltige) Authentifizierungslogik
- Die Integration externer Systeme ist möglich, selbst für die ältesten Systeme
Geh jetzt und passe an! Und denk daran, wenn jemand fragt, warum du eine Woche damit verbracht hast, ein kaffeebasiertes Authentifizierungssystem zu implementieren, sag einfach, es sei für "erhöhte Sicherheit". Sie werden es dir abkaufen.
"Der einzige Weg, großartige Arbeit zu leisten, ist, zu lieben, was man tut." - Steve Jobs
(Er hat wahrscheinlich nicht über die Anpassung von Keycloak gesprochen, aber wir können so tun.)
Viel Spaß beim Programmieren, und möge dein Token immer gültig und dein Kaffee immer stark sein!