From 05889984fd53ba3b3f79b28bb7da001431e838b9 Mon Sep 17 00:00:00 2001 From: Djeumen Rolain Bonaventure Date: Tue, 31 Oct 2023 10:58:00 +0100 Subject: [PATCH] chore(keycloak-integration): refactoring (#6375) * feat(keycloak-integration): added maven parent pom for subprojects * feat(keycloak-integration): added janssen authenticator pom * feat(keycloak-integration): added maven assembly xml for authenticator dependencies * feat(keycloak-integration): added spi factory discovery meta for keycloak * added authenticator spi factory discovery meta for keycloak * added rest service spi factory discovery meta for keycloak * feat(keycloak-integration): added authenticator message mapping file * feat(keycloak-integration): added authenticator image resources * feat(keycloak-integration): added page templates for authenticator * feat(keycloak-integration): added authenticator core coded * added authenticator code * added authenticator factory code * added authenticator config properties code * feat(keycloak-integration): added missing file containing session attribute definitions * feat(keycloak-integration): added nimbus based minimalist oidc client code * chore(keycloak-integration): minor change to the authenticator factory * feat(keycloak-integration): added authn completion rest service Signed-off-by: Rolain Djeumen * feat(keycloak-integration): fix authn return url from janssen Signed-off-by: Rolain Djeumen * feat(keycloak-integration): added installation documentation Signed-off-by: Rolain Djeumen * chore(keycloak-integration): renamed project and plugin internal names Signed-off-by: Rolain Djeumen * chore(keycloak-integration): minor update to documentation to reflect project name change Signed-off-by: Rolain Djeumen * chore(keycloak-integration): renamed the keycloak integration source directory Signed-off-by: Rolain Djeumen * feat(keycloak-integration): added skeleton code for task scheduler Signed-off-by: Rolain Djeumen * chore(keycloak-integration): moved kc storage spi into jans-keycloak-integration Signed-off-by: Rolain Djeumen * chore(keycloak-integration): removed storage-api as it was moved to jans-keycloak-integration Signed-off-by: Rolain Djeumen * chore(keycloak-integration): removed test case from storage-spi Signed-off-by: Rolain Djeumen * chore(keycloak-integration): housekeeping * moved of storage-spi to jans-keycloak-integration * integrated storage-spi dependencies into kc integration parent pom * ensure all kc integration projects build Signed-off-by: Rolain Djeumen * chore(keycloak-integration): storage spi refactoring * added plugin configuration file getting configuration from keycloak Signed-off-by: Rolain Djeumen * chore(keycloak-integration): storage spi refactoring * removed old config loader class * removed all references to said class and replaced with new config loader Signed-off-by: Rolain Djeumen * chore(keycloak-integration): authenticator refactoring * normalized provider id for the authenticator spi * normalized provider id for the authenticator rest service spi Signed-off-by: Rolain Djeumen * chore(keycloak-integration): keycloak storage spi refactoring * began swapping log4j for jboss logger to reduce external deps * normalized the storage spi provider id Signed-off-by: Rolain Djeumen * chore(keycloak-integration): refactoring * fix startup issues with the storage spi * removed references to slf4j to use jboss logging to align with keycloak Signed-off-by: Rolain Djeumen * chore(keycloak-integration): refactoring keycloak components * normalized keycloak integration parent bom with name kc-jans-parent Signed-off-by: Rolain Djeumen * chore(keycloak-integration): refactoring * made adjustments to the PluginConfiguration keys * keycloak configuration file to setup Signed-off-by: Rolain Djeumen * chore(keycloak-integration): refactoring * changed the kc-jans prefix for project artifacts to jans-kc Signed-off-by: Rolain Djeumen --------- Signed-off-by: Rolain Djeumen Signed-off-by: Mustafa Baser --- .../authenticator/installation.md | 62 +++ .../authenticator/pom.xml | 50 +-- .../main/java/io/jans/kc/spi/ProviderIDs.java | 6 + .../jans/kc/spi/auth/JansAuthenticator.java | 11 +- .../kc/spi/auth/JansAuthenticatorFactory.java | 4 +- ...nsAuthResponseResourceProviderFactory.java | 4 +- jans-keycloak-integration/pom.xml | 408 ++++++++++++------ jans-keycloak-integration/storage-api/pom.xml | 176 -------- .../src/main/assembly/deps-zip.xml | 26 -- .../idp/keycloak/config/JansConfigSource.java | 132 ------ .../CredentialAuthenticatingService.java | 38 -- .../RemoteUserStorageProviderFactory.java | 55 --- .../service/UsersApiLegacyService.java | 72 ---- ...lipse.microprofile.config.spi.ConfigSource | 1 - ...eycloak.storage.UserStorageProviderFactory | 1 - .../jans-keycloak-storage-api.properties | 9 - .../storage-api/src/main/resources/log4j2.xml | 36 -- .../jans/idp/keycloak/TestJenkinsRunner.java | 29 -- .../java/io/jans/jans-keycloak/AppTest.java | 38 -- .../{storage-api => storage-spi}/.gitignore | 0 jans-keycloak-integration/storage-spi/pom.xml | 100 +++++ .../storage-spi/src/assembly/dependencies.xml | 17 + .../storage/config/PluginConfiguration.java | 77 ++++ .../exception/JansConfigurationException.java | 2 +- .../CredentialAuthenticatingService.java | 42 ++ .../service/RemoteUserStorageProvider.java | 96 ++--- .../RemoteUserStorageProviderFactory.java | 57 +++ .../kc/spi/storage}/service/ScimService.java | 106 +++-- .../kc/spi/storage}/service/UserAdapter.java | 4 +- .../service/UsersApiLegacyService.java | 66 +++ .../jans/kc/spi/storage}/util/Constants.java | 3 +- .../kc/spi/storage}/util/JansDataUtil.java | 42 +- .../jans/kc/spi/storage}/util/JansUtil.java | 151 ++++--- ...eycloak.storage.UserStorageProviderFactory | 1 + .../task-scheduling/pom.xml | 108 +++++ .../src/assembly/dependencies.xml | 24 ++ .../JansTasksEventListenerProvider.java | 24 ++ ...JansTasksEventListenerProviderFactory.java | 53 +++ .../kc/spi/tasks/SamlConfigUpdateTask.java | 30 ++ ...ycloak.events.EventListenerProviderFactory | 1 + .../src/main/resources/assembly/.DONOTDELETE | 1 + .../templates/keycloak/keycloak.conf | 62 +++ 42 files changed, 1240 insertions(+), 985 deletions(-) create mode 100644 jans-keycloak-integration/authenticator/installation.md create mode 100644 jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/ProviderIDs.java delete mode 100644 jans-keycloak-integration/storage-api/pom.xml delete mode 100644 jans-keycloak-integration/storage-api/src/main/assembly/deps-zip.xml delete mode 100644 jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/config/JansConfigSource.java delete mode 100644 jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/CredentialAuthenticatingService.java delete mode 100644 jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/RemoteUserStorageProviderFactory.java delete mode 100644 jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/UsersApiLegacyService.java delete mode 100644 jans-keycloak-integration/storage-api/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource delete mode 100644 jans-keycloak-integration/storage-api/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory delete mode 100644 jans-keycloak-integration/storage-api/src/main/resources/jans-keycloak-storage-api.properties delete mode 100644 jans-keycloak-integration/storage-api/src/main/resources/log4j2.xml delete mode 100644 jans-keycloak-integration/storage-api/src/test/java/io/jans/idp/keycloak/TestJenkinsRunner.java delete mode 100644 jans-keycloak-integration/storage-api/src/test/java/io/jans/jans-keycloak/AppTest.java rename jans-keycloak-integration/{storage-api => storage-spi}/.gitignore (100%) create mode 100644 jans-keycloak-integration/storage-spi/pom.xml create mode 100644 jans-keycloak-integration/storage-spi/src/assembly/dependencies.xml create mode 100644 jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/config/PluginConfiguration.java rename jans-keycloak-integration/{storage-api/src/main/java/io/jans/idp/keycloak => storage-spi/src/main/java/io/jans/kc/spi/storage}/exception/JansConfigurationException.java (93%) create mode 100644 jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/CredentialAuthenticatingService.java rename jans-keycloak-integration/{storage-api/src/main/java/io/jans/idp/keycloak => storage-spi/src/main/java/io/jans/kc/spi/storage}/service/RemoteUserStorageProvider.java (58%) create mode 100644 jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/RemoteUserStorageProviderFactory.java rename jans-keycloak-integration/{storage-api/src/main/java/io/jans/idp/keycloak => storage-spi/src/main/java/io/jans/kc/spi/storage}/service/ScimService.java (53%) rename jans-keycloak-integration/{storage-api/src/main/java/io/jans/idp/keycloak => storage-spi/src/main/java/io/jans/kc/spi/storage}/service/UserAdapter.java (98%) create mode 100644 jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/UsersApiLegacyService.java rename jans-keycloak-integration/{storage-api/src/main/java/io/jans/idp/keycloak => storage-spi/src/main/java/io/jans/kc/spi/storage}/util/Constants.java (93%) rename jans-keycloak-integration/{storage-api/src/main/java/io/jans/idp/keycloak => storage-spi/src/main/java/io/jans/kc/spi/storage}/util/JansDataUtil.java (61%) rename jans-keycloak-integration/{storage-api/src/main/java/io/jans/idp/keycloak => storage-spi/src/main/java/io/jans/kc/spi/storage}/util/JansUtil.java (54%) create mode 100644 jans-keycloak-integration/storage-spi/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory create mode 100644 jans-keycloak-integration/task-scheduling/pom.xml create mode 100644 jans-keycloak-integration/task-scheduling/src/assembly/dependencies.xml create mode 100644 jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/events/JansTasksEventListenerProvider.java create mode 100644 jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/events/JansTasksEventListenerProviderFactory.java create mode 100644 jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/tasks/SamlConfigUpdateTask.java create mode 100644 jans-keycloak-integration/task-scheduling/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory create mode 100644 jans-keycloak-integration/task-scheduling/src/main/resources/assembly/.DONOTDELETE create mode 100644 jans-linux-setup/jans_setup/templates/keycloak/keycloak.conf diff --git a/jans-keycloak-integration/authenticator/installation.md b/jans-keycloak-integration/authenticator/installation.md new file mode 100644 index 00000000000..7726c66a146 --- /dev/null +++ b/jans-keycloak-integration/authenticator/installation.md @@ -0,0 +1,62 @@ +## Keycloak Installation configuration for use with Janssen Auth + +### 1- Brief + + This guide contains instructions on how to install keycloak for use with keycloak +and run it in a production setting alongside Janssen. + + +### 2- Keycloak and Plugins Installation + + We will be using the quarkus distribution of keycloak which can be found +[here](https://github.com/keycloak/keycloak/releases/download/22.0.3/keycloak-22.0.3.zip). +directory. +After downloading the binaries , it's suggested to unzip it in the `/opt/keycloak` directory. + +#### 2.1 - Keycloak Authentication Plugin Installation + +Installing the authentication plugin is straightforward. +It resides at the url +https://jenkins.jans.io/maven/io/jans/jans-authenticator// +Binaries of interest have to be copied to the +`/opt/keycloak/providers/` directory. They are: +- `kc-jans-authn-plugin-.jar` +- `kc-jans-authn-plugin--deps.zip`. It's contents have to +be unzipped into the directory. These are the plugin's dependencies. + +No further action is needed after copying these files. + + +### 3 - Running Keycloak + + The following assumptions will be made +- Keycloak has been installed under the directory `/opt/keycloak/` +- The Janssen Server's hostname is `janssen-with-kc.local` +- Keycloak will run behind a reverse proxy/ load balancer (e.g. apache ) + and will be listening only on the local interface on port 8092 + +From the terminal, run the following command +``` +/opt/keycloak/bin/kc.sh --log "console,file" --http-host=127.0.0.1 --http-port=8092 \ +--hostname-url=https://janssen-with-kc.local --spi-connections-http-client-default-disable-trust-manager=true \ +--proxy edge +``` + +#### 3.1 - Database Setup + By default , in a non-production environment , keycloak relies on the embedded H2 database for operation. +In a production setting, a more appropriate database needs to be deployed. +You can find a list of supported databases [here](https://www.keycloak.org/server/db). +Additional database configuration will need to be done. + + + +#### 3.2 - Reverse Proxy +As keycloak will run behind a proxy, there are a couple paths that need to be exposed (or not), with the full list +found [here](https://www.keycloak.org/server/reverseproxy). + + +### 5 - Configuration changes in Keycloak and Janssen-Auth +TBD + +### 6 - Clustering +TBD \ No newline at end of file diff --git a/jans-keycloak-integration/authenticator/pom.xml b/jans-keycloak-integration/authenticator/pom.xml index f1802904de1..484ca9aa0ea 100644 --- a/jans-keycloak-integration/authenticator/pom.xml +++ b/jans-keycloak-integration/authenticator/pom.xml @@ -1,14 +1,15 @@ - + 4.0.0 io.jans - jans-authenticator - jans-authenticator + kc-jans-authn-plugin + kc-jans-authn-plugin jar io.jans - jans-keycloak-integration-parent + jans-kc-parent 1.0.20-SNAPSHOT @@ -55,48 +56,23 @@ org.apache.maven.plugins maven-dependency-plugin - ${maven-deps-plugin.version} - - - copy - package - - copy-dependencies - - - ${project.build.directory}/deps - runtime - false - - - - org.apache.maven.plugins maven-assembly-plugin - ${maven-assembly-plugin.version} - - - src/assembly/dependencies.xml - - ${project.artifactId}-${project.version} - - - - zip-dependencies - package - - single - - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + + + diff --git a/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/ProviderIDs.java b/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/ProviderIDs.java new file mode 100644 index 00000000000..6b63e573d94 --- /dev/null +++ b/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/ProviderIDs.java @@ -0,0 +1,6 @@ +package io.jans.kc.spi; + +public class ProviderIDs { + public static final String JANS_AUTHENTICATOR_PROVIDER = "kc-jans-authn"; + public static final String JANS_AUTH_RESPONSE_REST_PROVIDER = "kc-jans-authn-rest-bridge"; +} diff --git a/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/auth/JansAuthenticator.java b/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/auth/JansAuthenticator.java index 85af3d73b93..eb5bf90378a 100644 --- a/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/auth/JansAuthenticator.java +++ b/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/auth/JansAuthenticator.java @@ -27,6 +27,7 @@ import org.keycloak.models.UserModel; import org.keycloak.models.utils.KeycloakModelUtils; +import io.jans.kc.spi.ProviderIDs; import io.jans.kc.spi.auth.oidc.OIDCAuthRequest; import io.jans.kc.spi.auth.oidc.OIDCMetaError; import io.jans.kc.spi.auth.oidc.OIDCService; @@ -52,7 +53,7 @@ public class JansAuthenticator implements Authenticator { private static final String JANS_LOGIN_URL_ATTRIBUTE = "jansLoginUrl"; private static final String OPENID_AUTH_PARAMS_ATTRIBUTE = "openIdAuthParams"; - private static final String URI_PATH_TO_REST_SERVICE = "/realms/{0}/jans-auth-bridge/auth-complete"; + private static final String URI_PATH_TO_REST_SERVICE = "/realms/{0}/{1}/auth-complete"; private OIDCService oidcService; @@ -187,6 +188,12 @@ public void close() { private Configuration extractAndValidateConfiguration(AuthenticationFlowContext context) { Configuration config = pluginConfigurationFromContext(context); + + if(config == null) { + log.debugv("Plugin probably not configured. Check the Janssen Auth plugin in the authentication flow"); + return null; + } + ValidationResult validationresult = config.validate(); if(validationresult.hasErrors()) { for(String err : validationresult.getErrors()) { @@ -201,7 +208,7 @@ private URI createRedirectUri(AuthenticationFlowContext context) { URI serverUri = context.getSession().getContext().getUri().getBaseUri(); String realmname = context.getRealm().getName(); - String rest_svc_uri = MessageFormat.format(URI_PATH_TO_REST_SERVICE,realmname); + String rest_svc_uri = MessageFormat.format(URI_PATH_TO_REST_SERVICE,realmname,ProviderIDs.JANS_AUTH_RESPONSE_REST_PROVIDER); return serverUri.resolve(rest_svc_uri); } diff --git a/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/auth/JansAuthenticatorFactory.java b/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/auth/JansAuthenticatorFactory.java index dc628236f07..6a49c9cba92 100644 --- a/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/auth/JansAuthenticatorFactory.java +++ b/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/auth/JansAuthenticatorFactory.java @@ -15,6 +15,7 @@ import org.keycloak.provider.ProviderConfigProperty; +import io.jans.kc.spi.ProviderIDs; import io.jans.kc.spi.auth.oidc.OIDCMetaCache; import io.jans.kc.spi.auth.oidc.OIDCService; import io.jans.kc.spi.auth.oidc.impl.HashBasedOIDCMetaCache; @@ -23,7 +24,8 @@ public class JansAuthenticatorFactory implements AuthenticatorFactory { - private static final String PROVIDER_ID = "janssen-auth"; + private static final String PROVIDER_ID = ProviderIDs.JANS_AUTHENTICATOR_PROVIDER; + private static final String DISPLAY_TYPE = "Janssen Authenticator"; private static final String REFERENCE_CATEGORY = "Janssen Authenticator"; private static final String HELP_TEXT= "Janssen authenticator for Keycloak"; diff --git a/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/rest/JansAuthResponseResourceProviderFactory.java b/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/rest/JansAuthResponseResourceProviderFactory.java index 1a08e254197..8384f1bf782 100644 --- a/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/rest/JansAuthResponseResourceProviderFactory.java +++ b/jans-keycloak-integration/authenticator/src/main/java/io/jans/kc/spi/rest/JansAuthResponseResourceProviderFactory.java @@ -7,9 +7,11 @@ import org.keycloak.services.resource.RealmResourceProvider; import org.keycloak.services.resource.RealmResourceProviderFactory; +import io.jans.kc.spi.ProviderIDs; + public class JansAuthResponseResourceProviderFactory implements RealmResourceProviderFactory { - private static final String ID = "janssen-auth-response-bridge"; + private static final String ID = ProviderIDs.JANS_AUTH_RESPONSE_REST_PROVIDER; @Override public String getId() { diff --git a/jans-keycloak-integration/pom.xml b/jans-keycloak-integration/pom.xml index 55877d6b844..54850761e03 100644 --- a/jans-keycloak-integration/pom.xml +++ b/jans-keycloak-integration/pom.xml @@ -1,126 +1,284 @@ - - - 4.0.0 - io.jans - jans-keycloak-integration-parent - pom - 1.0.20-SNAPSHOT - jans-keycloak-integration-parent - - - - github - Github Packages - https://maven.pkg.github.com/JanssenProject/jans - - - - - 3.3.9 - 11 - 11 - 3.10.1 - ${project.version} - 21.1.1 - 10.11 - 3.6.0 - 3.6.0 - 10.11 - JanssenProject_keycloak-integ - ${project.groupId}:${project - .artifactId} - janssenproject - https://sonarcloud.io - - - - ${maven.min-version} - - - - authenticator - storage-api - - - - - jans - Janssen project repository - https://maven.jans.io/maven - - - jans.io - Janssen project repository - https://jenkins.jans.io/maven/ - - - - - https://github.com/JanssenProject/jans - scm:git:git://github.com/JanssenProject/jans.git - scm:git:git@github.com:JanssenProject/jans.git - - - - - - - io.jans - jans-bom - ${jans.version} - import - pom - - - - - org.keycloak - - keycloak-core - provided - - ${keycloak-server-spi.version} - - - - - org.keycloak - keycloak-server-spi - - provided - ${keycloak-server-spi.version} - - - - - org.keycloak - keycloak-server-spi-private - - provided - ${keycloak-server-spi.version} - - - - - org.keycloak - keycloak-services - provided - - ${keycloak-server-spi.version} - - - - - - - com.nimbusds - oauth2-oidc-sdk - - ${nimbus.oauth2-oidc-sdk.version} - - - - + + + 4.0.0 + io.jans + jans-kc-parent + pom + 1.0.20-SNAPSHOT + keycloak-integration-parent + + + + github + Github Packages + https://maven.pkg.github.com/JanssenProject/jans + + + + + 3.3.9 + 11 + 11 + 21.1.1 + 10.11 + 10.11 + 1.8 + ${project.version} + 3.0.0 + 6.0.0 + 3.0.0-RC1 + 2.19.0 + 1.7.36 + 2.12.6 + 3.13.0 + 4.1 + 2.2.7 + 3.2.0 + 3.11.0 + 3.6.0 + 3.6.0 + JanssenProject_keycloak-integ + ${project.groupId}:${project.artifactId} + janssenproject + https://sonarcloud.io + + + + ${maven.min-version} + + + + authenticator + storage-spi + task-scheduling + + + + + jans.io + Janssen project repository + https://jenkins.jans.io/maven/ + + + + mavencentral + maven central + https://repo1.maven.org/maven2 + + + + + https://github.com/JanssenProject/keycloak-integration-jans + scm:git:git://github.com/JanssenProject/keycloak-integration-jans + scm:git:git@github.com:v/keycloak-integration-jans.git + + + + + + + org.keycloak + keycloak-core + provided + ${keycloak-server-spi.version} + + + + org.keycloak + keycloak-server-spi + provided + ${keycloak-server-spi.version} + + + + org.keycloak + keycloak-server-spi-private + provided + ${keycloak-server-spi.version} + + + + org.keycloak + keycloak-services + provided + ${keycloak-server-spi.version} + + + + org.keycloak + keycloak-model-legacy + provided + ${keycloak-server-spi.version} + + + + + + + com.nimbusds + oauth2-oidc-sdk + ${nimbus.oauth2-oidc-sdk.version} + + + + + + io.jans + jans-scim-model + ${jans.version} + + + + + + jakarta.ws.rs + jakarta.ws.rs-api + ${jakarta.ws-rs-api.version} + provided + + + jakarta.servlet + jakarta.servlet-api + ${jakarta.servlet-api.version} + + + + + + + io.smallrye.config + smallrye-config + ${smallrye-config.version} + + + + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + + + + org.apache.commons + commons-lang3 + ${commons-lang.version} + + + org.apache.commons + commons-collections4 + ${commons-collection.version} + + + + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + ${fasterxml-jackson.version} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${fasterxml-jackson.version} + + + + + + io.swagger.core.v3 + swagger-core-jakarta + ${swagger.version} + + + + + + + + + + + + org.apache.maven.plugins + maven-clean-plugin + ${maven-clean-plugin.version} + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-deps-plugin.version} + + + copy + package + + copy-dependencies + + + ${project.build.directory}/deps/ + runtime + false + + com.sun.activation, + jakarta.activation, + jakarta.annotation, + jakarta.servlet, + jakarta.validation, + jakarta.xml.bind, + org.jboss.resteasy + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + src/assembly/dependencies.xml + + ${project.artifactId}-${project.version} + + + + zip-dependencies + package + + single + + + + + + + + diff --git a/jans-keycloak-integration/storage-api/pom.xml b/jans-keycloak-integration/storage-api/pom.xml deleted file mode 100644 index 33035a29182..00000000000 --- a/jans-keycloak-integration/storage-api/pom.xml +++ /dev/null @@ -1,176 +0,0 @@ - - - - 4.0.0 - jans-keycloak-storage-api - jans-keycloak-storage-api - jar - - - io.jans - jans-keycloak-integration-parent - 1.0.20-SNAPSHOT - - - - ${maven.min-version} - - - 3.0.0-RC1 - 2.19.0 - 1.7.36 - 4.4 - 1.8 - - - - - - - io.jans - jans-scim-model - ${jans.version} - - - - - jakarta.ws.rs - jakarta.ws.rs-api - - - jakarta.servlet - jakarta.servlet-api - - - - - org.keycloak - keycloak-core - - - org.keycloak - keycloak-server-spi - - - org.keycloak - keycloak-model-legacy - ${keycloak-server-spi.version} - - - - - - io.smallrye.config - smallrye-config - ${smallrye.config.version} - - - - - org.apache.logging.log4j - log4j-api - - - org.apache.logging.log4j - log4j-core - - - org.slf4j - slf4j-log4j12 - - - - - commons-collections - commons-collections - - - commons-lang - commons-lang - - - - - org.apache.commons - commons-collections4 - ${commons.lang.version} - - - - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-base - 2.12.6 - - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-json-provider - 2.12.6 - - - - - - - jans-keycloak-storage-api - - - - src/main/resources - true - - **/*.xml - **/*.properties - **/*.json - META-INF/services/*.* - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - ${maven-deps-plugin.version} - - - copy - package - - copy-dependencies - - - ${project.build.directory}/deps - runtime - false - - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - false - - src/main/assembly/deps-zip.xml - - - - - - - - - - diff --git a/jans-keycloak-integration/storage-api/src/main/assembly/deps-zip.xml b/jans-keycloak-integration/storage-api/src/main/assembly/deps-zip.xml deleted file mode 100644 index 31321b50e74..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/assembly/deps-zip.xml +++ /dev/null @@ -1,26 +0,0 @@ - - distribution - - zip - - false - - - - io.jans:jans-scim-model - commons-collections:commons-collections - commons-lang:commons-lang - jakarta.ws.rs:jakarta.ws.rs-api - com.fasterxml.jackson.jaxrs:jackson-jaxrs-base - com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider - org.json:json - org.apache.commons:commons-collections4 - org.apache.logging.log4j:log4j-api - org.apache.logging.log4j:log4j-core - - runtime - - - \ No newline at end of file diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/config/JansConfigSource.java b/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/config/JansConfigSource.java deleted file mode 100644 index 3d180dac9f0..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/config/JansConfigSource.java +++ /dev/null @@ -1,132 +0,0 @@ -package io.jans.idp.keycloak.config; - -import io.jans.idp.keycloak.util.Constants; - -import java.io.FileInputStream; -import java.nio.file.FileSystems; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.eclipse.microprofile.config.spi.ConfigSource; -import org.keycloak.component.ComponentValidationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class JansConfigSource implements ConfigSource { - - private static Logger logger = LoggerFactory.getLogger(JansConfigSource.class); - private static final String CONFIG_FILE_NAME = "jans-keycloak-storage-api.properties"; - - private String configFilePath = null; - private Properties properties = null; - private Map propertiesMap = new HashMap<>(); - - public JansConfigSource() { - this.configFilePath = System.getProperty(Constants.JANS_CONFIG_PROP_PATH); - logger.info("this.configFilePath:{}", configFilePath); - - if (StringUtils.isBlank(configFilePath)) { - throw new ComponentValidationException( - "Configuration property file path `System property` not set, please verify."); - } - - this.loadProperties(); - } - - @Override - public Map getProperties() { - logger.info("\n\n Getting properties \n\n"); - return propertiesMap; - } - - @Override - public Set getPropertyNames() { - logger.debug("\n\n Getting Property Names \n\n"); - try { - return properties.stringPropertyNames(); - - } catch (Exception e) { - logger.error("Unable to read properties from CONFIG_FILE_NAME:{} - error is :{}", CONFIG_FILE_NAME, e); - } - return Collections.emptySet(); - } - - @Override - public int getOrdinal() { - return 800; - } - - @Override - public String getValue(String name) { - try { - logger.trace("JansConfigSource()::getValue() - name:{} - :{}", name, properties.getProperty(name)); - return properties.getProperty(name); - } catch (Exception e) { - logger.error("Unable to read properties from file:{} - error is :{} ", CONFIG_FILE_NAME, e); - } - - return null; - } - - @Override - public String getName() { - return CONFIG_FILE_NAME; - } - - public String getQualifiedFileName() { - String fileSeparator = FileSystems.getDefault().getSeparator(); - logger.info("\n\n JansConfigSource()::getQualifiedFileName() - fileSeparator:{}", fileSeparator); - return this.configFilePath + fileSeparator + CONFIG_FILE_NAME; - } - - private Properties loadProperties() { - logger.info("\n\n\n ***** JansConfigSource::loadProperties() - Properties form Config.Scope "); - - // Get file path - String filePath = getQualifiedFileName(); - logger.info("\n\n\n ***** JansConfigSource::loadProperties() - properties:{}, filePath:{}", properties, filePath); - - if (StringUtils.isBlank(filePath)) { - logger.error("Property filePath is null!"); - throw new ComponentValidationException("Config property filePath is null!!!"); - } - - // load the file handle for main.properties - try (FileInputStream file = new FileInputStream(filePath)) { - logger.info(" JansConfigSource::loadProperties() - file:{}", file); - - // load all the properties from this file - properties = new Properties(); - properties.load(file); - properties.stringPropertyNames().stream() - .forEach(key -> propertiesMap.put(key, properties.getProperty(key))); - - logger.debug("JansConfigSource()::loadProperties() - properties :{}", properties); - - if (properties.isEmpty()) { - logger.error("Could not load config properties!"); - throw new ComponentValidationException("Could not load config properties!!!"); - } - - printProperties(properties); - - } catch (Exception ex) { - logger.error("Failed to load property file", ex); - throw new ComponentValidationException("Failed to load property file!!!"); - } - - return properties; - } - - private static void printProperties(Properties prop) { - if (prop == null || prop.isEmpty()) { - return; - } - prop.keySet().stream().map(key -> key + ": " + prop.getProperty(key.toString())).forEach(logger::debug); - } - -} diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/CredentialAuthenticatingService.java b/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/CredentialAuthenticatingService.java deleted file mode 100644 index 02ca05773d0..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/CredentialAuthenticatingService.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.jans.idp.keycloak.service; - -import io.jans.idp.keycloak.util.Constants; -import io.jans.idp.keycloak.util.JansUtil; - -import jakarta.ws.rs.core.MediaType; - -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CredentialAuthenticatingService { - - private static Logger logger = LoggerFactory.getLogger(CredentialAuthenticatingService.class); - private static JansUtil jansUtil = new JansUtil(); - - public boolean authenticateUser(final String username, final String password) { - logger.info("CredentialAuthenticatingService::authenticateUser() - username:{}, password:{} ", username, - password); - boolean isValid = false; - try { - - String token = jansUtil.requestUserToken(jansUtil.getTokenEndpoint(), username, password, null, - Constants.RESOURCE_OWNER_PASSWORD_CREDENTIALS, null, MediaType.APPLICATION_FORM_URLENCODED); - - logger.info("CredentialAuthenticatingService::authenticateUser() - Final token token - {}", token); - - if (StringUtils.isNotBlank(token)) { - isValid = true; - } - } catch (Exception ex) { - ex.printStackTrace(); - logger.error("CredentialAuthenticatingService::authenticateUser() - Error while authenticating is ", ex); - } - return isValid; - } - -} diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/RemoteUserStorageProviderFactory.java b/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/RemoteUserStorageProviderFactory.java deleted file mode 100644 index a90971b3cc4..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/RemoteUserStorageProviderFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.jans.idp.keycloak.service; - -import io.jans.idp.keycloak.util.Constants; - -import org.keycloak.Config; -import org.keycloak.component.ComponentModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.storage.UserStorageProviderFactory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RemoteUserStorageProviderFactory implements UserStorageProviderFactory { - - private static Logger logger = LoggerFactory.getLogger(RemoteUserStorageProviderFactory.class); - public static final String PROVIDER_NAME = "jans-keycloak-storage-api"; - - @Override - public RemoteUserStorageProvider create(KeycloakSession session, ComponentModel model) { - logger.info("RemoteUserStorageProviderFactory::create() - session:{}, model:{}", session, model); - return new RemoteUserStorageProvider(session, model); - } - - @Override - public String getId() { - String id = PROVIDER_NAME; - logger.info("id:{}", id); - - return id; - } - - @Override - public String getHelpText() { - return "Jans Remote User Provider"; - } - - @Override - public void init(Config.Scope config) { - logger.info( - "RemoteUserStorageProviderFactory::init() - config:{}, System.getProperty(Constants.JANS_CONFIG_PROP_PATH):{}", - config, System.getProperty(Constants.JANS_CONFIG_PROP_PATH)); - } - - @Override - public void postInit(KeycloakSessionFactory factory) { - logger.info("RemoteUserStorageProviderFactory::postInit() - config:{}", factory); - } - - @Override - public void close() { - logger.info("RemoteUserStorageProviderFactory::close() - Exit"); - } - -} diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/UsersApiLegacyService.java b/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/UsersApiLegacyService.java deleted file mode 100644 index b028013be5b..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/UsersApiLegacyService.java +++ /dev/null @@ -1,72 +0,0 @@ -package io.jans.idp.keycloak.service; - -import io.jans.scim.model.scim2.user.UserResource; - -import java.util.Properties; - -import org.keycloak.component.ComponentModel; -import org.keycloak.models.KeycloakSession; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class UsersApiLegacyService { - - private static Logger logger = LoggerFactory.getLogger(UsersApiLegacyService.class); - private ScimService scimService = new ScimService(); - - private KeycloakSession session; - private ComponentModel model; - protected Properties jansProperties = new Properties(); - - public UsersApiLegacyService(KeycloakSession session, ComponentModel model) { - logger.info(" UsersApiLegacyService() - session:{}, model:{}", session, model); - - this.session = session; - this.model = model; - } - - public UserResource getUserById(String inum) { - logger.info("UsersApiLegacyService::getUserById() - inum:{}", inum); - try { - return scimService.getUserById(inum); - } catch (Exception ex) { - ex.printStackTrace(); - logger.error( - "UsersApiLegacyService::getUserById() - Error fetching user based on inum:{} from external service is:{} - {} ", - inum, ex.getMessage(), ex); - - } - return null; - } - - public UserResource getUserByName(String username) { - logger.info(" UsersApiLegacyService::getUserByName() - username:{}", username); - try { - - return scimService.getUserByName(username); - } catch (Exception ex) { - ex.printStackTrace(); - logger.error( - "UsersApiLegacyService::getUserByName() - Error fetching user based on username:{} from external service is:{} - {} ", - username, ex.getMessage(), ex); - - } - return null; - } - - public UserResource getUserByEmail(String email) { - logger.info(" UsersApiLegacyService::getUserByEmail() - email:{}", email); - try { - - return scimService.getUserByEmail(email); - } catch (Exception ex) { - ex.printStackTrace(); - logger.error( - " UsersApiLegacyService::getUserByEmail() - Error fetching user based on email:{} from external service is:{} - {} ", - email, ex.getMessage(), ex); - - } - return null; - } - -} diff --git a/jans-keycloak-integration/storage-api/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource b/jans-keycloak-integration/storage-api/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource deleted file mode 100644 index fb31e7be233..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource +++ /dev/null @@ -1 +0,0 @@ -io.jans.idp.keycloak.config.JansConfigSource \ No newline at end of file diff --git a/jans-keycloak-integration/storage-api/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory b/jans-keycloak-integration/storage-api/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory deleted file mode 100644 index af5dd9ee27e..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory +++ /dev/null @@ -1 +0,0 @@ -io.jans.idp.keycloak.service.RemoteUserStorageProviderFactory \ No newline at end of file diff --git a/jans-keycloak-integration/storage-api/src/main/resources/jans-keycloak-storage-api.properties b/jans-keycloak-integration/storage-api/src/main/resources/jans-keycloak-storage-api.properties deleted file mode 100644 index 292f8cf82fd..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/resources/jans-keycloak-storage-api.properties +++ /dev/null @@ -1,9 +0,0 @@ -# Sample properties -keycloak.server.url=https://${keycloack_hostname} -auth.token.endpoint=https://${hostname}/jans-auth/restv1/token -scim.user.endpoint=https://${hostname}/jans-scim/restv1/v2/Users -scim.user.search.endpoint=https://${hostname}/jans-scim/restv1/v2/Users/.search -scim.oauth.scope=https://jans.io/scim/users.read -keycloak.scim.client.id=${saml_scim_client_id} -keycloak.scim.client.password=${saml_scim_client_pw} - diff --git a/jans-keycloak-integration/storage-api/src/main/resources/log4j2.xml b/jans-keycloak-integration/storage-api/src/main/resources/log4j2.xml deleted file mode 100644 index d6f099dc2f6..00000000000 --- a/jans-keycloak-integration/storage-api/src/main/resources/log4j2.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jans-keycloak-integration/storage-api/src/test/java/io/jans/idp/keycloak/TestJenkinsRunner.java b/jans-keycloak-integration/storage-api/src/test/java/io/jans/idp/keycloak/TestJenkinsRunner.java deleted file mode 100644 index cd56722799c..00000000000 --- a/jans-keycloak-integration/storage-api/src/test/java/io/jans/idp/keycloak/TestJenkinsRunner.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2020, Janssen Project - */ - -package io.jans.idp.keycloak; - -import org.apache.commons.io.FileUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class TestJenkinsRunner { - - void testParallel() { - - } - - public static void generateReport(String karateOutputPath) { - - } -} diff --git a/jans-keycloak-integration/storage-api/src/test/java/io/jans/jans-keycloak/AppTest.java b/jans-keycloak-integration/storage-api/src/test/java/io/jans/jans-keycloak/AppTest.java deleted file mode 100644 index a0198b7ac3d..00000000000 --- a/jans-keycloak-integration/storage-api/src/test/java/io/jans/jans-keycloak/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.jans.jans-keycloak; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git a/jans-keycloak-integration/storage-api/.gitignore b/jans-keycloak-integration/storage-spi/.gitignore similarity index 100% rename from jans-keycloak-integration/storage-api/.gitignore rename to jans-keycloak-integration/storage-spi/.gitignore diff --git a/jans-keycloak-integration/storage-spi/pom.xml b/jans-keycloak-integration/storage-spi/pom.xml new file mode 100644 index 00000000000..302ce39e84d --- /dev/null +++ b/jans-keycloak-integration/storage-spi/pom.xml @@ -0,0 +1,100 @@ + + + + 4.0.0 + kc-jans-storage-plugin + kc-jans-storage-plugin + jar + + + io.jans + jans-kc-parent + 1.0.20-SNAPSHOT + + + + + + + io.jans + jans-scim-model + + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + jakarta.servlet + jakarta.servlet-api + + + + + org.keycloak + keycloak-core + + + org.keycloak + keycloak-server-spi + + + org.keycloak + keycloak-model-legacy + + + + + org.apache.commons + commons-collections4 + + + org.apache.commons + commons-lang3 + + + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + + + + + + io.swagger.core.v3 + swagger-core-jakarta + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + diff --git a/jans-keycloak-integration/storage-spi/src/assembly/dependencies.xml b/jans-keycloak-integration/storage-spi/src/assembly/dependencies.xml new file mode 100644 index 00000000000..392faa3826e --- /dev/null +++ b/jans-keycloak-integration/storage-spi/src/assembly/dependencies.xml @@ -0,0 +1,17 @@ + + deps + + zip + + false + + + target/deps/ + . + + *.jar + + + + \ No newline at end of file diff --git a/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/config/PluginConfiguration.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/config/PluginConfiguration.java new file mode 100644 index 00000000000..898370f0743 --- /dev/null +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/config/PluginConfiguration.java @@ -0,0 +1,77 @@ +package io.jans.kc.spi.storage.config; + +import org.keycloak.Config; + +public class PluginConfiguration { + + private static final String AUTH_TOKEN_ENDPOINT_KEY = "jans-storage-auth-token-endpoint"; + private static final String SCIM_USER_ENDPOINT_KEY = "jans-storage-scim-user-endpoint"; + private static final String SCIM_USER_SEARCH_ENDPOINT_KEY = "jans-storage-scim-user-search-endpoint"; + private static final String SCIM_OAUTH_SCOPE_KEY = "jans-storage-scim-oauth-scope"; + private static final String SCIM_CLIENT_ID_KEY = "jans-storage-scim-client-id"; + private static final String SCIM_CLIENT_SECRET = "jans-storage-scim-client-secret"; + + private String authTokenEndpoint; + private String scimUserEndpoint; + private String scimUserSearchEndpoint; + private String scimOauthScope; + private String scimClientId; + private String scimClientSecret; + + private PluginConfiguration() { + + } + + public static PluginConfiguration fromKeycloakConfiguration(Config.Scope config) { + + PluginConfiguration ret = new PluginConfiguration(); + ret.authTokenEndpoint = config.get(AUTH_TOKEN_ENDPOINT_KEY); + ret.scimUserEndpoint = config.get(SCIM_USER_ENDPOINT_KEY); + ret.scimUserSearchEndpoint = config.get(SCIM_USER_SEARCH_ENDPOINT_KEY); + ret.scimOauthScope = config.get(SCIM_OAUTH_SCOPE_KEY); + ret.scimClientId = config.get(SCIM_CLIENT_ID_KEY); + ret.scimClientSecret = config.get(SCIM_CLIENT_SECRET); + return ret; + } + + public String getAuthTokenEndpoint() { + + return authTokenEndpoint; + } + + public String getScimUserEndpoint() { + + return scimUserEndpoint; + } + + + public String getScimUserSearchEndpoint() { + + return scimUserSearchEndpoint; + } + + public String getScimOauthScope() { + + return scimOauthScope; + } + + public String getScimClientId() { + + return scimClientId; + } + + public String getScimClientSecret() { + + return scimClientSecret; + } + + public boolean isValid() { + + return authTokenEndpoint != null + && scimUserEndpoint != null + && scimUserSearchEndpoint != null + && scimOauthScope != null + && scimClientId != null + && scimClientSecret != null; + } +} diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/exception/JansConfigurationException.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/exception/JansConfigurationException.java similarity index 93% rename from jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/exception/JansConfigurationException.java rename to jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/exception/JansConfigurationException.java index f7b45366821..e4461547a96 100644 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/exception/JansConfigurationException.java +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/exception/JansConfigurationException.java @@ -4,7 +4,7 @@ * Copyright (c) 2020, Janssen Project */ -package io.jans.idp.keycloak.exception; +package io.jans.kc.spi.storage.exception; public class JansConfigurationException extends RuntimeException { diff --git a/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/CredentialAuthenticatingService.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/CredentialAuthenticatingService.java new file mode 100644 index 00000000000..14fc98309c3 --- /dev/null +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/CredentialAuthenticatingService.java @@ -0,0 +1,42 @@ +package io.jans.kc.spi.storage.service; + +import io.jans.kc.spi.storage.util.Constants; +import io.jans.kc.spi.storage.util.JansUtil; + +import jakarta.ws.rs.core.MediaType; + +import org.apache.commons.lang.StringUtils; + +import org.jboss.logging.Logger; + +public class CredentialAuthenticatingService { + + private static Logger log = Logger.getLogger(CredentialAuthenticatingService.class); + + private JansUtil jansUtil; + + public CredentialAuthenticatingService(JansUtil jansUtil) { + this.jansUtil = jansUtil; + } + + public boolean authenticateUser(final String username, final String password) { + log.debugv("CredentialAuthenticatingService::authenticateUser() - username:{0}, password:{1} ", username, + password); + boolean isValid = false; + try { + + String token = jansUtil.requestUserToken(jansUtil.getTokenEndpoint(), username, password, null, + Constants.RESOURCE_OWNER_PASSWORD_CREDENTIALS, null, MediaType.APPLICATION_FORM_URLENCODED); + + log.debugv("CredentialAuthenticatingService::authenticateUser() - Final token token - {0}", token); + + if (StringUtils.isNotBlank(token)) { + isValid = true; + } + } catch (Exception ex) { + log.debug("CredentialAuthenticatingService::authenticateUser() - Error while authenticating", ex); + } + return isValid; + } + +} diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/RemoteUserStorageProvider.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/RemoteUserStorageProvider.java similarity index 58% rename from jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/RemoteUserStorageProvider.java rename to jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/RemoteUserStorageProvider.java index 7cc72863939..3a70142e225 100644 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/RemoteUserStorageProvider.java +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/RemoteUserStorageProvider.java @@ -1,5 +1,7 @@ -package io.jans.idp.keycloak.service; +package io.jans.kc.spi.storage.service; +import io.jans.kc.spi.storage.config.PluginConfiguration; +import io.jans.kc.spi.storage.util.JansUtil; import io.jans.scim.model.scim2.user.UserResource; import org.keycloak.component.ComponentModel; @@ -13,49 +15,50 @@ import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.user.UserLookupProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.jboss.logging.Logger; + public class RemoteUserStorageProvider implements CredentialInputValidator, UserLookupProvider, UserStorageProvider { - private static Logger logger = LoggerFactory.getLogger(RemoteUserStorageProvider.class); + private static Logger log = Logger.getLogger(RemoteUserStorageProvider.class); private KeycloakSession session; private ComponentModel model; private UsersApiLegacyService usersService; - private CredentialAuthenticatingService credentialAuthenticatingService = new CredentialAuthenticatingService(); - - public RemoteUserStorageProvider(KeycloakSession session, ComponentModel model) { - logger.info("RemoteUserStorageProvider() - session:{}, model:{}", session, model); + private CredentialAuthenticatingService credentialAuthenticatingService; + public RemoteUserStorageProvider(KeycloakSession session, ComponentModel model, PluginConfiguration pluginConfiguration) { + log.debugv("RemoteUserStorageProvider() - session:{0}, model:{1}", session, model); + JansUtil jansUtil = new JansUtil(pluginConfiguration); this.session = session; this.model = model; - this.usersService = new UsersApiLegacyService(session, model); + this.usersService = new UsersApiLegacyService(session, model,new ScimService(jansUtil)); + this.credentialAuthenticatingService = new CredentialAuthenticatingService(jansUtil); } @Override public boolean supportsCredentialType(String credentialType) { - logger.info("RemoteUserStorageProvider::supportsCredentialType() - credentialType:{}", credentialType); + log.debugv("RemoteUserStorageProvider::supportsCredentialType() - credentialType:{0}", credentialType); return PasswordCredentialModel.TYPE.equals(credentialType); } @Override public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) { - logger.info("RemoteUserStorageProvider::isConfiguredFor() - realm:{}, user:{}, credentialType:{} ", realm, user, + log.debugv("RemoteUserStorageProvider::isConfiguredFor() - realm:{0}, user:{1}, credentialType:{2} ", realm, user, credentialType); return user.credentialManager().isConfiguredFor(credentialType); } @Override public boolean isValid(RealmModel realm, UserModel user, CredentialInput credentialInput) { - logger.info( - "RemoteUserStorageProvider::isValid() - realm:{}, user:{}, credentialInput:{}, user.getUsername():{}, credentialInput.getChallengeResponse():{}", + log.debugv( + "RemoteUserStorageProvider::isValid() - realm:{0}, user:{1}, credentialInput:{2}, user.getUsername():{2}, credentialInput.getChallengeResponse():{}", realm, user, credentialInput, user.getUsername(), credentialInput.getChallengeResponse()); boolean valid = credentialAuthenticatingService.authenticateUser(user.getUsername(), credentialInput.getChallengeResponse()); - logger.info("RemoteUserStorageProvider::isValid() - valid:{}", valid); + log.debugv("RemoteUserStorageProvider::isValid() - valid:{0}", valid); return valid; @@ -65,32 +68,31 @@ public boolean isValid(RealmModel realm, UserModel user, CredentialInput credent * Get user based on id */ public UserModel getUserById(RealmModel paramRealmModel, String id) { - logger.info("RemoteUserStorageProvider::getUserById() - paramRealmModel:{}, id:{}", paramRealmModel, id); + log.debugv("RemoteUserStorageProvider::getUserById() - paramRealmModel:{0}, id:{1}", paramRealmModel, id); UserModel userModel = null; try { UserResource user = usersService.getUserById(StorageId.externalId(id)); - logger.info("RemoteUserStorageProvider::getUserById() - user fetched based on id:{} is user:{}", id, user); + log.debugv("RemoteUserStorageProvider::getUserById() - user fetched based on id:{0} is user:{1}", id, user); if (user != null) { userModel = createUserModel(paramRealmModel, user); - logger.info(" RemoteUserStorageProvider::getUserById() - userModel:{}", userModel); + log.debugv(" RemoteUserStorageProvider::getUserById() - userModel:{0}", userModel); if (userModel != null) { - logger.info( - "RemoteUserStorageProvider::getUserById() - Final userModel fetched with id:{}, userModel:{}, userModel.getAttributes(:{})", + log.debugv( + "RemoteUserStorageProvider::getUserById() - Final userModel fetched with id:{0}, userModel:{1}, userModel.getAttributes(:{2})", id, userModel, userModel.getAttributes()); } } - logger.info( - "RemoteUserStorageProvider::getUserById() - User fetched with id:{} from external service is:{}", + log.debugv( + "RemoteUserStorageProvider::getUserById() - User fetched with id:{0} from external service is:{1}", id, user); } catch (Exception ex) { - ex.printStackTrace(); - logger.error( - "RemoteUserStorageProvider::getUserById() - Error fetching user id:{} from external service is:{} - {} ", - id, ex.getMessage(), ex); + log.errorv(ex, + "RemoteUserStorageProvider::getUserById() - Error fetching user id:{0} from external service", + id); } @@ -101,78 +103,76 @@ public UserModel getUserById(RealmModel paramRealmModel, String id) { * Get user based on name */ public UserModel getUserByUsername(RealmModel paramRealmModel, String name) { - logger.info("RemoteUserStorageProvider::getUserByUsername() - paramRealmModel:{}, name:{}", paramRealmModel, + log.debugv("RemoteUserStorageProvider::getUserByUsername() - paramRealmModel:{0}, name:{1}", paramRealmModel, name); UserModel userModel = null; try { UserResource user = usersService.getUserByName(name); - logger.info( - "RemoteUserStorageProvider::getUserByUsername() - User fetched with name:{} from external service is:{}", + log.debugv( + "RemoteUserStorageProvider::getUserByUsername() - User fetched with name:{0} from external service is:{1}", name, user); if (user != null) { userModel = createUserModel(paramRealmModel, user); - logger.info("RemoteUserStorageProvider::getUserByUsername() - userModel:{}", userModel); + log.debugv("RemoteUserStorageProvider::getUserByUsername() - userModel:{0}", userModel); } if (userModel != null) { - logger.info( - "RemoteUserStorageProvider::getUserByUsername() - Final User fetched with name:{}, userModel:{}, userModel.getAttributes():{}", + log.debugv( + "RemoteUserStorageProvider::getUserByUsername() - Final User fetched with name:{0}, userModel:{1}, userModel.getAttributes():{2}", name, userModel, userModel.getAttributes()); } } catch (Exception ex) { - ex.printStackTrace(); - logger.error( - "\n RemoteUserStorageProvider::getUserByUsername() - Error fetching user name:{}, from external service is:{} - {} ", - name, ex.getMessage(), ex); + log.errorv(ex, + "\n RemoteUserStorageProvider::getUserByUsername() - Error fetching user name:{0}", + name); } return userModel; } public UserModel getUserByEmail(RealmModel paramRealmModel, String email) { - logger.info("RemoteUserStorageProvider::getUserByEmail() - paramRealmModel:{}, email:{}", paramRealmModel, + log.debugv("RemoteUserStorageProvider::getUserByEmail() - paramRealmModel:{0}, email:{1}", paramRealmModel, email); UserModel userModel = null; try { UserResource user = usersService.getUserByEmail(email); - logger.info( - "RemoteUserStorageProvider::getUserByEmail() - User fetched with email:{} from external service is:{}", + log.debugv( + "RemoteUserStorageProvider::getUserByEmail() - User fetched with email:{0} from external service is:{1}", email, user); if (user != null) { userModel = createUserModel(paramRealmModel, user); - logger.info("RemoteUserStorageProvider::getUserByEmail() - userModel:{}", userModel); + log.debugv("RemoteUserStorageProvider::getUserByEmail() - userModel:{0}", userModel); } if (userModel != null) { - logger.info( - "RemoteUserStorageProvider::getUserByEmail() - Final User fetched with email:{}, userModel:{}, userModel.getAttributes(:{})", + log.debugv( + "RemoteUserStorageProvider::getUserByEmail() - Final User fetched with email:{0}, userModel:{1}, userModel.getAttributes(:{2})", email, userModel, userModel.getAttributes()); } } catch (Exception ex) { - ex.printStackTrace(); - logger.error( - "\n RemoteUserStorageProvider::getUserByEmail() - Error fetching user email:{}, from external service is:{} - {} ", - email, ex.getMessage(), ex); + log.errorv(ex, + "RemoteUserStorageProvider::getUserByEmail() - Error fetching user email:{0}", + email); } return userModel; } public void close() { - logger.info("RemoteUserStorageProvider::close()"); + log.debug("RemoteUserStorageProvider::close()"); } private UserModel createUserModel(RealmModel realm, UserResource user) { - logger.info("RemoteUserStorageProvider::createUserModel() - realm:{} , user:{}", realm, user); + log.debugv("RemoteUserStorageProvider::createUserModel() - realm:{0} , user:{1}", realm, user); UserModel userModel = new UserAdapter(session, realm, model, user); - logger.info("Final RemoteUserStorageProvider::createUserModel() - userModel:{}", userModel); + log.debugv("Final RemoteUserStorageProvider::createUserModel() - userModel:{0}", userModel); return userModel; } diff --git a/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/RemoteUserStorageProviderFactory.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/RemoteUserStorageProviderFactory.java new file mode 100644 index 00000000000..77a1c8fbeae --- /dev/null +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/RemoteUserStorageProviderFactory.java @@ -0,0 +1,57 @@ +package io.jans.kc.spi.storage.service; + +import io.jans.kc.spi.storage.config.PluginConfiguration; +import io.jans.kc.spi.storage.util.Constants; + +import org.jboss.logging.Logger; + +import org.keycloak.Config; +import org.keycloak.component.ComponentModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.storage.UserStorageProviderFactory; + + + + +public class RemoteUserStorageProviderFactory implements UserStorageProviderFactory { + + private static Logger log = Logger.getLogger(RemoteUserStorageProviderFactory.class); + + public static final String PROVIDER_NAME = "jans-keycloak-storage-api"; + private PluginConfiguration pluginConfiguration; + + @Override + public RemoteUserStorageProvider create(KeycloakSession session, ComponentModel model) { + log.debugv("RemoteUserStorageProviderFactory::create() - session:{}, model:{}", session, model); + return new RemoteUserStorageProvider(session, model,pluginConfiguration); + } + + @Override + public String getId() { + + return Constants.PROVIDER_ID; + } + + @Override + public String getHelpText() { + return "Janssen User Storage Provider"; + } + + @Override + public void init(Config.Scope config) { + + this.pluginConfiguration = PluginConfiguration.fromKeycloakConfiguration(config); + } + + @Override + public void postInit(KeycloakSessionFactory factory) { + log.debug("RemoteUserStorageProviderFactory::postInit()"); + } + + @Override + public void close() { + log.debug("RemoteUserStorageProviderFactory::close() - Exit"); + } + +} diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/ScimService.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/ScimService.java similarity index 53% rename from jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/ScimService.java rename to jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/ScimService.java index f2c9e49e93e..ea9c7ffe783 100644 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/ScimService.java +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/ScimService.java @@ -1,94 +1,94 @@ -package io.jans.idp.keycloak.service; +package io.jans.kc.spi.storage.service; import com.fasterxml.jackson.databind.JsonNode; -import io.jans.idp.keycloak.util.JansUtil; +import io.jans.kc.spi.storage.util.JansUtil; import io.jans.scim.model.scim2.SearchRequest; import io.jans.scim.model.scim2.user.UserResource; -import jakarta.ws.rs.WebApplicationException; - import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClientBuilder; + +import org.jboss.logging.Logger; + import org.keycloak.broker.provider.util.SimpleHttp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.keycloak.util.JsonSerialization; + public class ScimService { - private static Logger LOG = LoggerFactory.getLogger(ScimService.class); - private static JansUtil jansUtil = new JansUtil(); + private static Logger log = Logger.getLogger(ScimService.class); + + private JansUtil jansUtil; + + public ScimService(JansUtil jansUtil) { + this.jansUtil = jansUtil; + } private String getScimUserEndpoint() { String scimUserEndpoint = jansUtil.getScimUserEndpoint(); - LOG.info("ScimService::getScimUserEndpoint() - scimUserEndpoint:{}", scimUserEndpoint); + log.debugv("ScimService::getScimUserEndpoint() - scimUserEndpoint:{0}", scimUserEndpoint); return scimUserEndpoint; } private String getScimUserSearchEndpoint() { String scimUserSearchEndpoint = jansUtil.getScimUserSearchEndpoint(); - LOG.info("ScimService::getScimUserSearchEndpoint() - scimUserSearchEndpoint:{}", scimUserSearchEndpoint); + log.debugv("ScimService::getScimUserSearchEndpoint() - scimUserSearchEndpoint:{0}", scimUserSearchEndpoint); return scimUserSearchEndpoint; } private String requestAccessToken() { - LOG.info("ScimService::requestAccessToken()"); + log.debug("ScimService::requestAccessToken()"); String token = null; try { token = jansUtil.requestScimAccessToken(); - LOG.info("ScimService::requestAccessToken() - token:{}", token); + log.debugv("ScimService::requestAccessToken() - token:{}", token); } catch (Exception ex) { - LOG.error("ScimService::requestAccessToken() - Error while generating access token for SCIM endpoint is:{}", - ex); - throw new WebApplicationException( - "ScimService::requestAccessToken() - Error while generating access token for SCIM endpoint is = " - + ex); + log.errorv(ex,"ScimService::requestAccessToken() - Error while generating access token for SCIM"); + throw new RuntimeException( + "ScimService::requestAccessToken() - Error while generating access token for SCIM endpoint",ex); } return token; } public UserResource getUserById(String inum) { - LOG.info(" ScimService::getUserById() - inum:{}", inum); + log.infov(" ScimService::getUserById() - inum:{0}", inum); try { return getData(getScimUserEndpoint() + "/" + inum, this.requestAccessToken()); } catch (Exception ex) { - ex.printStackTrace(); - LOG.error( - "ScimService::getUserById() - Error fetching user based on inum:{} from external service is:{} - {} ", - inum, ex.getMessage(), ex); + log.errorv(ex, + "ScimService::getUserById() - Error fetching user based on inum:{0} from external service", + inum); } return null; } public UserResource getUserByName(String username) { - LOG.info("ScimService::getUserByName() - username:{}", username); + log.infov("ScimService::getUserByName() - username:{0}", username); try { String filter = "userName eq \"" + username + "\""; return postData(this.getScimUserSearchEndpoint(), this.requestAccessToken(), filter); } catch (Exception ex) { - ex.printStackTrace(); - LOG.error( - "ScimService::getUserByName() - Error fetching user based on username:{} from external service is:{} - {} ", - username, ex.getMessage(), ex); + log.errorv(ex, + "ScimService::getUserByName() - Error fetching user based on username:{0} from external service", + username); } return null; } public UserResource getUserByEmail(String email) { - LOG.info(" ScimService::getUserByEmail() - email:{}", email); + log.debugv(" ScimService::getUserByEmail() - email:{}", email); try { String filter = "emails[value eq \"" + email + "\"]"; - LOG.info(" ScimService::getUserByEmail() - filter:{}", filter); + log.debugv(" ScimService::getUserByEmail() - filter:{}", filter); return postData(this.getScimUserSearchEndpoint(), this.requestAccessToken(), filter); } catch (Exception ex) { - ex.printStackTrace(); - LOG.error( - " ScimService::getUserByEmail() - Error fetching user based on email:{} from external service is:{} - {} ", - email, ex.getMessage(), ex); + log.errorv(ex, + " ScimService::getUserByEmail() - Error fetching user based on email:{0}", + email); } return null; @@ -96,94 +96,90 @@ public UserResource getUserByEmail(String email) { public UserResource postData(String uri, String accessToken, String filter) { UserResource user = null; - LOG.info("ScimService::postData() - uri:{}, accessToken:{}, filter:{}", uri, accessToken, filter); + log.debugv("ScimService::postData() - uri:{0}, accessToken:{1}, filter:{2}", uri, accessToken, filter); try { HttpClient client = HttpClientBuilder.create().build(); SearchRequest searchRequest = createSearchRequest(filter); - LOG.info("ScimService::postData() - client:{}, searchRequest:{}, accessToken:{}", client, searchRequest, + log.debugv("ScimService::postData() - client:{0}, searchRequest:{1}, accessToken:{2}", client, searchRequest, accessToken); JsonNode jsonNode = SimpleHttp.doPost(uri, client).auth(accessToken).json(searchRequest).asJson(); - LOG.info("\n\n ScimService::postData() - jsonNode:{}", jsonNode); + log.debugv("\n\n ScimService::postData() - jsonNode:{0}", jsonNode); user = getUserResourceFromList(jsonNode); - LOG.info("ScimService::postData() - user:{}", user); + log.debugv("ScimService::postData() - user:{0}", user); } catch (Exception ex) { - ex.printStackTrace(); - LOG.error("\n\n ScimService::postData() - Error while fetching data is ex:{}", ex); + log.errorv(ex,"ScimService::postData() - Error while fetching data"); } return user; } public UserResource getData(String uri, String accessToken) { UserResource user = null; - LOG.info("ScimService::getData() - uri:{}, accessToken:{}", uri, accessToken); + log.debugv("ScimService::getData() - uri:{0}, accessToken:{1}", uri, accessToken); try { HttpClient client = HttpClientBuilder.create().build(); JsonNode jsonNode = SimpleHttp.doGet(uri, client).auth(accessToken).asJson(); - LOG.info("\n\n ScimService::getData() - jsonNode:{}", jsonNode); + log.debugv("\n\n ScimService::getData() - jsonNode:{0}", jsonNode); user = getUserResource(jsonNode); - LOG.info("ScimService::getData() - user:{}", user); + log.debugv("ScimService::getData() - user:{}", user); } catch (Exception ex) { - ex.printStackTrace(); - LOG.error("\n\n ScimService::getData() - Error while fetching data is ex:{}", ex); + log.errorv(ex,"\n\n ScimService::getData() - Error while fetching data"); } return user; } private SearchRequest createSearchRequest(String filter) { - LOG.info("ScimService::createSearchRequest() - createSearchRequest() - filter:{}", filter); + log.debugv("ScimService::createSearchRequest() - createSearchRequest() - filter:{0}", filter); SearchRequest searchRequest = new SearchRequest(); searchRequest.setFilter(filter); - LOG.info(" ScimService::createSearchRequest() - searchRequest:{}", searchRequest); + log.debugv(" ScimService::createSearchRequest() - searchRequest:{0}", searchRequest); return searchRequest; } private UserResource getUserResourceFromList(JsonNode jsonNode) { - LOG.info(" \n\n ScimService::getUserResourceFromList() - jsonNode:{}", jsonNode); + log.debugv(" \n\n ScimService::getUserResourceFromList() - jsonNode:{0}", jsonNode); UserResource user = null; try { if (jsonNode != null) { if (jsonNode.get("Resources") != null) { JsonNode value = jsonNode.get("Resources").get(0); - LOG.info("\n\n *** ScimService::getUserResourceFromList() - value:{}, value.getClass():{}", value, + log.debugv("*** ScimService::getUserResourceFromList() - value:{0}, value.getClass():{1}", value, value.getClass()); user = JsonSerialization.readValue(JsonSerialization.writeValueAsBytes(value), UserResource.class); - LOG.info(" ScimService::getUserResourceFromList() - user:{}, user.getClass():{}", user, + log.debugv(" ScimService::getUserResourceFromList() - user:{0}, user.getClass():{1}", user, user.getClass()); } } } catch (Exception ex) { - ex.printStackTrace(); - LOG.error("\n\n ScimService::getUserResourceFromList() - Error while fetching data is ex:{}", ex); + log.errorv(ex,"\n\n ScimService::getUserResourceFromList() - Error while fetching data"); } return user; } private UserResource getUserResource(JsonNode jsonNode) { - LOG.info(" \n\n ScimService::getUserResource() - jsonNode:{}", jsonNode); + log.debugv("ScimService::getUserResource() - jsonNode:{0}", jsonNode); UserResource user = null; try { if (jsonNode != null) { user = JsonSerialization.readValue(JsonSerialization.writeValueAsBytes(jsonNode), UserResource.class); - LOG.info(" ScimService::getUserResource() - user:{}, user.getClass():{}", user, user.getClass()); + log.debugv(" ScimService::getUserResource() - user:{0}, user.getClass():{1}", user, user.getClass()); } } catch (Exception ex) { - ex.printStackTrace(); - LOG.error("\n\n ScimService::getUserResource() - Error while fetching data is ex:{}", ex); + log.errorv(ex,"\n\n ScimService::getUserResource() - Error while fetching data is ex:{}"); } return user; } diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/UserAdapter.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/UserAdapter.java similarity index 98% rename from jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/UserAdapter.java rename to jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/UserAdapter.java index 4594d8907f8..b26bb3e0e1c 100644 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/service/UserAdapter.java +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/UserAdapter.java @@ -1,6 +1,6 @@ -package io.jans.idp.keycloak.service; +package io.jans.kc.spi.storage.service; -import io.jans.idp.keycloak.util.JansDataUtil; +import io.jans.kc.spi.storage.util.JansDataUtil; import io.jans.scim.model.scim2.user.UserResource; import io.jans.scim.model.scim2.util.DateUtil; diff --git a/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/UsersApiLegacyService.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/UsersApiLegacyService.java new file mode 100644 index 00000000000..4bb8d75b2a6 --- /dev/null +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/service/UsersApiLegacyService.java @@ -0,0 +1,66 @@ +package io.jans.kc.spi.storage.service; + +import io.jans.scim.model.scim2.user.UserResource; + +import java.util.Properties; + +import org.jboss.logging.Logger; + +import org.keycloak.component.ComponentModel; +import org.keycloak.models.KeycloakSession; + +public class UsersApiLegacyService { + + private static Logger log = Logger.getLogger(UsersApiLegacyService.class); + + private ScimService scimService; + protected Properties jansProperties = new Properties(); + + public UsersApiLegacyService(KeycloakSession session, ComponentModel model, ScimService scimService) { + + log.debugv(" UsersApiLegacyService() - session:{0}, model:{1}", session, model); + this.scimService = scimService; + } + + public UserResource getUserById(String inum) { + log.debugv("UsersApiLegacyService::getUserById() - inum:{0}", inum); + try { + return scimService.getUserById(inum); + } catch (Exception ex) { + log.errorv(ex, + "UsersApiLegacyService::getUserById() - Error fetching user based on inum:{0} from external service", + inum); + + } + return null; + } + + public UserResource getUserByName(String username) { + log.debugv(" UsersApiLegacyService::getUserByName() - username:{0}", username); + try { + + return scimService.getUserByName(username); + } catch (Exception ex) { + log.errorv(ex, + "UsersApiLegacyService::getUserByName() - Error fetching user based on username:{0} from external service", + username); + + } + return null; + } + + public UserResource getUserByEmail(String email) { + log.infov(" UsersApiLegacyService::getUserByEmail() - email:{0}", email); + try { + + return scimService.getUserByEmail(email); + } catch (Exception ex) { + log.errorv( + " UsersApiLegacyService::getUserByEmail() - Error fetching user based on email:{0}", + email); + + } + return null; + } + +} diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/Constants.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/Constants.java similarity index 93% rename from jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/Constants.java rename to jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/Constants.java index 11b23b89f43..4740e3c734f 100644 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/Constants.java +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/Constants.java @@ -4,12 +4,13 @@ * Copyright (c) 2020, Janssen Project */ -package io.jans.idp.keycloak.util; +package io.jans.kc.spi.storage.util; public class Constants { private Constants() {} + public static final String PROVIDER_ID = "kc-jans-storage"; public static final String JANS_CONFIG_PROP_PATH = "jans.config.prop.path"; public static final String KEYCLOAK_USER = "/keycloak-user"; public static final String BASE_URL = "https://localhost"; diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/JansDataUtil.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/JansDataUtil.java similarity index 61% rename from jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/JansDataUtil.java rename to jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/JansDataUtil.java index 85a22e3d9b1..179dd9bebdd 100644 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/JansDataUtil.java +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/JansDataUtil.java @@ -1,4 +1,4 @@ -package io.jans.idp.keycloak.util; +package io.jans.kc.spi.storage.util; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; @@ -11,16 +11,15 @@ import java.util.List; import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.jboss.logging.Logger; public class JansDataUtil { - private static final Logger logger = LoggerFactory.getLogger(JansDataUtil.class); + private static final Logger log = Logger.getLogger(JansDataUtil.class); public static Object invokeMethod(Class clazz, String methodName, Class... parameterTypes) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - logger.debug("JansDataUtil::invokeMethod() - Invoke clazz:{} on methodName:{} with name:{} ", clazz, methodName, + log.debugv("JansDataUtil::invokeMethod() - Invoke clazz:{0} on methodName:{1} with name:{2} ", clazz, methodName, parameterTypes); Object obj = null; if (clazz == null || methodName == null || parameterTypes == null) { @@ -29,48 +28,47 @@ public static Object invokeMethod(Class clazz, String methodName, Class... Method m = clazz.getDeclaredMethod(methodName, parameterTypes); obj = m.invoke(null, parameterTypes); - logger.debug("JansDataUtil::invokeMethod() - methodName:{} returned obj:{} ", methodName, obj); + log.debugv("JansDataUtil::invokeMethod() - methodName:{0} returned obj:{1} ", methodName, obj); return obj; } public Object invokeReflectionGetter(Object obj, String variableName) { - logger.debug("JansDataUtil::invokeMethod() - Invoke obj:{}, variableName:{}", obj, variableName); + log.debugv("JansDataUtil::invokeMethod() - Invoke obj:{0}, variableName:{1}", obj, variableName); try { if (obj == null) { return obj; } PropertyDescriptor pd = new PropertyDescriptor(variableName, obj.getClass()); Method getter = pd.getReadMethod(); - logger.debug("JansDataUtil::invokeMethod() - Invoke getter:{}", getter); + log.debugv("JansDataUtil::invokeMethod() - Invoke getter:{0}", getter); if (getter != null) { return getter.invoke(obj); } else { - logger.error( - "JansDataUtil::invokeReflectionGetter() - Getter Method not found for class:{} property:{}", + log.errorv( + "JansDataUtil::invokeReflectionGetter() - Getter Method not found for class:{0} property:{1}", obj.getClass().getName(), variableName); } } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | IntrospectionException e) { - logger.error(String.format( - "JansDataUtil::invokeReflectionGetter() - Getter Method ERROR for class: %s property: %s", - obj.getClass().getName(), variableName), e); + log.errorv(e,"JansDataUtil::invokeReflectionGetter() - Getter Method ERROR for class: {0} property: {1}", + obj.getClass().getName(), variableName); } return obj; } public static List getAllFields(Class type) { - logger.debug("JansDataUtil::getAllFields() - type:{} ", type); + log.debugv("JansDataUtil::getAllFields() - type:{0} ", type); List allFields = new ArrayList<>(); if (type == null) { return allFields; } getAllFields(allFields, type); - logger.debug("JansDataUtil::getAllFields() - Fields:{} of type:{} ", allFields, type); + log.debugv("JansDataUtil::getAllFields() - Fields:{0} of type:{1} ", allFields, type); return allFields; } public static List getAllFields(List fields, Class type) { - logger.debug("JansDataUtil::getAllFields() - fields:{} , type:{} ", fields, type); + log.debugv("JansDataUtil::getAllFields() - fields:{0} , type:{1} ", fields, type); if (fields == null || type == null) { return fields; } @@ -79,12 +77,12 @@ public static List getAllFields(List fields, Class type) { if (type.getSuperclass() != null) { getAllFields(fields, type.getSuperclass()); } - logger.debug("JansDataUtil::getAllFields() - Final fields:{} of type:{} ", fields, type); + log.debugv("JansDataUtil::getAllFields() - Final fields:{0} of type:{1} ", fields, type); return fields; } public static Map getFieldTypeMap(Class clazz) { - logger.debug("JansDataUtil::getFieldTypeMap() - clazz:{} ", clazz); + log.debugv("JansDataUtil::getFieldTypeMap() - clazz:{0} ", clazz); Map propertyTypeMap = new HashMap<>(); if (clazz == null) { @@ -92,17 +90,17 @@ public static Map getFieldTypeMap(Class clazz) { } List fields = getAllFields(clazz); - logger.debug("JansDataUtil::getFieldTypeMap() - all-fields:{} ", fields); + log.debugv("JansDataUtil::getFieldTypeMap() - all-fields:{0} ", fields); for (Field field : fields) { - logger.debug( - "JansDataUtil::getFieldTypeMap() - field:{} , field.getAnnotatedType():{}, field.getAnnotations():{} , field.getType().getAnnotations():{}, field.getType().getCanonicalName():{} , field.getType().getClass():{} , field.getType().getClasses():{} , field.getType().getComponentType():{}", + log.debugv( + "JansDataUtil::getFieldTypeMap() - field:{0} , field.getAnnotatedType():{1}, field.getAnnotations():{2} , field.getType().getAnnotations():{3}, field.getType().getCanonicalName():{4} , field.getType().getClass():{5} , field.getType().getClasses():{6} , field.getType().getComponentType():{7}", field, field.getAnnotatedType(), field.getAnnotations(), field.getType().getAnnotations(), field.getType().getCanonicalName(), field.getType().getClass(), field.getType().getClasses(), field.getType().getComponentType()); propertyTypeMap.put(field.getName(), field.getType().getSimpleName()); } - logger.debug("JansDataUtil::getFieldTypeMap() - Final propertyTypeMap{} ", propertyTypeMap); + log.debugv("JansDataUtil::getFieldTypeMap() - Final propertyTypeMap{0} ", propertyTypeMap); return propertyTypeMap; } diff --git a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/JansUtil.java b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/JansUtil.java similarity index 54% rename from jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/JansUtil.java rename to jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/JansUtil.java index 3ae58e5204e..826bc155eea 100644 --- a/jans-keycloak-integration/storage-api/src/main/java/io/jans/idp/keycloak/util/JansUtil.java +++ b/jans-keycloak-integration/storage-spi/src/main/java/io/jans/kc/spi/storage/util/JansUtil.java @@ -1,11 +1,10 @@ -package io.jans.idp.keycloak.util; +package io.jans.kc.spi.storage.util; import com.fasterxml.jackson.databind.JsonNode; -import io.jans.idp.keycloak.config.JansConfigSource; +import io.jans.kc.spi.storage.config.PluginConfiguration; import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.WebApplicationException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; @@ -17,89 +16,91 @@ import org.apache.commons.lang.StringUtils; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.keycloak.broker.provider.util.SimpleHttp; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.jboss.logging.Logger; + +import org.keycloak.broker.provider.util.SimpleHttp; public class JansUtil { - private static Logger logger = LoggerFactory.getLogger(JansUtil.class); - private JansConfigSource jansConfigSource = new JansConfigSource(); - private Map configProperties = null; - - public JansUtil() { - logger.debug("\nJ ansUtil() - Getting properties"); - configProperties = jansConfigSource.getProperties(); - if (configProperties == null || configProperties.isEmpty()) { - throw new WebApplicationException("Config properties is null!!!"); + + private static Logger log = Logger.getLogger(JansUtil.class); + private PluginConfiguration pluginConfiguration; + + public JansUtil(PluginConfiguration pluginConfiguration) { + + this.pluginConfiguration = pluginConfiguration; + if (this.pluginConfiguration == null || !this.pluginConfiguration.isValid()) { + throw new RuntimeException("Plugin configuration missing or invalid"); } } public String getTokenEndpoint() { - logger.debug("\n JansUtil::getTokenEndpoint() - configProperties.get(Constants.AUTH_TOKEN_ENDPOINT)():{}", - configProperties.get(Constants.AUTH_TOKEN_ENDPOINT)); - return configProperties.get(Constants.AUTH_TOKEN_ENDPOINT); + log.debugv("JansUtil::getTokenEndpoint() - {0}", + pluginConfiguration.getAuthTokenEndpoint()); + + return pluginConfiguration.getAuthTokenEndpoint(); } public String getScimUserEndpoint() { - logger.debug(" \n JansUtil::getScimUserEndpoint() - configProperties.get(Constants.SCIM_USER_ENDPOINT)():{}", - configProperties.get(Constants.SCIM_USER_ENDPOINT)); - return configProperties.get(Constants.SCIM_USER_ENDPOINT); + log.debugv("JansUtil::getScimUserEndpoint() - {0}", + pluginConfiguration.getScimUserEndpoint()); + + return pluginConfiguration.getScimUserEndpoint(); } public String getScimUserSearchEndpoint() { - logger.debug( - "\n JansUtil::getScimUserSearchEndpoint() - configProperties.get(Constants.SCIM_USER_SEARCH_ENDPOINT)():{}", - configProperties.get(Constants.SCIM_USER_SEARCH_ENDPOINT)); - return configProperties.get(Constants.SCIM_USER_SEARCH_ENDPOINT); + log.debugv( + "JansUtil::getScimUserSearchEndpoint() - {0}", + pluginConfiguration.getScimUserSearchEndpoint()); + return pluginConfiguration.getScimUserSearchEndpoint(); } - public String getClientId() { - logger.debug(" \n JansUtil::getClientId() - configProperties.get(Constants.KEYCLOAK_SCIM_CLIENT_ID)():{}", - configProperties.get(Constants.KEYCLOAK_SCIM_CLIENT_ID)); - return configProperties.get(Constants.KEYCLOAK_SCIM_CLIENT_ID); + public String getScimClientId() { + log.debugv("JansUtil::getScimClientId() - {0}", + pluginConfiguration.getScimClientId()); + return pluginConfiguration.getScimClientId(); } - public String getClientPassword() { - logger.debug(" \n JansUtil::getClientPassword() - configProperties.get(Constants.KEYCLOAK_SCIM_CLIENT_PASSWORD)():{}", - configProperties.get(Constants.KEYCLOAK_SCIM_CLIENT_PASSWORD)); - return configProperties.get(Constants.KEYCLOAK_SCIM_CLIENT_PASSWORD); + public String getScimClientSecret() { + log.debugv("JansUtil::getClientPassword() - {0}", + pluginConfiguration.getScimClientSecret()); + return pluginConfiguration.getScimClientSecret(); } public String getScimOauthScope() { - logger.debug(" \n JansUtil::getScimOauthScope() - configProperties.get(Constants.SCIM_OAUTH_SCOPE)():{}", - configProperties.get(Constants.SCIM_OAUTH_SCOPE)); - return configProperties.get(Constants.SCIM_OAUTH_SCOPE); + log.debugv("JansUtil::getScimOauthScope() - {0}", + pluginConfiguration.getScimOauthScope()); + return pluginConfiguration.getScimOauthScope(); } public String requestScimAccessToken() throws IOException { - logger.info(" \n JansUtil::requestScimAccessToken() "); + log.debug("JansUtil::requestScimAccessToken() "); List scopes = new ArrayList<>(); scopes.add(getScimOauthScope()); - String token = requestAccessToken(getClientId(), scopes); - logger.info("JansUtil::requestScimAccessToken() - token:{} ", token); + String token = requestAccessToken(getScimClientId(), scopes); + log.debugv("JansUtil::requestScimAccessToken() - token:{0} ", token); return token; } public String requestAccessToken(final String clientId, final List scope) throws IOException { - logger.info("JansUtil::requestAccessToken() - Request for AccessToken - clientId:{}, scope:{} ", clientId, + log.debugv("JansUtil::requestAccessToken() - Request for AccessToken - clientId:{0}, scope:{1} ", clientId, scope); String tokenUrl = getTokenEndpoint(); String token = getAccessToken(tokenUrl, clientId, scope); - logger.info("JansUtil::requestAccessToken() - oAuth AccessToken response - token:{}", token); + log.debugv("JansUtil::requestAccessToken() - oAuth AccessToken response - token:{0}", token); return token; } public String getAccessToken(final String tokenUrl, final String clientId, final List scopes) throws IOException { - logger.info("JansUtil::getAccessToken() - Access Token Request - tokenUrl:{}, clientId:{}, scopes:{}", tokenUrl, + log.debugv("JansUtil::getAccessToken() - Access Token Request - tokenUrl:{0}, clientId:{1}, scopes:{2}", tokenUrl, clientId, scopes); // Get clientSecret - String clientSecret = this.getClientPassword(); - logger.info("JansUtil::getAccessToken() - Access Token Request - clientId:{}, clientSecret:{}", clientId, + String clientSecret = getScimClientSecret(); + log.debugv("JansUtil::getAccessToken() - Access Token Request - clientId:{0}, clientSecret:{1}", clientId, clientSecret); // distinct scopes @@ -109,23 +110,23 @@ public String getAccessToken(final String tokenUrl, final String clientId, final scope.append(" ").append(s); } - logger.info("JansUtil::getAccessToken() - Scope required - {}", scope); + log.debugv("JansUtil::getAccessToken() - Scope required - {0}", scope); String token = requestAccessToken(tokenUrl, clientId, clientSecret, scope.toString(), Constants.CLIENT_CREDENTIALS, Constants.CLIENT_SECRET_BASIC, MediaType.APPLICATION_FORM_URLENCODED); - logger.info("JansUtil::getAccessToken() - Final token token - {}", token); + log.debugv("JansUtil::getAccessToken() - Final token token - {0}", token); return token; } public String requestAccessToken(final String tokenUrl, final String clientId, final String clientSecret, final String scope, String grantType, String authenticationMethod, String mediaType) throws IOException { - logger.info( - "JansUtil::requestAccessToken() - Request for Access Token - tokenUrl:{}, clientId:{}, clientSecret:{}, scope:{}, grantType:{}, authenticationMethod:{}, mediaType:{}", + log.debugv( + "JansUtil::requestAccessToken() - Request for Access Token - tokenUrl:{0}, clientId:{1}, clientSecret:{2}, scope:{3}, grantType:{4}, authenticationMethod:{5}, mediaType:{6}", tokenUrl, clientId, clientSecret, scope, grantType, authenticationMethod, mediaType); String token = null; try { - logger.info(" JansUtil::requestAccessToken() - this.getEncodedCredentials():{}", + log.debugv("JansUtil::requestAccessToken() - this.getEncodedCredentials():{0}", this.getEncodedCredentials(clientId, clientSecret)); HttpClient client = HttpClientBuilder.create().build(); JsonNode jsonNode = SimpleHttp.doPost(tokenUrl, client) @@ -133,31 +134,30 @@ public String requestAccessToken(final String tokenUrl, final String clientId, f .header("Content-Type", mediaType).param("grant_type", "client_credentials") .param("username", clientId + ":" + clientSecret).param("scope", scope).param("client_id", clientId) .param("client_secret", clientSecret).param("authorization_method", "client_secret_basic").asJson(); - logger.info("\n JansUtil::requestAccessToken() - POST Request for Access Token - jsonNode:{} ", jsonNode); + log.debugv("JansUtil::requestAccessToken() - POST Request for Access Token - jsonNode:{0} ", jsonNode); token = this.getToken(jsonNode); - logger.info("\n JansUtil::requestAccessToken() - After Post request for Access Token - token:{} ", token); + log.debugv("\n JansUtil::requestAccessToken() - After Post request for Access Token - token:{0} ", token); } catch (Exception ex) { - ex.printStackTrace(); - logger.error("\n JansUtil::requestAccessToken() - Post error is ", ex); + log.error("JansUtil::requestAccessToken() - Post error is ",ex); } return token; } public String requestUserToken(final String tokenUrl, final String username, final String password, final String scope, String grantType, String authenticationMethod, String mediaType) throws IOException { - logger.info( - "JansUtil::requestUserToken() - Request for Access Token - tokenUrl:{}, username:{}, password:{}, scope:{}, grantType:{}, authenticationMethod:{}, mediaType:{}", + log.debugv( + "JansUtil::requestUserToken() - Request for Access Token - tokenUrl:{0}, username:{1}, password:{2}, scope:{3}, grantType:{4}, authenticationMethod:{5}, mediaType:{6}", tokenUrl, username, password, scope, grantType, authenticationMethod, mediaType); String token = null; try { - String clientId = this.getClientId(); - String clientSecret = this.getClientPassword(); + String clientId = this.getScimClientId(); + String clientSecret = this.getScimClientSecret(); - logger.info( - " JansUtil::requestUserToken() - clientId:{} , clientSecret:{}, this.getEncodedCredentials():{}", + log.debugv( + " JansUtil::requestUserToken() - clientId:{0} , clientSecret:{1}, this.getEncodedCredentials():{2}", clientId, clientSecret, this.getEncodedCredentials(clientId, clientSecret)); HttpClient client = HttpClientBuilder.create().build(); JsonNode jsonNode = SimpleHttp.doPost(tokenUrl, client) @@ -165,23 +165,22 @@ public String requestUserToken(final String tokenUrl, final String username, fin .header("Content-Type", mediaType).param("grant_type", grantType).param("username", username) .param("password", password).asJson(); - logger.info("\n JansUtil::requestUserToken() - After invoking post request for user token - jsonNode:{} ", + log.debugv("JansUtil::requestUserToken() - After invoking post request for user token - jsonNode:{0}", jsonNode); token = this.getToken(jsonNode); - logger.info("\n JansUtil::requestUserToken() -POST Request for Access Token - token:{} ", token); + log.debugv("\n JansUtil::requestUserToken() -POST Request for Access Token - token:{0} ", token); } catch (Exception ex) { - ex.printStackTrace(); - logger.error("\n JansUtil::requestUserToken() - Post error is ", ex); + log.errorv("\n JansUtil::requestUserToken() - Error getting user token", ex); } return token; } private boolean validateTokenScope(JsonNode jsonNode, String scope) { - logger.info(" \n\n JansUtil::validateTokenScope() - jsonNode:{}, scope:{}", jsonNode, scope); + log.debugv("JansUtil::validateTokenScope() - jsonNode:{0}, scope:{1}", jsonNode, scope); boolean validScope = false; try { @@ -189,12 +188,12 @@ private boolean validateTokenScope(JsonNode jsonNode, String scope) { if (jsonNode != null && jsonNode.get("scope") != null) { JsonNode value = jsonNode.get("scope"); - logger.info("\n\n *** JansUtil::validateTokenScope() - value:{}", value); + log.debugv("JansUtil::validateTokenScope() - value:{0}", value); if (value != null) { String responseScope = value.toString(); - logger.info( - "JansUtil::validateTokenScope() - scope:{}, responseScope:{}, responseScope.contains(scope):{}", + log.debugv( + "JansUtil::validateTokenScope() - scope:{0}, responseScope:{1}, responseScope.contains(scope):{2}", scope, responseScope, responseScope.contains(scope)); if (scopeList.contains(responseScope)) { validScope = true; @@ -202,11 +201,10 @@ private boolean validateTokenScope(JsonNode jsonNode, String scope) { } } - logger.info("JansUtil::validateTokenScope() - validScope:{}", validScope); + log.debugv("JansUtil::validateTokenScope() - validScope:{0}", validScope); } catch (Exception ex) { - ex.printStackTrace(); - logger.error("\n JansUtil::validateTokenScope() - Error while validating token scope from response is ", + log.error("JansUtil::validateTokenScope() - Error while validating token scope from response is ", ex); } return validScope; @@ -214,23 +212,22 @@ private boolean validateTokenScope(JsonNode jsonNode, String scope) { } private String getToken(JsonNode jsonNode) { - logger.info(" \n\n JansUtil::getToken() - jsonNode:{}", jsonNode); + log.debugv("JansUtil::getToken() - jsonNode:{0}", jsonNode); String token = null; try { if (jsonNode != null && jsonNode.get("access_token") != null) { JsonNode value = jsonNode.get("access_token"); - logger.info("\n\n *** JansUtil::getToken() - value:{}", value); + log.debugv("JansUtil::getToken() - value:{0}", value); if (value != null) { token = value.asText(); } - logger.info("getToken() - token:{}", token); + log.debugv("getToken() - token:{0}", token); } } catch (Exception ex) { - ex.printStackTrace(); - logger.error("\n\n Error while getting token from response is ", ex); + log.errorv("Error while getting token from response", ex); } return token; } @@ -245,13 +242,13 @@ private boolean hasCredentials(String authUsername, String authPassword) { * @return The client credentials. */ private String getCredentials(String authUsername, String authPassword) throws UnsupportedEncodingException { - logger.info("getCredentials() - authUsername:{}, authPassword:{}", authUsername, authPassword); + log.debugv("getCredentials() - authUsername:{0}, authPassword:{1}", authUsername, authPassword); return URLEncoder.encode(authUsername, Constants.UTF8_STRING_ENCODING) + ":" + URLEncoder.encode(authPassword, Constants.UTF8_STRING_ENCODING); } private String getEncodedCredentials(String authUsername, String authPassword) { - logger.info("getEncodedCredentials() - authUsername:{}, authPassword:{}", authUsername, authPassword); + log.debugv("getEncodedCredentials() - authUsername:{0}, authPassword:{1}", authUsername, authPassword); try { if (hasCredentials(authUsername, authPassword)) { return Base64.encodeBase64String(getBytes(getCredentials(authUsername, authPassword))); diff --git a/jans-keycloak-integration/storage-spi/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory b/jans-keycloak-integration/storage-spi/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory new file mode 100644 index 00000000000..2691b848dd3 --- /dev/null +++ b/jans-keycloak-integration/storage-spi/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory @@ -0,0 +1 @@ +io.jans.kc.spi.storage.service.RemoteUserStorageProviderFactory \ No newline at end of file diff --git a/jans-keycloak-integration/task-scheduling/pom.xml b/jans-keycloak-integration/task-scheduling/pom.xml new file mode 100644 index 00000000000..b5c8d879c13 --- /dev/null +++ b/jans-keycloak-integration/task-scheduling/pom.xml @@ -0,0 +1,108 @@ + + + 4.0.0 + io.jans + kc-jans-scheduler + kc-jans-scheduler + jar + + + io.jans + jans-kc-parent + 1.0.20-SNAPSHOT + + + + ${maven.min-version} + + + + + + + org.keycloak + keycloak-core + + + + org.keycloak + keycloak-server-spi + + + + org.keycloak + keycloak-server-spi-private + + + + org.keycloak + keycloak-services + + + + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-deps-plugin.version} + + + copy + package + + copy-dependencies + + + ${project.build.directory}/deps + runtime + false + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + src/assembly/dependencies.xml + + ${project.artifactId}-${project.version} + + + + zip-dependencies + package + + single + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + diff --git a/jans-keycloak-integration/task-scheduling/src/assembly/dependencies.xml b/jans-keycloak-integration/task-scheduling/src/assembly/dependencies.xml new file mode 100644 index 00000000000..373f6f1d362 --- /dev/null +++ b/jans-keycloak-integration/task-scheduling/src/assembly/dependencies.xml @@ -0,0 +1,24 @@ + + deps + + zip + + false + + + target/deps/ + . + + *.jar + + + + src/main/resources/assembly + . + + *.DONOTDELETE + + + + \ No newline at end of file diff --git a/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/events/JansTasksEventListenerProvider.java b/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/events/JansTasksEventListenerProvider.java new file mode 100644 index 00000000000..cfbe6978e2d --- /dev/null +++ b/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/events/JansTasksEventListenerProvider.java @@ -0,0 +1,24 @@ +package io.jans.kc.spi.events; + +import org.keycloak.events.Event; +import org.keycloak.events.EventListenerProvider; +import org.keycloak.events.admin.AdminEvent; + +public class JansTasksEventListenerProvider implements EventListenerProvider{ + + @Override + public void close() { + // TODO Auto-generated method stub + } + + @Override + public void onEvent(Event event) { + // TODO Auto-generated method stub + } + + @Override + public void onEvent(AdminEvent event, boolean includeRepresentation) { + // TODO Auto-generated method stub + } + +} diff --git a/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/events/JansTasksEventListenerProviderFactory.java b/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/events/JansTasksEventListenerProviderFactory.java new file mode 100644 index 00000000000..2dcbca56019 --- /dev/null +++ b/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/events/JansTasksEventListenerProviderFactory.java @@ -0,0 +1,53 @@ +package io.jans.kc.spi.events; + + +import org.keycloak.Config; +import org.keycloak.events.EventListenerProvider; +import org.keycloak.events.EventListenerProviderFactory; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.utils.PostMigrationEvent; +import org.keycloak.timer.TimerProvider; +import org.keycloak.timer.TimerProviderFactory; + +import io.jans.kc.spi.tasks.SamlConfigUpdateTask; + +public class JansTasksEventListenerProviderFactory implements EventListenerProviderFactory { + + private static final String PROVIDER_ID = "kc-jans-event-listener"; + + @Override + public String getId() { + + return PROVIDER_ID; + } + + @Override + public EventListenerProvider create(KeycloakSession keycloakSession) { + + return new JansTasksEventListenerProvider(); + } + + @Override + public void init(Config.Scope scope) { + + } + + @Override + public void postInit(KeycloakSessionFactory keycloakSessionFactory) { + + keycloakSessionFactory.register(event -> { + if( event instanceof PostMigrationEvent) { + KeycloakSession kcsession = keycloakSessionFactory.create(); + TimerProviderFactory tpfactory = (TimerProviderFactory) keycloakSessionFactory.getProviderFactory(TimerProvider.class); + SamlConfigUpdateTask task = new SamlConfigUpdateTask(); + tpfactory.create(kcsession).scheduleTask(task, task.getTaskInterval(), task.getTaskId()); + } + }); + } + + @Override + public void close() { + + } +} diff --git a/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/tasks/SamlConfigUpdateTask.java b/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/tasks/SamlConfigUpdateTask.java new file mode 100644 index 00000000000..891ebafa190 --- /dev/null +++ b/jans-keycloak-integration/task-scheduling/src/main/java/io/jans/kc/spi/tasks/SamlConfigUpdateTask.java @@ -0,0 +1,30 @@ +package io.jans.kc.spi.tasks; + +import org.keycloak.models.KeycloakSession; +import org.keycloak.timer.ScheduledTask; + +import org.jboss.logging.Logger; + +public class SamlConfigUpdateTask implements ScheduledTask { + + private static final Logger logger = Logger.getLogger(SamlConfigUpdateTask.class); + + private static final String TASK_ID = "saml-config-update"; + private static final long TASK_INTERVAL = 1000 * 5; // Run task every five minutes + + public String getTaskId() { + + return TASK_ID; + } + + public long getTaskInterval() { + + return TASK_INTERVAL; + } + + @Override + public void run(KeycloakSession session) { + // TODO Auto-generated method stub + } + +} diff --git a/jans-keycloak-integration/task-scheduling/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory b/jans-keycloak-integration/task-scheduling/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory new file mode 100644 index 00000000000..fa69884b287 --- /dev/null +++ b/jans-keycloak-integration/task-scheduling/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory @@ -0,0 +1 @@ +io.jans.kc.spi.events.JansTasksEventListenerProviderFactory \ No newline at end of file diff --git a/jans-keycloak-integration/task-scheduling/src/main/resources/assembly/.DONOTDELETE b/jans-keycloak-integration/task-scheduling/src/main/resources/assembly/.DONOTDELETE new file mode 100644 index 00000000000..c7c1c13b13c --- /dev/null +++ b/jans-keycloak-integration/task-scheduling/src/main/resources/assembly/.DONOTDELETE @@ -0,0 +1 @@ +This file is used to prevent build errors during the run of the maven assembly plugin \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/templates/keycloak/keycloak.conf b/jans-linux-setup/jans_setup/templates/keycloak/keycloak.conf new file mode 100644 index 00000000000..1f6b35812c3 --- /dev/null +++ b/jans-linux-setup/jans_setup/templates/keycloak/keycloak.conf @@ -0,0 +1,62 @@ +# Basic settings for running in production. Change accordingly before deploying the server. + +# Database + +# The database vendor. +#db=postgres + +# The username of the database user. +#db-username=keycloak + +# The password of the database user. +#db-password=password + +# The full database JDBC URL. If not provided, a default URL is set based on the selected database vendor. +#db-url=jdbc:postgresql://localhost/keycloak + +# Observability + +# If the server should expose healthcheck endpoints. +#health-enabled=true + +# If the server should expose metrics endpoints. +#metrics-enabled=true + +# HTTP + +# The file path to a server certificate or certificate chain in PEM format. +#https-certificate-file=${kc.home.dir}conf/server.crt.pem + +# The file path to a private key in PEM format. +#https-certificate-key-file=${kc.home.dir}conf/server.key.pem + +# The proxy address forwarding mode if the server is behind a reverse proxy. +#proxy=reencrypt + +# Do not attach route to cookies and rely on the session affinity capabilities from reverse proxy +#spi-sticky-session-encoder-infinispan-should-attach-route=false + +# Hostname for the Keycloak server. +#hostname=myhostname + +# Janssen configuration parameters + +# Storage spi configuration + +# token endpoint +#jans-storage-auth-token-endpoint= + +# scim user endpoint +#jans-storage-scim-user-endpoint + +# scim user search endpoint +#jans-storage-scim-user-search-endpoint + +# scim oauth scopes +#jans-storage-scim-oauth-scope + +#scim client id +#jans-storage-client-id + +#scim client secret +#jans-storage-client-secret