Add script to add `sourcearcade` realm to Keycloak
diff --git a/TODO.on.site b/TODO.on.site
index da83a0e..ac2f4f1 100644
--- a/TODO.on.site
+++ b/TODO.on.site
@@ -6,7 +6,7 @@
 Create environment files (cf. `git ls-files \*environment.template`):
 * Set SA_PUBLIC_DOMAIN_NAME in `environment`
 * Set CANONICAL_WEB_URL in `gerrit/environment`
-* Enable GitHub OAUTH in `gerrit/environment`
+* Enable GitHub OAUTH in `keycloak/environment`
 
 Building using self-signed certificates:
 We always create a temporary, self-signed certificate which
diff --git a/docker-compose.yml b/docker-compose.yml
index c45cf79..94eb724 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -61,6 +61,21 @@
       - KC_DB_POOL_MAX_SIZE=16
       - KEYCLOAK_ADMIN=deusarcadia
       - KEYCLOAK_ADMIN_PASSWORD=arcanumhomini
+  keycloak-init-realm:
+    depends_on:
+      - keycloak
+    build:
+      context: ./keycloak/init/
+    env_file:
+      - keycloak/environment
+      - environment
+    environment:
+      - KEYCLOAK_ADMIN=deusarcadia
+      - KEYCLOAK_ADMIN_PASSWORD=arcanumhomini
+    networks:
+      - kcnet
+    secrets:
+      - seed
   simpleid:
     build:
       context: .
diff --git a/gerrit/Dockerfile.entrypoint b/gerrit/Dockerfile.entrypoint
index 7079792..fefd704 100644
--- a/gerrit/Dockerfile.entrypoint
+++ b/gerrit/Dockerfile.entrypoint
@@ -8,6 +8,7 @@
 }
 
 export GERRIT_MAIL_PASSWORD=$(secret mail:gerrit)
+export GERRIT_KC_PASSWORD=$(secret kc:gerrit)
 
 # Allows us to bind mount arbitrary owned files
 chown -R gerrit:gerrit /var/gerrit/{logs,etc,db,git,index,cache}/
diff --git a/gerrit/Dockerfile.entrypoint-unprivileged b/gerrit/Dockerfile.entrypoint-unprivileged
index 1771d81..b768dbc 100644
--- a/gerrit/Dockerfile.entrypoint-unprivileged
+++ b/gerrit/Dockerfile.entrypoint-unprivileged
@@ -30,4 +30,15 @@
     git config -f ${config} sendemail.html false
 fi
 
+if [ "${GERRIT_KC_PASSWORD}" ]; then
+    kc_oauth=plugin.gerrit-oauth-provider-keycloak-oauth
+
+    git config -f ${config} ${kc_oauth}.root-url https://id.${SA_PUBLIC_DOMAIN_NAME}/
+    git config -f ${config} ${kc_oauth}.realm sourcearcade
+    git config -f ${config} ${kc_oauth}.client-id gerrit
+    git config -f ${config} ${kc_oauth}.client-secret ${GERRIT_KC_PASSWORD}
+    git config -f ${config} ${kc_oauth}.use-preferred-username true
+    git config -f ${config} --add auth.trustedOpenID keycloak-oauth:
+fi
+
 exec /entrypoint.sh "$@"
diff --git a/keycloak/.gitignore b/keycloak/.gitignore
new file mode 100644
index 0000000..a4b9cf8
--- /dev/null
+++ b/keycloak/.gitignore
@@ -0,0 +1 @@
+/environment
diff --git a/keycloak/environment.template b/keycloak/environment.template
new file mode 100644
index 0000000..f6ac757
--- /dev/null
+++ b/keycloak/environment.template
@@ -0,0 +1,3 @@
+# Set to enable GitHub OAUTH
+# GITHUB_OAUTH_CLIENT_ID=
+# GITHUB_OAUTH_CLIENT_SECRET=
diff --git a/keycloak/init/Dockerfile b/keycloak/init/Dockerfile
new file mode 100644
index 0000000..29f76bc
--- /dev/null
+++ b/keycloak/init/Dockerfile
@@ -0,0 +1,5 @@
+ARG KC_TAG=22.0
+FROM quay.io/keycloak/keycloak:${KC_TAG}
+
+COPY sa-up /opt/keycloak/bin/sa-up.sh
+ENTRYPOINT ["/bin/sh", "/opt/keycloak/bin/sa-up.sh"]
diff --git a/keycloak/init/sa-up b/keycloak/init/sa-up
new file mode 100644
index 0000000..768c784
--- /dev/null
+++ b/keycloak/init/sa-up
@@ -0,0 +1,97 @@
+#!/bin/sh
+
+set -eu
+
+kca() {
+    /opt/keycloak/bin/kcadm.sh "$@"
+}
+
+kca_cred() {
+    kca config credentials \
+        --server http://keycloak:8080 \
+        --realm master \
+        --user ${KEYCLOAK_ADMIN} \
+        --password ${KEYCLOAK_ADMIN_PASSWORD}
+}
+
+secret() {
+    seed=$(cat /run/secrets/seed)
+    printf "%s:%40s" "${seed}" "$*" | sha256sum | sed 's/[[:space:]].*//'
+}
+
+i=15
+sleep ${i} # give it a moment to come up
+while kca_cred 2>&1 | grep -q 'Connection refused\|Bad Gateway'; do
+    if [ ${i} -eq 60 ]; then
+        echo "ERROR: Couldn't login to Keycloak after ${i}s."
+        exit 1
+    fi
+    echo Waiting...
+    sleep 1
+    i=$((i+1))
+done
+if ! kca_cred; then
+    echo "ERROR: Failed to login to Keycloak."
+    exit 2
+fi
+
+REALM=${SA_REALM:-sourcearcade}
+if kca get realms/${REALM} --fields id >/dev/null 2>&1; then
+    echo Realm ${REALM} already set up.
+else
+    kca create realms -f - <<EOF
+    {
+        "realm"                 : "${REALM}",
+        "enabled"               : true,
+        "sslRequired"           : "all",
+        "registrationAllowed"   : true,
+        "resetPasswordAllowed"  : true,
+        "rememberMe"            : true,
+        "verifyEmail"           : true,
+        "smtpServer" : {
+            "host"              : "mail.${SA_PUBLIC_DOMAIN_NAME}",
+            "port"              : "465",
+            "auth"              : true,
+            "ssl"               : true,
+            "user"              : "keycloak@${SA_PUBLIC_DOMAIN_NAME}",
+            "password"          : "$(secret mail:keycloak)",
+            "from"              : "keycloak@${SA_PUBLIC_DOMAIN_NAME}",
+            "fromDisplayName"   : "SourceArcade"
+        },
+        "identityProviders" : [ {
+            "alias"             : "github",
+            "providerId"        : "github",
+            "enabled"           : true,
+            "config" : {
+                "clientId"      : "${GITHUB_OAUTH_CLIENT_ID}",
+                "clientSecret"  : "${GITHUB_OAUTH_CLIENT_SECRET}"
+            }
+        } ]
+    }
+EOF
+
+    ac_id=$(kca get clients -r ${REALM} -q clientId=account-console --fields id \
+            | sed -n 's/.*"id" : "\(.*\)".*/\1/p')
+    kca update clients/${ac_id} -r ${REALM} -s webOrigins='[ "+" ]'
+
+    echo New realm ${REALM} set up.
+fi
+
+if kca get clients -r ${REALM} -q clientId=gerrit --fields clientId | grep -q gerrit; then
+    echo Gerrit client in realm ${REALM} already set up.
+else
+    kca create clients -r ${REALM} -f - <<EOF
+    {
+        "clientId"                  : "gerrit",
+        "name"                      : "Gerrit",
+        "enabled"                   : true,
+        "description"               : "SourceArcade review platform",
+        "rootUrl"                   : "https://review.${SA_PUBLIC_DOMAIN_NAME}",
+        "clientAuthenticatorType"   : "client-secret",
+        "secret"                    : "$(secret kc:gerrit)",
+        "protocol"                  : "openid-connect",
+        "directAccessGrantsEnabled" : false
+    }
+EOF
+    echo Gerrit client in realm ${REALM} set up.
+fi
diff --git a/mail/config/user-patches.sh b/mail/config/user-patches.sh
index 4879036..dc94987 100644
--- a/mail/config/user-patches.sh
+++ b/mail/config/user-patches.sh
@@ -29,7 +29,7 @@
 }
 
 {
-    add_users_with_passwd gerrit
+    add_users_with_passwd gerrit keycloak
 
     # Restrict gerrit@ sending to local IP:
     if ! grep -q gerrit /tmp/docker-mailserver/user.access 2>/dev/null; then