generated from coulomb/repo-seed
fix(lldap): fix gql() brace bug + use LDAP for password setting
Three fixes:
1. gql() default vars '${2:-{}}' — bash parsed first '}' as closing the
parameter expansion, appending a stray '}' to every caller's vars.
Fixed by storing '{}' in a local variable first.
2. make_vars() — add VAR_INT_KEYS support so groupId is emitted as a
JSON integer (Int!) rather than a string, matching LLDAP's schema.
3. Password setting — LLDAP has no GraphQL mutation for admin password
reset. Replace the broken resetUserPasswordFromAdmin mutation with
an RFC 3062 LDAP Password Modify operation via kubectl port-forward
to the in-cluster LLDAP service, using ldap3.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -65,7 +65,8 @@ LLDAP_TOKEN=$(curl -sf -X POST "$LLDAP_URL/auth/simple/login" \
|
||||
# with special characters (spaces, quotes) in display names or emails.
|
||||
gql() {
|
||||
local query="$1"
|
||||
local vars="${2:-{}}"
|
||||
local _empty="{}"
|
||||
local vars="${2:-$_empty}"
|
||||
local body
|
||||
body=$(GQL_QUERY="$query" GQL_VARS="$vars" python3 -c "
|
||||
import json, os
|
||||
@@ -80,14 +81,17 @@ print(json.dumps({
|
||||
-d "$body"
|
||||
}
|
||||
|
||||
# Build variables JSON safely via env vars
|
||||
# Build variables JSON safely via env vars.
|
||||
# Set VAR_INT_KEYS to a comma-separated list of keys that should be JSON integers.
|
||||
make_vars() {
|
||||
python3 -c "
|
||||
import json, os
|
||||
d = {}
|
||||
int_keys = set(k for k in os.environ.get('VAR_INT_KEYS','').split(',') if k)
|
||||
for k in os.environ.get('VAR_KEYS','').split(','):
|
||||
if k:
|
||||
d[k] = os.environ.get('VAR_' + k, '')
|
||||
v = os.environ.get('VAR_' + k, '')
|
||||
d[k] = int(v) if k in int_keys else v
|
||||
print(json.dumps(d))
|
||||
"
|
||||
}
|
||||
@@ -142,7 +146,7 @@ fi
|
||||
|
||||
# ── Add to net-kingdom-users ──────────────────────────────────────────────────
|
||||
echo "Adding '$USERNAME' to net-kingdom-users (id=$USERS_GID) ..."
|
||||
VARS=$(VAR_KEYS="uid,gid" VAR_uid="$USERNAME" VAR_gid="$USERS_GID" make_vars)
|
||||
VARS=$(VAR_KEYS="uid,gid" VAR_INT_KEYS="gid" VAR_uid="$USERNAME" VAR_gid="$USERS_GID" make_vars)
|
||||
ADD_RESP=$(gql \
|
||||
'mutation AddToGroup($uid: String!, $gid: Int!) { addUserToGroup(userId: $uid, groupId: $gid) { ok } }' \
|
||||
"$VARS")
|
||||
@@ -157,7 +161,7 @@ if [[ -n "$ADMIN_FLAG" ]]; then
|
||||
echo " WARNING: group 'net-kingdom-admins' not found — skipping." >&2
|
||||
else
|
||||
echo "Adding '$USERNAME' to net-kingdom-admins (id=$ADMINS_GID) ..."
|
||||
VARS=$(VAR_KEYS="uid,gid" VAR_uid="$USERNAME" VAR_gid="$ADMINS_GID" make_vars)
|
||||
VARS=$(VAR_KEYS="uid,gid" VAR_INT_KEYS="gid" VAR_uid="$USERNAME" VAR_gid="$ADMINS_GID" make_vars)
|
||||
ADD_RESP=$(gql \
|
||||
'mutation AddToGroup($uid: String!, $gid: Int!) { addUserToGroup(userId: $uid, groupId: $gid) { ok } }' \
|
||||
"$VARS")
|
||||
@@ -181,14 +185,54 @@ else
|
||||
fi
|
||||
|
||||
if [[ -n "$USER_PASS" ]]; then
|
||||
VARS=$(VAR_KEYS="uid,pw" VAR_uid="$USERNAME" VAR_pw="$USER_PASS" make_vars)
|
||||
PASS_RESP=$(gql \
|
||||
'mutation SetPass($uid: String!, $pw: String!) { resetUserPasswordFromAdmin(userId: $uid, password: $pw) }' \
|
||||
"$VARS")
|
||||
ERR=$(echo "$PASS_RESP" | python3 -c \
|
||||
"import sys,json; d=json.load(sys.stdin); errs=d.get('errors',[]); print(errs[0]['message'] if errs else '')" \
|
||||
2>/dev/null || echo "")
|
||||
[[ -n "$ERR" ]] && echo " WARNING: password not set — $ERR" || echo " Password set."
|
||||
# LLDAP has no GraphQL mutation for password setting.
|
||||
# Use RFC 3062 LDAP Password Modify extended operation via a kubectl
|
||||
# port-forward to the in-cluster LLDAP LDAP port (ClusterIP only).
|
||||
LLDAP_BIND_DN="uid=admin,ou=people,dc=netkingdom,dc=local"
|
||||
TARGET_DN="uid=$USERNAME,ou=people,dc=netkingdom,dc=local"
|
||||
LOCAL_PORT=13891 # avoid conflict with other forwarders
|
||||
|
||||
echo " Opening kubectl port-forward to lldap:3890 ..."
|
||||
KUBECONFIG="${KUBECONFIG:-$HOME/.kube/config-railiance01}" \
|
||||
kubectl port-forward svc/lldap "$LOCAL_PORT:3890" -n sso &>/dev/null &
|
||||
PF_PID=$!
|
||||
# Wait for the forwarder to be ready (up to 10s)
|
||||
for i in $(seq 1 10); do
|
||||
nc -z 127.0.0.1 "$LOCAL_PORT" 2>/dev/null && break
|
||||
sleep 1
|
||||
done
|
||||
|
||||
PASS_ERR=$(LLDAP_USER_PASS="$LLDAP_ADMIN_PASS" \
|
||||
LLDAP_BIND_DN_VAR="$LLDAP_BIND_DN" \
|
||||
TARGET_DN_VAR="$TARGET_DN" \
|
||||
NEW_PASS="$USER_PASS" \
|
||||
LOCAL_PORT_VAR="$LOCAL_PORT" \
|
||||
python3 -c "
|
||||
import os, sys
|
||||
try:
|
||||
from ldap3 import Server, Connection
|
||||
s = Server('127.0.0.1', port=int(os.environ['LOCAL_PORT_VAR']))
|
||||
c = Connection(s, user=os.environ['LLDAP_BIND_DN_VAR'], password=os.environ['LLDAP_USER_PASS'])
|
||||
c.bind()
|
||||
c.extend.standard.modify_password(
|
||||
user=os.environ['TARGET_DN_VAR'],
|
||||
new_password=os.environ['NEW_PASS'])
|
||||
if c.result['result'] != 0:
|
||||
print(c.result['description'], file=sys.stderr)
|
||||
sys.exit(1)
|
||||
c.unbind()
|
||||
except ImportError:
|
||||
print('ldap3 not installed — install with: pip install ldap3 --break-system-packages', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
" 2>&1)
|
||||
kill "$PF_PID" 2>/dev/null; wait "$PF_PID" 2>/dev/null || true
|
||||
|
||||
if [[ -n "$PASS_ERR" ]]; then
|
||||
echo " WARNING: password not set — $PASS_ERR" >&2
|
||||
echo " Set manually via the LLDAP WebUI at $LLDAP_URL"
|
||||
else
|
||||
echo " Password set."
|
||||
fi
|
||||
else
|
||||
echo " Skipped — set password via $LLDAP_URL as admin."
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user