diff --git a/Dockerfile b/Dockerfile index 6640f5a..cd14fb8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,6 @@ ARG VERSION=26.7.0 ARG KC_HEALTH_ENABLED=true ARG KC_METRICS_ENABLED=true -ARG KC_FEATURES=token-exchange ARG KC_DB=postgres ARG KC_HTTP_RELATIVE_PATH=/auth @@ -27,36 +26,31 @@ LABEL git-commit=$GIT_COMMIT # Configure build options ARG KC_HEALTH_ENABLED ARG KC_METRICS_ENABLED -ARG KC_FEATURES ARG KC_DB ARG KC_HTTP_RELATIVE_PATH ENV KC_HEALTH_ENABLED=$KC_HEALTH_ENABLED ENV KC_METRICS_ENABLED=$KC_METRICS_ENABLED -ENV KC_FEATURES=$KC_FEATURES ENV KC_DB=$KC_DB ENV KC_HTTP_RELATIVE_PATH=$KC_HTTP_RELATIVE_PATH # Install custom providers COPY --chown=keycloak:keycloak build/image/openremote-theme-provider.jar /opt/keycloak/providers -COPY --chown=keycloak:keycloak build/image/openremote-issuer-provider.jar /opt/keycloak/providers COPY --chown=keycloak:keycloak build/image/openremote-self-register-configure-event-listener.jar /opt/keycloak/providers WORKDIR /opt/keycloak # Build custom image and copy into this new image -RUN /opt/keycloak/bin/kc.sh build --spi-initializer-provider=issuer +RUN /opt/keycloak/bin/kc.sh build FROM keycloak/keycloak:${VERSION} # Reinstate build args in case starting in dev mode ARG KC_HEALTH_ENABLED ARG KC_METRICS_ENABLED -ARG KC_FEATURES ARG KC_DB ARG KC_HTTP_RELATIVE_PATH ENV KC_HEALTH_ENABLED=$KC_HEALTH_ENABLED ENV KC_METRICS_ENABLED=$KC_METRICS_ENABLED -ENV KC_FEATURES=$KC_FEATURES ENV KC_DB=$KC_DB ENV KC_HTTP_RELATIVE_PATH=$KC_HTTP_RELATIVE_PATH @@ -95,4 +89,4 @@ HEALTHCHECK --interval=3s --timeout=3s --start-period=30s --retries=120 CMD curl EXPOSE 8080 -ENTRYPOINT exec /opt/keycloak/bin/kc.sh ${KEYCLOAK_START_COMMAND:-start --optimized} --spi-initializer-issuer-base-uri=${KEYCLOAK_ISSUER_BASE_URI:-} --spi-events-listener-self-register-user-configure-self-registered-user-roles="${KEYCLOAK_SELF_REGISTERED_USER_ROLES:-}" ${KEYCLOAK_START_OPTS:-} +ENTRYPOINT exec /opt/keycloak/bin/kc.sh ${KEYCLOAK_START_COMMAND:-start} --spi-events-listener-self-register-user-configure-self-registered-user-roles="${KEYCLOAK_SELF_REGISTERED_USER_ROLES:-}" ${KEYCLOAK_START_OPTS:-} diff --git a/README.md b/README.md index 0b4c534..f70145f 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,6 @@ Keycloak docker image built for `postgres` with: * Default env variable values to assume running behind a reverse proxy sending `X-Forwarded-*` headers (env variables can be changed see keycloak documentation) * Enables metrics and health endpoints by default -* Adds custom functionality to allow token 'issuer' to be fixed by setting `KEYCLOAK_ISSUER_BASE_URI` (e.g. `KEYCLOAK_ISSUER_BASE_URI: https://192.168.1.2/auth`) -this is to allow a private deployment to be accessed over a reverse tunnel, when using this you also need to set the following but precaution should be taken to validate the `Host` header in the reverse proxy: - * `KC_HOSTNAME: ` - * `KC_HOSTNAME_STRICT: false` * OpenRemote theme embedded and set as default (login and email templates only) * Request path to `/auth` (like older versions of Keycloak to simplify usage behind a reverse proxy) * Listener to configure roles of self-registered users. Roles are set using `KEYCLOAK_SELF_REGISTERED_USER_ROLES` environment variable, @@ -33,13 +29,13 @@ This can be done e.g. by piping to `jq -c | sed 's/"/\\"/g'`, which would result The listener is not enabled by default. In Keycloak, in the `Realm settings` - `Events` - `Event listeners` admin screen, `self-register-user-configure` should be added to the list. ## Working on the OpenRemote theme -The openremote theme template files are located in `src/main/resources/theme/openremote`; to work on the OpenRemote theme use (ensure you are in the repo root dir first): +The OpenRemote theme template files are located in `theme/src/main/resources/theme/openremote`; to work on the OpenRemote theme use (ensure you are in the repo root dir first and change port as required): ```shell -docker run --rm -p 8081:8080 -e KC_HOSTNAME_PORT=8081 -e KEYCLOAK_START_COMMAND=start-dev -e KEYCLOAK_START_OPTS="--spi-theme-static-max-age=-1 --spi-theme-cache-themes=false --spi-theme-cache-templates=false" --mount type=bind,src=$PWD/theme/src/main/resources/theme/openremote,dst=/deployment/keycloak/themes/dev openremote/keycloak:latest +docker run --rm -p 8081:8080 -e KC_DB="dev-mem" -e KC_HOSTNAME="localhost" -e KEYCLOAK_START_OPTS="--spi-theme-static-max-age=-1 --spi-theme-cache-themes=false --spi-theme-cache-templates=false" --mount type=bind,src=$PWD/theme/src/main/resources/theme/openremote,dst=/deployment/keycloak/themes/dev openremote/keycloak:develop ``` -Then access http://localhost:8081/auth/ then change the template used for a realm to the `dev` template then try and login to that realm via http://localhost:8081/auth/admin/REALM_NAME/console and any changes made to the template files can be reloaded in realtime by just refreshing the window. +Then access http://localhost:8081/auth/ then create a new realm and change the template used for the realm to the `dev` template then try and login to that realm via http://localhost:8081/auth/admin/REALM_NAME/console and any changes made to the template files can be reloaded in realtime by just refreshing the window. To get the standard themes for reference use the following (replace `${VERSION}` with actual keycloak version used): ```shell diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..3231ec7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,3 @@ +plugins { + id 'base' +} diff --git a/fixed-issuer/build.gradle b/fixed-issuer/build.gradle deleted file mode 100644 index 24ea7ce..0000000 --- a/fixed-issuer/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -plugins { - id 'java' -} - -base { - archivesName = "openremote-issuer-provider" -} - -configurations { - jarLibs -} - -repositories { - mavenCentral() -} - -dependencies { - implementation libs.keycloakServices - implementation libs.keycloakServerSpi - implementation libs.byteBuddy - implementation libs.byteBuddyAgent - jarLibs libs.byteBuddyAgent - implementation libs.slf4jApi - compileOnly libs.lombok - annotationProcessor libs.lombok - compileOnly libs.autoService - annotationProcessor libs.autoService -} - -jar { - from { - configurations.jarLibs.collect { - zipTree(it) - } - } -} - -tasks.register('installDist', Copy) { - into "${rootDir}/build/image" - from jar.outputs -} diff --git a/fixed-issuer/src/main/java/org/openremote/keycloak/InitializerProviderFactory.java b/fixed-issuer/src/main/java/org/openremote/keycloak/InitializerProviderFactory.java deleted file mode 100644 index f335682..0000000 --- a/fixed-issuer/src/main/java/org/openremote/keycloak/InitializerProviderFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.openremote.keycloak; - -import org.keycloak.Config; -import org.keycloak.models.KeycloakSession; -import org.keycloak.provider.Provider; -import org.keycloak.provider.ProviderFactory; - -public interface InitializerProviderFactory extends ProviderFactory, Provider { - @Override - default Provider create(KeycloakSession session) { - return null; - } - - @Override - default void init(Config.Scope config) { - } - - @Override - default void close() { - } -} diff --git a/fixed-issuer/src/main/java/org/openremote/keycloak/InitializerSpi.java b/fixed-issuer/src/main/java/org/openremote/keycloak/InitializerSpi.java deleted file mode 100644 index 67a6ad3..0000000 --- a/fixed-issuer/src/main/java/org/openremote/keycloak/InitializerSpi.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.openremote.keycloak; - -import com.google.auto.service.AutoService; -import org.keycloak.provider.Provider; -import org.keycloak.provider.ProviderFactory; -import org.keycloak.provider.Spi; - -@AutoService(Spi.class) -public class InitializerSpi implements Spi { - - @Override - public boolean isInternal() { - return true; - } - - @Override - public String getName() { - return "initializer"; - } - - @Override - public Class getProviderClass() { - return Provider.class; - } - - @Override - public Class getProviderFactoryClass() { - return InitializerProviderFactory.class; - } -} diff --git a/fixed-issuer/src/main/java/org/openremote/keycloak/IssuerInitializerProvider.java b/fixed-issuer/src/main/java/org/openremote/keycloak/IssuerInitializerProvider.java deleted file mode 100644 index 6aa6c41..0000000 --- a/fixed-issuer/src/main/java/org/openremote/keycloak/IssuerInitializerProvider.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.openremote.keycloak; - -import com.google.auto.service.AutoService; -import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.ByteBuddy; -import net.bytebuddy.agent.ByteBuddyAgent; -import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; -import net.bytebuddy.implementation.MethodDelegation; -import org.keycloak.Config; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.provider.Provider; -import org.keycloak.provider.ProviderConfigProperty; -import org.keycloak.provider.ProviderConfigurationBuilder; -import org.keycloak.services.Urls; -import org.keycloak.services.validation.Validation; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; - -import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.returns; - -/** - * Copied from https://github.com/dasniko/keycloak-extensions-demo/blob/main/initializer/src/main/java/dasniko/keycloak/initializer/issuer/IssuerInitializerProvider.java - * in order to be able to set a fixed issuer value which is useful when keycloak needs to be accessed by a non public hostname and this isn't supported out of the box, - * see https://github.com/keycloak/keycloak/issues/11584 for discussion. - */ -@Slf4j -@AutoService(InitializerProviderFactory.class) -public class IssuerInitializerProvider implements InitializerProviderFactory { - - public static final String PROVIDER_ID = "issuer"; - - private static final String CONFIG_ATTR_BASE_URI = "base-uri"; - - private static String issuerBaseUri; - - @Override - public String getId() { - return PROVIDER_ID; - } - - @Override - public Provider create(KeycloakSession session) { - return null; - } - - @Override - public void init(Config.Scope config) { - issuerBaseUri = config.get(CONFIG_ATTR_BASE_URI); - if (!Validation.isBlank(issuerBaseUri)) { - log.info("Issuer BaseURI fixed value: {}", issuerBaseUri); - } else { - log.info("No issuer BaseURI provided"); - } - } - - @Override - public void postInit(KeycloakSessionFactory factory) { - if (!Validation.isBlank(issuerBaseUri)) { - ByteBuddyAgent.install(); - new ByteBuddy() - .redefine(Urls.class) - .method(named("realmIssuer").and(isDeclaredBy(Urls.class).and(returns(String.class)))) - .intercept(MethodDelegation.to(this.getClass())) - .make() - .load(Urls.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent()); - } - } - - @SuppressWarnings("unused") - public static String realmIssuer(URI baseUri, String realmName) { - try { - baseUri = new URI(issuerBaseUri); - } catch (URISyntaxException | NullPointerException ignored) { - } - return Urls.realmBase(baseUri).path("{realm}").build(realmName).toString(); - } - - @Override - public List getConfigMetadata() { - return ProviderConfigurationBuilder.create() - .property() - .name(CONFIG_ATTR_BASE_URI) - .type(ProviderConfigProperty.STRING_TYPE) - .helpText("The baseUri to use for the issuer of this server. Keep empty, if the regular hostname settings should be used.") - .add() - .build(); - } -} diff --git a/settings.gradle b/settings.gradle index f5fc7a2..64671b9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,2 @@ -include 'fixed-issuer' include 'self-register-user-configure' include 'theme'