iac/apps/django/uralkal/zitadel-action-configmap.yaml

132 lines
4.6 KiB
YAML

apiVersion: v1
kind: ConfigMap
metadata:
name: zitadel-action-create-user
namespace: django
data:
createUser.js: |
function createUser(ctx, api) {
let http = require('zitadel/http');
let logger = require('zitadel/log');
const BACKEND_HOST = 'http://backend-svc.django.svc.cluster.local:80/api'
const USER_COMPANIES = [1]
const BASIC_AUTH = '__BASIC_AUTH__'
logger.log('Creating external user in backend');
logger.log('Context: ' + JSON.stringify(ctx));
const userData = {
first_name: ctx.v1.user.human.firstName,
last_name: ctx.v1.user.human.lastName,
email: ctx.v1.user.human.email,
username: ctx.v1.user.username,
companies: USER_COMPANIES,
departments: [],
user_permissions: []
};
logger.log('Sending user data: ' + JSON.stringify(userData));
const response = http.fetch(BACKEND_HOST + '/core/admin/users/external/', {
method: 'POST',
body: userData,
headers: {
'Content-Type': 'application/json',
'Authorization': BASIC_AUTH
}
});
if (response.status != 200 && response.status != 201) {
logger.log('Error response status: ' + response.status);
logger.log('Error response body: ' + response.text());
throw "Backend API error: " + response.status;
}
const metadata = response.json();
logger.log('Metadata received: ' + JSON.stringify(metadata));
Object.keys(metadata).forEach(function(key) {
var value = metadata[key];
logger.log('Setting metadata - Key: ' + key + ', Value: ' + value);
api.v1.user.appendMetadata(key, value);
});
logger.log('External user successfully created and metadata set');
}
apply.py: |
import os
import sys
import httpx
ZITADEL = os.environ["ZITADEL_URL"]
HEADERS = {
"Host": os.environ["ZITADEL_HOST"],
"X-Forwarded-Proto": "https",
"Authorization": "Bearer " + open("/vault/secrets/zitadel-token").read().strip(),
"Content-Type": "application/json",
}
ORG_NAME = os.environ["ZITADEL_ORG_NAME"]
ACTION_NAME = os.environ["ACTION_NAME"]
FLOW_TYPE = os.environ["FLOW_TYPE"]
TRIGGER_TYPE = os.environ["TRIGGER_TYPE"]
client = httpx.Client(base_url=ZITADEL, headers=HEADERS, timeout=30)
def call(method, path, body=None, org_id=None, allow=()):
headers = {"x-zitadel-orgid": org_id} if org_id else {}
r = client.request(method, path, json=body, headers=headers)
if r.status_code in allow:
return None
if r.status_code >= 300:
print(f"{method} {path} -> {r.status_code}: {r.text}")
sys.exit(1)
return r.json() if r.content else {}
me = call("GET", "/auth/v1/users/me")["user"]
print(f"token user {me.get('userName')} id={me.get('id')}")
org = None
found_orgs = call("POST", "/admin/v1/orgs/_search", {"queries": []}, allow=(403,))
if found_orgs is not None:
orgs = found_orgs.get("result", [])
org = next((o for o in orgs if o.get("name", "").lower() == ORG_NAME.lower()), None)
if org is None:
print(f"org '{ORG_NAME}' not found, available: {[o.get('name') for o in orgs]}")
sys.exit(1)
else:
org = call("GET", "/management/v1/orgs/me")["org"]
print(f"no instance permissions, using token org '{org.get('name')}'")
if org.get("name", "").lower() != ORG_NAME.lower():
print(f"token org is '{org.get('name')}', not '{ORG_NAME}'")
sys.exit(1)
org_id = org["id"]
print(f"org {org['name']} id={org_id}")
script = open("/opt/action/createUser.js").read().replace(
"__BASIC_AUTH__", "Basic " + open("/vault/secrets/backend-basic").read().strip()
)
body = {"name": ACTION_NAME, "script": script, "timeout": "10s", "allowedToFail": False}
found = call(
"POST",
"/management/v1/actions/_search",
{"queries": [{"actionNameQuery": {"name": ACTION_NAME, "method": "TEXT_QUERY_METHOD_EQUALS"}}]},
org_id,
).get("result", [])
if found:
action_id = found[0]["id"]
call("PUT", f"/management/v1/actions/{action_id}", body, org_id)
print(f"action {ACTION_NAME} updated id={action_id}")
else:
action_id = call("POST", "/management/v1/actions", body, org_id)["id"]
print(f"action {ACTION_NAME} created id={action_id}")
call("POST", f"/management/v1/flows/{FLOW_TYPE}/trigger/{TRIGGER_TYPE}", {"actionIds": [action_id]}, org_id)
print(f"flow {FLOW_TYPE} trigger {TRIGGER_TYPE} -> {ACTION_NAME}")