From 476cb92600003a6a77c833228ab97dd1e6a40043 Mon Sep 17 00:00:00 2001 From: louis Date: Wed, 22 May 2024 13:09:15 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20Support=20for=20TOTP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/systemli/keycloak/UserliHttpClient.java | 11 ++++++++++- .../keycloak/UserliUserStorageProvider.java | 17 +++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/systemli/keycloak/UserliHttpClient.java b/src/main/java/org/systemli/keycloak/UserliHttpClient.java index eb7e153..69c0526 100644 --- a/src/main/java/org/systemli/keycloak/UserliHttpClient.java +++ b/src/main/java/org/systemli/keycloak/UserliHttpClient.java @@ -60,13 +60,22 @@ public UserliUser getUserById(String id) { } @SneakyThrows - public Boolean validate(String email, String password) { + public Boolean validate(String email, String password, String credentialType) { String url = String.format("%s/api/keycloak/%s/validate/%s", baseUrl, realmDomain, email); SimpleHttp.Response response = SimpleHttp.doPost(url, httpClient) .auth(keycloakApiToken) + .param("credentialType", credentialType) .param("password", password) .asResponse(); return response.getStatus() == 200; } + @SneakyThrows + public Boolean isConfiguredFor(String email, String credentialType) { + String url = String.format("%s/api/keycloak/%s/configured/%s/%s", baseUrl, realmDomain, credentialType, email); + return SimpleHttp.doGet(url, httpClient) + .auth(keycloakApiToken) + .asResponse().getStatus() == 200; + } + } diff --git a/src/main/java/org/systemli/keycloak/UserliUserStorageProvider.java b/src/main/java/org/systemli/keycloak/UserliUserStorageProvider.java index 3c60bf9..a336b7d 100644 --- a/src/main/java/org/systemli/keycloak/UserliUserStorageProvider.java +++ b/src/main/java/org/systemli/keycloak/UserliUserStorageProvider.java @@ -2,12 +2,14 @@ import org.keycloak.component.ComponentModel; import org.keycloak.credential.CredentialInput; +import org.keycloak.credential.CredentialInputUpdater; import org.keycloak.credential.CredentialInputValidator; import org.keycloak.models.GroupModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; +import org.keycloak.models.credential.OTPCredentialModel; import org.keycloak.models.credential.PasswordCredentialModel; import org.keycloak.storage.StorageId; import org.keycloak.storage.UserStorageProvider; @@ -43,12 +45,16 @@ public void close() { @Override public boolean supportsCredentialType(String credentialType) { - return PasswordCredentialModel.TYPE.equals(credentialType); + return PasswordCredentialModel.TYPE.equals(credentialType) || OTPCredentialModel.TYPE.equals(credentialType); } @Override public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) { - return supportsCredentialType(credentialType); + return switch (credentialType) { + case PasswordCredentialModel.TYPE -> true; + case OTPCredentialModel.TYPE -> client.isConfiguredFor(user.getEmail(), credentialType); + default -> false; + }; } @Override @@ -57,12 +63,7 @@ public boolean isValid(RealmModel realm, UserModel user, CredentialInput credent return false; } - String password = credentialInput.getChallengeResponse(); - if (password == null) { - return false; - } - - return client.validate(user.getEmail(), password); + return client.validate(user.getEmail(), credentialInput.getChallengeResponse(), credentialInput.getType()); } @Override