diff --git a/dev-env/keycloak/Dockerfile b/dev-env/keycloak/Dockerfile index 3b0bc8bac..1628cf148 100644 --- a/dev-env/keycloak/Dockerfile +++ b/dev-env/keycloak/Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/keycloak/keycloak:26.3.2 +FROM quay.io/keycloak/keycloak:26.7.0 # Add the Oracle JDBC jars ARG ORACLE_JDBC_VERSION=23.8.0.25.04 @@ -12,6 +12,7 @@ ENV KC_HEALTH_ENABLED=true COPY keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar /opt/keycloak/providers/ # Copy additional configurations +COPY keycloak.conf /opt/keycloak/conf/ COPY quarkus.properties /opt/keycloak/conf/ COPY test-realm.json /opt/keycloak/data/import/ diff --git a/dev-env/keycloak/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar b/dev-env/keycloak/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar index 051b8f1b3..5a4bd0765 100644 Binary files a/dev-env/keycloak/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar and b/dev-env/keycloak/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar differ diff --git a/dev-env/keycloak/keycloak.conf b/dev-env/keycloak/keycloak.conf new file mode 100644 index 000000000..125338107 --- /dev/null +++ b/dev-env/keycloak/keycloak.conf @@ -0,0 +1,6 @@ +db-kind-user-store=postgres +db-url-full-user-store=jdbc:postgresql://${DATAVERSE_DB_HOST}:${DATAVERSE_DB_PORT}/dataverse +db-username-user-store=${DATAVERSE_DB_USER} +db-password-user-store=${DATAVERSE_DB_PASSWORD} +db-driver-user-store=org.postgresql.Driver +transaction-xa-enabled-user-store=false diff --git a/dev-env/keycloak/quarkus.properties b/dev-env/keycloak/quarkus.properties index 64ce6d898..ebb14d8f4 100644 --- a/dev-env/keycloak/quarkus.properties +++ b/dev-env/keycloak/quarkus.properties @@ -1,15 +1 @@ -quarkus.datasource.user-store.db-kind=postgresql -quarkus.datasource.user-store.jdbc.url=jdbc:postgresql://${DATAVERSE_DB_HOST}:${DATAVERSE_DB_PORT}/dataverse -quarkus.datasource.user-store.username=${DATAVERSE_DB_USER} -quarkus.datasource.user-store.password=${DATAVERSE_DB_PASSWORD} - -quarkus.datasource.user-store.jdbc.driver=org.postgresql.Driver -quarkus.datasource.user-store.jdbc.transactions=disabled quarkus.transaction-manager.unsafe-multiple-last-resources=allow - -quarkus.datasource.user-store.jdbc.recovery.username=${DATAVERSE_DB_USER} -quarkus.datasource.user-store.jdbc.recovery.password=${DATAVERSE_DB_PASSWORD} - -quarkus.datasource.user-store.jdbc.xa-properties.serverName=${DATAVERSE_DB_HOST} -quarkus.datasource.user-store.jdbc.xa-properties.portNumber=${DATAVERSE_DB_PORT} -quarkus.datasource.user-store.jdbc.xa-properties.databaseName=dataverse diff --git a/dev-env/keycloak/setup-spi.sh b/dev-env/keycloak/setup-spi.sh index 5e0fa29f7..bd6924a07 100755 --- a/dev-env/keycloak/setup-spi.sh +++ b/dev-env/keycloak/setup-spi.sh @@ -27,6 +27,14 @@ ADMIN_TOKEN=$(curl -s -X POST "http://keycloak:9080/realms/master/protocol/openi -d "grant_type=password" \ -d "client_id=admin-cli" | jq -r .access_token) +EXISTING_SPI_COUNT=$(curl -s "http://keycloak:9080/admin/realms/test/components" \ + -H "Authorization: Bearer $ADMIN_TOKEN" | jq '[.[] | select(.providerId == "dv-builtin-users-authenticator" and .providerType == "org.keycloak.storage.UserStorageProvider")] | length') + +if [ "$EXISTING_SPI_COUNT" -gt 0 ]; then + echo "Keycloak SPI already configured in realm." + exit 0 +fi + # Create user storage provider using the components endpoint curl -X POST "http://keycloak:9080/admin/realms/test/components" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ diff --git a/dev-env/keycloak/test-realm.json b/dev-env/keycloak/test-realm.json index 571a1e80f..7921e6e26 100644 --- a/dev-env/keycloak/test-realm.json +++ b/dev-env/keycloak/test-realm.json @@ -842,9 +842,11 @@ "alwaysDisplayInConsole": false, "clientAuthenticatorType": "client-secret", "redirectUris": [ - "*" + "http://localhost:8000/modern/*" + ], + "webOrigins": [ + "http://localhost:8000" ], - "webOrigins": [], "notBefore": 0, "bearerOnly": false, "consentRequired": false, @@ -2396,7 +2398,7 @@ "clientSessionMaxLifespan": "0", "frontendUrl": "" }, - "keycloakVersion": "26.3.2", + "keycloakVersion": "26.7.0", "userManagedAccessAllowed": false, "organizationsEnabled": false, "verifiableCredentialsEnabled": false, @@ -2407,4 +2409,4 @@ "clientPolicies": { "policies": [] } -} \ No newline at end of file +} diff --git a/dev-env/shib-dev-env/keycloak/Dockerfile b/dev-env/shib-dev-env/keycloak/Dockerfile index 3b0bc8bac..1628cf148 100644 --- a/dev-env/shib-dev-env/keycloak/Dockerfile +++ b/dev-env/shib-dev-env/keycloak/Dockerfile @@ -1,4 +1,4 @@ -FROM quay.io/keycloak/keycloak:26.3.2 +FROM quay.io/keycloak/keycloak:26.7.0 # Add the Oracle JDBC jars ARG ORACLE_JDBC_VERSION=23.8.0.25.04 @@ -12,6 +12,7 @@ ENV KC_HEALTH_ENABLED=true COPY keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar /opt/keycloak/providers/ # Copy additional configurations +COPY keycloak.conf /opt/keycloak/conf/ COPY quarkus.properties /opt/keycloak/conf/ COPY test-realm.json /opt/keycloak/data/import/ diff --git a/dev-env/shib-dev-env/keycloak/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar b/dev-env/shib-dev-env/keycloak/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar index 3aa3ba47a..5a4bd0765 100644 Binary files a/dev-env/shib-dev-env/keycloak/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar and b/dev-env/shib-dev-env/keycloak/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar differ diff --git a/dev-env/shib-dev-env/keycloak/keycloak.conf b/dev-env/shib-dev-env/keycloak/keycloak.conf new file mode 100644 index 000000000..125338107 --- /dev/null +++ b/dev-env/shib-dev-env/keycloak/keycloak.conf @@ -0,0 +1,6 @@ +db-kind-user-store=postgres +db-url-full-user-store=jdbc:postgresql://${DATAVERSE_DB_HOST}:${DATAVERSE_DB_PORT}/dataverse +db-username-user-store=${DATAVERSE_DB_USER} +db-password-user-store=${DATAVERSE_DB_PASSWORD} +db-driver-user-store=org.postgresql.Driver +transaction-xa-enabled-user-store=false diff --git a/dev-env/shib-dev-env/keycloak/quarkus.properties b/dev-env/shib-dev-env/keycloak/quarkus.properties index 64ce6d898..ebb14d8f4 100644 --- a/dev-env/shib-dev-env/keycloak/quarkus.properties +++ b/dev-env/shib-dev-env/keycloak/quarkus.properties @@ -1,15 +1 @@ -quarkus.datasource.user-store.db-kind=postgresql -quarkus.datasource.user-store.jdbc.url=jdbc:postgresql://${DATAVERSE_DB_HOST}:${DATAVERSE_DB_PORT}/dataverse -quarkus.datasource.user-store.username=${DATAVERSE_DB_USER} -quarkus.datasource.user-store.password=${DATAVERSE_DB_PASSWORD} - -quarkus.datasource.user-store.jdbc.driver=org.postgresql.Driver -quarkus.datasource.user-store.jdbc.transactions=disabled quarkus.transaction-manager.unsafe-multiple-last-resources=allow - -quarkus.datasource.user-store.jdbc.recovery.username=${DATAVERSE_DB_USER} -quarkus.datasource.user-store.jdbc.recovery.password=${DATAVERSE_DB_PASSWORD} - -quarkus.datasource.user-store.jdbc.xa-properties.serverName=${DATAVERSE_DB_HOST} -quarkus.datasource.user-store.jdbc.xa-properties.portNumber=${DATAVERSE_DB_PORT} -quarkus.datasource.user-store.jdbc.xa-properties.databaseName=dataverse diff --git a/dev-env/shib-dev-env/keycloak/setup-spi.sh b/dev-env/shib-dev-env/keycloak/setup-spi.sh index 5e0fa29f7..bd6924a07 100755 --- a/dev-env/shib-dev-env/keycloak/setup-spi.sh +++ b/dev-env/shib-dev-env/keycloak/setup-spi.sh @@ -27,6 +27,14 @@ ADMIN_TOKEN=$(curl -s -X POST "http://keycloak:9080/realms/master/protocol/openi -d "grant_type=password" \ -d "client_id=admin-cli" | jq -r .access_token) +EXISTING_SPI_COUNT=$(curl -s "http://keycloak:9080/admin/realms/test/components" \ + -H "Authorization: Bearer $ADMIN_TOKEN" | jq '[.[] | select(.providerId == "dv-builtin-users-authenticator" and .providerType == "org.keycloak.storage.UserStorageProvider")] | length') + +if [ "$EXISTING_SPI_COUNT" -gt 0 ]; then + echo "Keycloak SPI already configured in realm." + exit 0 +fi + # Create user storage provider using the components endpoint curl -X POST "http://keycloak:9080/admin/realms/test/components" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ diff --git a/dev-env/shib-dev-env/keycloak/test-realm.json b/dev-env/shib-dev-env/keycloak/test-realm.json index 0b53d51db..78d5a2ca8 100644 --- a/dev-env/shib-dev-env/keycloak/test-realm.json +++ b/dev-env/shib-dev-env/keycloak/test-realm.json @@ -2636,7 +2636,7 @@ "frontendUrl": "https://localhost", "acr.loa.map": "{}" }, - "keycloakVersion": "26.1.4", + "keycloakVersion": "26.7.0", "userManagedAccessAllowed": false, "organizationsEnabled": false, "verifiableCredentialsEnabled": false, diff --git a/docs/KEYCLOAK_DEPLOYMENT.md b/docs/KEYCLOAK_DEPLOYMENT.md index 6e19cd4e3..449d023e3 100644 --- a/docs/KEYCLOAK_DEPLOYMENT.md +++ b/docs/KEYCLOAK_DEPLOYMENT.md @@ -10,8 +10,8 @@ Install [Keycloak](https://www.keycloak.org/downloads.html) from the official we Download the following JAR files from the URLs below, and place them in the `keycloak-26.X.X/providers` directory: -- [ojdbc11-23.7.0.25.01.jar](https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc11/23.7.0.25.01/ojdbc11-23.7.0.25.01.jar) -- [orai18n-23.7.0.25.01.jar](https://repo1.maven.org/maven2/com/oracle/database/nls/orai18n/23.7.0.25.01/orai18n-23.7.0.25.01.jar) +- [ojdbc11-23.8.0.25.04.jar](https://repo1.maven.org/maven2/com/oracle/database/jdbc/ojdbc11/23.8.0.25.04/ojdbc11-23.8.0.25.04.jar) +- [orai18n-23.8.0.25.04.jar](https://repo1.maven.org/maven2/com/oracle/database/nls/orai18n/23.8.0.25.04/orai18n-23.8.0.25.04.jar) The `ojdbc11` JAR provides the actual JDBC driver required for database connectivity. The `orai18n` JAR provides additional character-set and localization support required by the driver in certain environments. @@ -37,26 +37,59 @@ npm run build-keycloak-theme Copy the generated `dv-spa-kc-theme.jar` file to your Keycloak instance’s `keycloak-26.X.X/providers` directory. -### Create quarkus.properties +### Create keycloak.conf + +Inside the `keycloak-26.X.X/conf` directory, create a `keycloak.conf` file with the following database configuration, replacing the bracketed variables with the corresponding values for your environment. -Inside the `keycloak-26.X.X/conf` directory, create the following file, replacing the bracketed variables with the corresponding values for the Dataverse database that the SPI will access. +The first database block configures Keycloak's own database, which stores realm, client, session, and server state. The `user-store` named datasource block configures the Dataverse database connection used by the Builtin Users SPI. ```properties -quarkus.datasource.user-store.db-kind=postgresql -quarkus.datasource.user-store.jdbc.url=jdbc:postgresql://:/ -quarkus.datasource.user-store.username= -quarkus.datasource.user-store.password= +# Keycloak server database. +db=postgres +db-url-full=jdbc:postgresql://:/ +db-username= +db-password= + +# Dataverse Builtin Users SPI datasource. +db-kind-user-store=postgres +db-url-full-user-store=jdbc:postgresql://:/ +db-username-user-store= +db-password-user-store= +db-driver-user-store=org.postgresql.Driver +transaction-xa-enabled-user-store=false +``` -quarkus.datasource.user-store.jdbc.driver=org.postgresql.Driver -quarkus.datasource.user-store.jdbc.transactions=disabled -quarkus.transaction-manager.unsafe-multiple-last-resources=allow +### Production Database Setup + +Keycloak includes an embedded H2 database driver for development purposes only. Do not use H2 for production, and do not rely on the development-mode database files for a deployed Keycloak instance. + +For production, create a dedicated relational database for Keycloak before starting the server. This database is separate from the Dataverse database used by the Builtin Users SPI. -quarkus.datasource.user-store.jdbc.recovery.username= -quarkus.datasource.user-store.jdbc.recovery.password= +For PostgreSQL, the setup is typically: -quarkus.datasource.user-store.jdbc.xa-properties.serverName= -quarkus.datasource.user-store.jdbc.xa-properties.portNumber= -quarkus.datasource.user-store.jdbc.xa-properties.databaseName= +```sql +CREATE DATABASE keycloak; +CREATE USER keycloak WITH PASSWORD ''; +GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak; +\c keycloak +GRANT ALL ON SCHEMA public TO keycloak; +``` + +Then configure the Keycloak database connection in `keycloak.conf`: + +```properties +db=postgres +db-url-full=jdbc:postgresql://:/keycloak +db-username=keycloak +db-password= +``` + +### Create quarkus.properties + +Inside the `keycloak-26.X.X/conf` directory, create a `quarkus.properties` file with the following transaction-manager setting. + +```properties +quarkus.transaction-manager.unsafe-multiple-last-resources=allow ``` ### SSL configuration @@ -81,10 +114,16 @@ Once the certificate and key have been uploaded to the instance, you need to con ### Running Keycloak +For a production deployment, build the optimized Keycloak server after the configuration files and provider JARs are in place: + +```bash +./bin/kc.sh build +``` + Run Keycloak for the first time on the instance using the following command. ```bash -nohup ./bin/kc.sh start --bootstrap-admin-username tmpadm --bootstrap-admin-password pass --hostname https:// > keycloak.log 2>&1 & +nohup ./bin/kc.sh start --optimized --bootstrap-admin-username tmpadm --bootstrap-admin-password pass --hostname https:// > keycloak.log 2>&1 & ``` This command will set up an admin user so you can log in and create a permanent one from the Keycloak Admin Console: @@ -93,7 +132,7 @@ This command will set up an admin user so you can log in and create a permanent For subsequent executions of Keycloak, you can use the following command omitting the admin user bootstrapping parameters: ```bash -nohup ./bin/kc.sh start --hostname https:// > keycloak.log 2>&1 & +nohup ./bin/kc.sh start --optimized --hostname https:// > keycloak.log 2>&1 & ``` Note that the output logs of the command are saved in a file named `keycloak.log`.