| 1 | #!/usr/bin/env python3 |
| 2 | import json |
| 3 | import sys |
| 4 | |
| 5 | from api import Keycloak |
| 6 | |
| 7 | |
| 8 | config = json.load(sys.stdin) |
| 9 | keycloak = Keycloak(config["host"], config["password"]) |
| 10 | keycloak.configure_profile() |
| 11 | keycloak.request( |
| 12 | "/admin/realms/master", |
| 13 | "PUT", |
| 14 | { |
| 15 | "displayName": "snow sign on", |
| 16 | "displayNameHtml": '<div class="kc-logo-text"><span>snow sign on</span></div>', |
| 17 | "editUsernameAllowed": True, |
| 18 | "resetPasswordAllowed": True, |
| 19 | "rememberMe": True, |
| 20 | "loginWithEmailAllowed": True, |
| 21 | "registrationAllowed": False, |
| 22 | "webAuthnPolicyRpEntityName": "snow sign on", |
| 23 | "webAuthnPolicyPasswordlessPasskeysEnabled": True, |
| 24 | "loginTheme": "snow", |
| 25 | }, |
| 26 | ) |
| 27 | roles_path = "/admin/realms/master/roles" |
| 28 | roles = {role["name"]: role for role in keycloak.request(roles_path)} |
| 29 | for name in ("admin", "infra-admin", "media", "media-manage"): |
| 30 | if name not in roles: |
| 31 | keycloak.request(roles_path, "POST", {"name": name}) |
| 32 | roles[name] = keycloak.request(f"{roles_path}/{name}") |
| 33 | |
| 34 | users = keycloak.request("/admin/realms/master/users?username=admin&exact=true") |
| 35 | if len(users) != 1: |
| 36 | raise ValueError("expected one bootstrap admin user") |
| 37 | if users[0].get("email") or users[0].get("emailVerified"): |
| 38 | keycloak.request( |
| 39 | f"/admin/realms/master/users/{users[0]['id']}", "PUT", |
| 40 | {**users[0], "email": None, "emailVerified": False}, |
| 41 | ) |
| 42 | mapping_path = f"/admin/realms/master/users/{users[0]['id']}/role-mappings/realm" |
| 43 | assigned = {role["name"] for role in keycloak.request(mapping_path)} |
| 44 | missing = [roles[name] for name in ("admin", "media", "media-manage") if name not in assigned] |
| 45 | if missing: |
| 46 | keycloak.request(mapping_path, "POST", missing) |
| 47 | |
| 48 | snow = keycloak.request("/admin/realms/master/users?username=snow&exact=true") |
| 49 | if not snow: |
| 50 | keycloak.request("/admin/realms/master/users", "POST", { |
| 51 | "username": "snow", |
| 52 | "enabled": True, |
| 53 | "credentials": [{"type": "password", "value": config["snow_password"], "temporary": False}], |
| 54 | }) |
| 55 | snow = keycloak.request("/admin/realms/master/users?username=snow&exact=true") |
| 56 | if len(snow) != 1: |
| 57 | raise ValueError("expected one snow user") |
| 58 | if snow[0].get("email") != config["ownerEmail"] or not snow[0].get("emailVerified"): |
| 59 | keycloak.request( |
| 60 | f"/admin/realms/master/users/{snow[0]['id']}", "PUT", |
| 61 | {**snow[0], "email": config["ownerEmail"], "emailVerified": True}, |
| 62 | ) |
| 63 | mapping_path = f"/admin/realms/master/users/{snow[0]['id']}/role-mappings/realm" |
| 64 | assigned = {role["name"] for role in keycloak.request(mapping_path)} |
| 65 | missing = [roles[name] for name in ("infra-admin", "media", "media-manage") if name not in assigned] |
| 66 | if missing: |
| 67 | keycloak.request(mapping_path, "POST", missing) |