From 11b018899cffd405afd2391e203e863bc4ee77f9 Mon Sep 17 00:00:00 2001
From: "Antoine R. Dumont (@ardumont)" <ardumont@softwareheritage.org>
Date: Tue, 23 Feb 2021 11:05:46 +0100
Subject: [PATCH] keycloak: Add deposit container to keycloak docker compose

So as to be able to play around with keycloak and deposit together.

Related to T2858
---
 docker/conf/deposit-keycloak.yml              |  30 +++
 docker/docker-compose.keycloak.yml            |   9 +
 .../services/keycloak/keycloak_swh_setup.py   | 235 ++++++++++--------
 3 files changed, 171 insertions(+), 103 deletions(-)
 create mode 100644 docker/conf/deposit-keycloak.yml

diff --git a/docker/conf/deposit-keycloak.yml b/docker/conf/deposit-keycloak.yml
new file mode 100644
index 0000000..88c1b4b
--- /dev/null
+++ b/docker/conf/deposit-keycloak.yml
@@ -0,0 +1,30 @@
+scheduler:
+  cls: remote
+  url: http://swh-scheduler:5008
+
+storage:
+  cls: remote
+  url: http://swh-storage:5002/
+
+storage_metadata:
+  cls: remote
+  url: http://swh-storage:5002/
+
+allowed_hosts:
+  - '*'
+
+private:
+  secret_key: prod-in-docker
+  db:
+    host: swh-deposit-db
+    port: 5432
+    name: swh-deposit
+    user: postgres
+    password: testpassword
+  media_root: /tmp/swh-deposit/uploads
+
+extraction_dir: "/tmp/swh-deposit/archive/"
+
+keycloak:
+  server_url: http://keycloak:8080/keycloak/auth/
+  realm_name: SoftwareHeritage
diff --git a/docker/docker-compose.keycloak.yml b/docker/docker-compose.keycloak.yml
index c43a62e..05b5f95 100644
--- a/docker/docker-compose.keycloak.yml
+++ b/docker/docker-compose.keycloak.yml
@@ -33,3 +33,12 @@ services:
       SWH_CONFIG_FILENAME: /web-keycloak.yml
     volumes:
       - "./conf/web-keycloak.yml:/web-keycloak.yml:ro"
+
+  swh-deposit:
+    depends_on:
+      - keycloak
+    environment:
+      SWH_CONFIG_FILENAME: /deposit-keycloak.yml
+    volumes:
+      - "./conf/deposit-keycloak.yml:/deposit-keycloak.yml:ro"
+
diff --git a/docker/services/keycloak/keycloak_swh_setup.py b/docker/services/keycloak/keycloak_swh_setup.py
index f6a4d37..b0c0922 100755
--- a/docker/services/keycloak/keycloak_swh_setup.py
+++ b/docker/services/keycloak/keycloak_swh_setup.py
@@ -1,18 +1,24 @@
 #!/usr/bin/env python3
 
-# Copyright (C) 2020  The Software Heritage developers
+# Copyright (C) 2020-2021  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
+import logging
 from keycloak import KeycloakAdmin
 
 
-server_url = "http://localhost:8080/keycloak/auth/"
-realm_name = "SoftwareHeritage"
-client_name = "swh-web"
+SERVER_URL = "http://localhost:8080/keycloak/auth/"
+REALM_NAME = "SoftwareHeritage"
 
-admin = {"username": "admin", "password": "admin"}
+CLIENT_WEBAPP_NAME = "swh-web"
+CLIENT_DEPOSIT_NAME = "swh-deposit"
+
+ADMIN = {"username": "admin", "password": "admin"}
+
+
+logger = logging.getLogger(__name__)
 
 
 def assign_client_base_url(keycloak_admin, client_name, base_url):
@@ -36,38 +42,40 @@ def assign_client_roles_to_user(keycloak_admin, client_name, client_roles, usern
 def create_user(keycloak_admin, user_data):
     try:
         keycloak_admin.create_user(user_data)
-    except Exception:
-        # user already created
-        pass
+    except Exception as e:
+        logger.warning(f"User already created: {e}, skipping.")
 
 
 def create_client_roles(keycloak_admin, client_name, client_roles):
     for client_role in client_roles:
-        keycloak_admin.create_client_role(client_name, payload={"name": client_role})
+        try:
+            keycloak_admin.create_client_role(client_name, payload={"name": client_role})
+        except Exception as e:
+            logger.warning(f"User already created: {e}, skipping.")
 
 
 # login as admin in master realm
-keycloak_admin = KeycloakAdmin(server_url, admin["username"], admin["password"])
+KEYCLOAK_ADMIN = KeycloakAdmin(SERVER_URL, ADMIN["username"], ADMIN["password"])
 
 # update master realm clients base urls as we use a reverse proxy
 assign_client_base_url(
-    keycloak_admin, "account", "/keycloak/auth/realms/master/account"
+    KEYCLOAK_ADMIN, "account", "/keycloak/auth/realms/master/account"
 )
 
 assign_client_base_url(
-    keycloak_admin,
+    KEYCLOAK_ADMIN,
     "security-admin-console",
     "/keycloak/auth/admin/master/console/index.html",
 )
 
-keycloak_admin.update_realm(
+KEYCLOAK_ADMIN.update_realm(
     "master", payload={"loginTheme": "swh", "accountTheme": "swh", "adminTheme": "swh",}
 )
 
 # create swh realm
-keycloak_admin.create_realm(
+KEYCLOAK_ADMIN.create_realm(
     payload={
-        "realm": realm_name,
+        "realm": REALM_NAME,
         "rememberMe": True,
         "attributes": {"frontendUrl": "http://localhost:5080/keycloak/auth/"},
         "enabled": True,
@@ -79,33 +87,33 @@ keycloak_admin.create_realm(
 )
 
 # set swh realm name in order to create users in it
-keycloak_admin.realm_name = realm_name
+KEYCLOAK_ADMIN.realm_name = REALM_NAME
 
 # update swh realm clients base urls as we use a reverse proxy
 assign_client_base_url(
-    keycloak_admin, "account", f"/keycloak/auth/realms/{realm_name}/account"
+    KEYCLOAK_ADMIN, "account", f"/keycloak/auth/realms/{REALM_NAME}/account"
 )
 
 assign_client_base_url(
-    keycloak_admin,
+    KEYCLOAK_ADMIN,
     "security-admin-console",
-    f"/keycloak/auth/admin/{realm_name}/console/index.html",
+    f"/keycloak/auth/admin/{REALM_NAME}/console/index.html",
 )
 
 # create an admin user in the swh realm
 user_data = {
     "email": "admin@example.org",
-    "username": admin["username"],
-    "firstName": admin["username"],
-    "lastName": admin["username"],
+    "username": ADMIN["username"],
+    "firstName": ADMIN["username"],
+    "lastName": ADMIN["username"],
     "credentials": [
-        {"value": admin["username"], "type": admin["password"], "temporary": False}
+        {"value": ADMIN["username"], "type": ADMIN["password"], "temporary": False}
     ],
     "enabled": True,
     "emailVerified": False,
 }
 
-create_user(keycloak_admin, user_data)
+create_user(KEYCLOAK_ADMIN, user_data)
 
 # assign realm admin roles to created user
 realm_management_roles = [
@@ -128,103 +136,124 @@ realm_management_roles = [
     "manage-users",
     "query-groups",
 ]
+
 assign_client_roles_to_user(
-    keycloak_admin, "realm-management", realm_management_roles, admin["username"]
+    KEYCLOAK_ADMIN, "realm-management", realm_management_roles, ADMIN["username"]
 )
 
 
 # login as admin in swh realm
-keycloak_admin = KeycloakAdmin(
-    server_url, admin["username"], admin["password"], realm_name
+KEYCLOAK_ADMIN = KeycloakAdmin(
+    SERVER_URL, ADMIN["username"], ADMIN["password"], REALM_NAME
 )
 
-# create swh-web public client
-keycloak_admin.create_client(
-    payload={
-        "id": client_name,
-        "clientId": client_name,
-        "surrogateAuthRequired": False,
-        "enabled": True,
-        "redirectUris": ["http://localhost:5004/*",],
-        "bearerOnly": False,
-        "consentRequired": False,
-        "standardFlowEnabled": True,
-        "implicitFlowEnabled": False,
-        "directAccessGrantsEnabled": True,
-        "serviceAccountsEnabled": False,
-        "publicClient": True,
-        "frontchannelLogout": False,
-        "protocol": "openid-connect",
-        "fullScopeAllowed": True,
-        "protocolMappers": [
-            {
-                "name": "user groups",
-                "protocol": "openid-connect",
-                "protocolMapper": "oidc-group-membership-mapper",
-                "consentRequired": False,
-                "config": {
-                    "full.path": True,
-                    "userinfo.token.claim": True,
-                    "id.token.claim": True,
-                    "access.token.claim": True,
-                    "claim.name": "groups",
-                    "jsonType.label": "String",
+for (client_name, client_uri) in [
+        (CLIENT_WEBAPP_NAME, "http://localhost:5004/*"),
+        (CLIENT_DEPOSIT_NAME, "http://localhost:5006/*")
+]:
+    # create swh-web public client
+    KEYCLOAK_ADMIN.create_client(
+        payload={
+            "id": client_name,
+            "clientId": client_name,
+            "surrogateAuthRequired": False,
+            "enabled": True,
+            "redirectUris": [client_uri,],
+            "bearerOnly": False,
+            "consentRequired": False,
+            "standardFlowEnabled": True,
+            "implicitFlowEnabled": False,
+            "directAccessGrantsEnabled": True,
+            "serviceAccountsEnabled": False,
+            "publicClient": True,
+            "frontchannelLogout": False,
+            "protocol": "openid-connect",
+            "fullScopeAllowed": True,
+            "protocolMappers": [
+                {
+                    "name": "user groups",
+                    "protocol": "openid-connect",
+                    "protocolMapper": "oidc-group-membership-mapper",
+                    "consentRequired": False,
+                    "config": {
+                        "full.path": True,
+                        "userinfo.token.claim": True,
+                        "id.token.claim": True,
+                        "access.token.claim": True,
+                        "claim.name": "groups",
+                        "jsonType.label": "String",
+                    },
                 },
-            },
-            {
-                "name": "audience",
-                "protocol": "openid-connect",
-                "protocolMapper": "oidc-audience-mapper",
-                "consentRequired": False,
-                "config": {
-                    "included.client.audience": client_name,
-                    "id.token.claim": True,
-                    "access.token.claim": True,
+                {
+                    "name": "audience",
+                    "protocol": "openid-connect",
+                    "protocolMapper": "oidc-audience-mapper",
+                    "consentRequired": False,
+                    "config": {
+                        "included.client.audience": client_name,
+                        "id.token.claim": True,
+                        "access.token.claim": True,
+                    },
                 },
-            },
-        ],
-    },
-    skip_exists=True,
-)
+            ],
+        },
+        skip_exists=True,
+    )
 
 # create staff group
-keycloak_admin.create_group(payload={"name": "staff",}, skip_exists=True)
+KEYCLOAK_ADMIN.create_group(payload={"name": "staff",}, skip_exists=True)
 
-groups = keycloak_admin.get_groups()
+GROUPS = KEYCLOAK_ADMIN.get_groups()
 
-admin_user_id = keycloak_admin.get_user_id(username=admin["username"])
+ADMIN_USER_ID = KEYCLOAK_ADMIN.get_user_id(username=ADMIN["username"])
 
-for group in groups:
-    if group["name"] == "staff":
-        keycloak_admin.group_user_add(admin_user_id, group["id"])
+for GROUP in GROUPS:
+    if GROUP["name"] == "staff":
+        KEYCLOAK_ADMIN.group_user_add(ADMIN_USER_ID, GROUP["id"])
         break
 
-# create swh-web client roles
+# create webapp client roles
 create_client_roles(
-    keycloak_admin,
-    client_name,
+    KEYCLOAK_ADMIN,
+    CLIENT_WEBAPP_NAME,
     ["swh.web.api.throttling_exempted", "swh.web.api.graph"],
 )
 
-# create some test users
-user_data = {
-    "email": "john.doe@example.org",
-    "username": "johndoe",
-    "firstName": "John",
-    "lastName": "Doe",
-    "credentials": [{"value": "johndoe-swh", "type": "password", "temporary": False}],
-    "enabled": True,
-    "emailVerified": False,
-}
-create_user(keycloak_admin, user_data)
+# create deposit client roles
+create_client_roles(
+    KEYCLOAK_ADMIN,
+    CLIENT_DEPOSIT_NAME,
+    ["swh.deposit.api"],
+)
 
-user_data = {
-    "email": "jane.doe@example.org",
-    "username": "janedoe",
-    "firstName": "Jane",
-    "lastName": "Doe",
-    "credentials": [{"value": "janedoe-swh", "type": "password", "temporary": False}],
-    "enabled": True,
-    "emailVerified": False,
-}
-create_user(keycloak_admin, user_data)
+# create some test users
+for user_data in [
+    {
+        "email": "john.doe@example.org",
+        "username": "johndoe",
+        "firstName": "John",
+        "lastName": "Doe",
+        "credentials": [{"value": "johndoe-swh", "type": "password", "temporary": False}],
+        "enabled": True,
+        "emailVerified": False,
+    },
+    {
+        "email": "jane.doe@example.org",
+        "username": "janedoe",
+        "firstName": "Jane",
+        "lastName": "Doe",
+        "credentials": [{"value": "janedoe-swh", "type": "password", "temporary": False}],
+        "enabled": True,
+        "emailVerified": False,
+    },
+    {
+        "email": "",
+        "username": "hal",
+        "firstName": "HAL",
+        "lastName": "AI",
+        "credentials": [{"value": "test", "type": "password", "temporary": False}],
+        "enabled": True,
+        "emailVerified": False,
+    }
+]:
+    create_user(KEYCLOAK_ADMIN, user_data)
-- 
GitLab