Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion dev-env/keycloak/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM quay.io/keycloak/keycloak:26.3.2
FROM quay.io/keycloak/keycloak:26.7.2

# Add the Oracle JDBC jars
ARG ORACLE_JDBC_VERSION=23.8.0.25.04
Expand All @@ -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/

Expand Down
Binary file not shown.
6 changes: 6 additions & 0 deletions dev-env/keycloak/keycloak.conf
Original file line number Diff line number Diff line change
@@ -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
14 changes: 0 additions & 14 deletions dev-env/keycloak/quarkus.properties
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions dev-env/keycloak/setup-spi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Expand Down
10 changes: 6 additions & 4 deletions dev-env/keycloak/test-realm.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -2396,7 +2398,7 @@
"clientSessionMaxLifespan": "0",
"frontendUrl": ""
},
"keycloakVersion": "26.3.2",
"keycloakVersion": "26.7.2",
"userManagedAccessAllowed": false,
"organizationsEnabled": false,
"verifiableCredentialsEnabled": false,
Expand All @@ -2407,4 +2409,4 @@
"clientPolicies": {
"policies": []
}
}
}
3 changes: 2 additions & 1 deletion dev-env/shib-dev-env/keycloak/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM quay.io/keycloak/keycloak:26.3.2
FROM quay.io/keycloak/keycloak:26.7.2

# Add the Oracle JDBC jars
ARG ORACLE_JDBC_VERSION=23.8.0.25.04
Expand All @@ -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/

Expand Down
Binary file not shown.
6 changes: 6 additions & 0 deletions dev-env/shib-dev-env/keycloak/keycloak.conf
Original file line number Diff line number Diff line change
@@ -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
14 changes: 0 additions & 14 deletions dev-env/shib-dev-env/keycloak/quarkus.properties
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions dev-env/shib-dev-env/keycloak/setup-spi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Expand Down
2 changes: 1 addition & 1 deletion dev-env/shib-dev-env/keycloak/test-realm.json
Original file line number Diff line number Diff line change
Expand Up @@ -2636,7 +2636,7 @@
"frontendUrl": "https://localhost",
"acr.loa.map": "{}"
},
"keycloakVersion": "26.1.4",
"keycloakVersion": "26.7.2",
"userManagedAccessAllowed": false,
"organizationsEnabled": false,
"verifiableCredentialsEnabled": false,
Expand Down
143 changes: 122 additions & 21 deletions docs/KEYCLOAK_DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -37,26 +37,60 @@ 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.
(Note that the keycloak.conf file in dev-env is configured to use a file based H2 database for development purposes only. You will need to change the configuration to use a production database for your Keycloak instance. See below for more details.)

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://<SERVER_IP>:<SERVER_PORT>/<DB_NAME>
quarkus.datasource.user-store.username=<DB_USERNAME>
quarkus.datasource.user-store.password=<DB_PASSWORD>
# Keycloak server database.
db=postgres
db-url-full=jdbc:postgresql://<KEYCLOAK_DB_SERVER_IP>:<KEYCLOAK_DB_SERVER_PORT>/<KEYCLOAK_DB_NAME>
db-username=<KEYCLOAK_DB_USERNAME>
db-password=<KEYCLOAK_DB_PASSWORD>

# Dataverse Builtin Users SPI datasource.
db-kind-user-store=postgres
db-url-full-user-store=jdbc:postgresql://<DATAVERSE_DB_SERVER_IP>:<DATAVERSE_DB_SERVER_PORT>/<DATAVERSE_DB_NAME>
db-username-user-store=<DATAVERSE_DB_USERNAME>
db-password-user-store=<DATAVERSE_DB_PASSWORD>
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

quarkus.datasource.user-store.jdbc.recovery.username=<DB_USERNAME>
quarkus.datasource.user-store.jdbc.recovery.password=<DB_PASSWORD>
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.

quarkus.datasource.user-store.jdbc.xa-properties.serverName=<SERVER_IP>
quarkus.datasource.user-store.jdbc.xa-properties.portNumber=<SERVER_PORT>
quarkus.datasource.user-store.jdbc.xa-properties.databaseName=<DB_NAME>
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.

For PostgreSQL, the setup is typically:

```sql
CREATE DATABASE keycloak;
CREATE USER keycloak WITH PASSWORD '<KEYCLOAK_DB_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_SERVER_IP>:<KEYCLOAK_DB_SERVER_PORT>/keycloak
db-username=keycloak
db-password=<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
Expand All @@ -81,10 +115,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_DOMAIN> > keycloak.log 2>&1 &
nohup ./bin/kc.sh start --optimized --bootstrap-admin-username tmpadm --bootstrap-admin-password pass --hostname https://<KEYCLOAK_DOMAIN> > 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:
Expand All @@ -93,7 +133,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_DOMAIN> > keycloak.log 2>&1 &
nohup ./bin/kc.sh start --optimized --hostname https://<KEYCLOAK_DOMAIN> > keycloak.log 2>&1 &
```

Note that the output logs of the command are saved in a file named `keycloak.log`.
Expand Down Expand Up @@ -313,14 +353,16 @@ The following startup file (`/etc/systemd/system/keycloak.service`) has been cre
```
[Unit]
Description=Harvard IQSS Dataverse Keycloak Server
After=syslog.target network.target
After=syslog.target network.target postgresql-16.service
Before=httpd.service
ConditionPathExists=/opt/dvn/keycloak/current/bin/kc.sh
ConditionPathExists=/opt/dvn/keycloak/bin/keycloakstart.sh
Requires=postgresql-16.service

[Service]
User=keycloak
Group=keycloak
ExecStart=/opt/dvn/keycloak/current/bin/kc.sh start --hostname auth.dataverse.harvard.edu --http-enabled=true --proxy-headers xforwarded
Type=forking
ExecStart=/opt/dvn/keycloak/bin/keycloakstart.sh
TimeoutStartSec=600
TimeoutStopSec=600
Restart=on-failure
Expand All @@ -332,6 +374,17 @@ WantedBy=multi-user.target

`systemctl enable keycloak` to make sure Keycloak starts every time the instance boots.

Note that the systemd file above references another shell script, `/opt/dvn/keycloak/bin/keycloakstart.sh` that does the actual starting.

```
$ cat /opt/dvn/keycloak/bin/keycloakstart.sh
#!/bin/sh

export DIRECTORY=/opt/dvn/keycloak/current

nohup ${DIRECTORY}/bin/kc.sh start --hostname auth.dataverse.harvard.edu --optimized --http-enabled=true --proxy-headers xforwarded > /var/log/keycloak.log 2>&1 &
```

### Register the Keycloak Dataverse Backend OIDC client in Dataverse

Both the JVM options from this step and the next must be registered within the instance where your Dataverse installation is hosted.
Expand All @@ -352,3 +405,51 @@ In the Dataverse instance, you need to enable different OIDC-related feature fla
- `dataverse.feature.api-bearer-auth`
- `dataverse.feature.api-bearer-auth-provide-missing-claims`
- `dataverse.feature.api-bearer-auth-use-builtin-user-on-id-match`

### Upgrades

This section implies a production, or a permanent test/demo etc. instance.
A developer will not be expected to need to upgrade a keycloak instance started as part of their personal dev. environment. It should be easier to simply start a new version from scratch.

The process below also assumes that an external PostgreSQL, or a similar database is used to store the realm(s) and users information. This way the database does not need to be exported and reimported into the new keycloak instance.

An upgrade from 26.7.0 to 26.7.2 is used in the command lines below. Adjust as needed (same for the directories used in the examples)

1. Build a new `builtin-users-spi` jar file; make sure the target keycloak version is reflected in the `pom.xml` and any extra user stores - if the keycloak instance serves more than one realm - are listed in the `persistence.xml` file.
2. Stop the old keycloak: `sudo systemctl stop keycloak`
3. If you want to be safe, back up the database (exercise for the user)
4. Download and unzip the new version and switch the link:

```
cd /usr/local/keycloak
sudo unzip /tmp/keycloak-26.7.2.zip
sudo rm current
sudo ln -s keycloak-26.7.2 current
```

5. Copy the new authenticator jar in place:
`sudo cp /tmp/keycloak-dv-builtin-users-authenticator-1.0-SNAPSHOT.jar current/providers/`
6. Copy the other 3 jar files (assumes these have not changed and can be reused!)

```
sudo cp keycloak-26.7.0/providers/dv-spa-kc-theme.jar current/providers/
sudo cp keycloak-26.7.0/providers/ojdbc11-23.8.0.25.04.jar current/providers/
sudo cp keycloak-26.7.0/providers/orai18n-23.8.0.25.04.jar current/providers/
```

7. Copy the config files: (same assumption, that nothing has changed since the last version; consult the installation instruction to be sure)

```
sudo cp keycloak-26.7.0/conf/keycloak.conf current/conf/
sudo cp keycloak-26.7.0/conf/quarkus.properties current/conf/
```

8. Build:

```
cd current
sudo ./bin/kc.sh build
```

You can now start keycloak. Using the setup shown above, with the link `current` always pointing to the latest version, no changes should be needed to the startup.
None of the extra configuration steps described in the installation instructions are needed, since all the configuration information has been preserved in the database.
Loading