Problem
Opening a Shared Account in the IAM Administration Portal (UMC) becomes slow when its permissions selectors resolve thousands of OX users. The form appears frozen even when the administrator only wants to review permissions.
Administrators must wait before reviewing or changing access, cannot reliably distinguish a busy form from a failed request, and risk repeating actions while the selector is still loading. This affects routine Shared Account administration, not just bulk provisioning.
| Evidence | Before optimization | After optimization | Measurement scope |
|---|---|---|---|
| Local reproduction, 13,000 OX-enabled users | ~20-30 s | ~1-2 s | Opening the Shared Account form |
Root Cause
Related upstream reference: Univention Bug 60036.
The original /usr/lib/python3/dist-packages/univention/admin/syntax.d/50_ox.py defines OxUser and OxGroup as UDM_Objects subclasses without overriding use_objects.
UDM_Objectsdefaults touse_objects = True.OxUser._is_simple()returns(False, set()).- The fallback
users.user.lookupconstructs full user objects, maps attributes, and applies authorization processing throughfilter_lookup_results. - With a limit of 12,000,
ldapSizelimitExceededis caught after expensive work. A customer response still returned HTTP 200 withsize_limit_exceeded: trueandperforms_well: true, after approximately 25 seconds. These flags and HTTP success do not demonstrate a fast lookup.
Setting use_objects = False enables lightweight selection of username and univentionObjectIdentifier for users, and name and identifier for groups. The existing filters remain (isOxUser=OK) and (isOxGroup=OK).
Workaround
The two-line change below is a proposed, locally tested workaround: an unreleased candidate provided in this case, not a vendor-supported production update or an officially released fix. Check Bug 60036 for current status and finally fix.
1. Establish the operator shell and preserve evidence
Run the examples in Bash unless explicitly marked otherwise. Requirements: kubectl, jq, Python 3, patch, Docker, and approved cluster access.
export NAMESPACE=<YOUR_NAMESPACE>
export DOMAIN=${NAMESPACE?}.univention.dev
export WORK=/home/USERNAME/Downloads/ox-syntax-test
export PLUGIN=/usr/lib/python3/dist-packages/univention/admin/syntax.d/50_ox.py
mkdir -p "$WORK"
cd "$WORK"
kubectl config current-context
kubectl -n "$NAMESPACE" get sts ums-umc-server
Confirm the context and namespace before any write. Backups may contain internal configuration; keep them private.
kubectl -n "$NAMESPACE" get sts ums-umc-server -o yaml \
> "ums-umc-server-before-$(date +%Y%m%d-%H%M%S).yaml"
kubectl -n "$NAMESPACE" exec ums-umc-server-0 -c main -- cat "$PLUGIN" \
> 50_ox.py
2. Prepare and validate the two-line change locally
Do not run patch against the read-only pod path. Preserve the existing local artifacts by using a new staging directory.
The patch: Possible Patch from Bug 60036
Save the patch with the name ox-user-group-use-objects.patch
--- a/50_ox.py
+++ b/50_ox.py
@@ -425,6 +425,7 @@
class OxUser(UDM_Objects):
+ use_objects = False
udm_modules = ('users/user',)
key = '%(univentionObjectIdentifier)s'
label = '%(username)s'
@@ -432,6 +433,7 @@
class OxGroup(UDM_Objects):
+ use_objects = False
udm_modules = ('groups/group',)
key = '%(univentionObjectIdentifier)s'
label = '%(name)s'
STAGE=$(mktemp -d "$WORK/patch-stage.XXXXXX")
cp 50_ox.py "$STAGE/50_ox.py"
patch --dry-run -d "$STAGE" -p1 < ox-user-group-use-objects.patch
patch -d "$STAGE" -p1 < ox-user-group-use-objects.patch
diff -u 50_ox.py "$STAGE/50_ox.py" || test "$?" -eq 1
python3 - <<'PY'
import ast
from pathlib import Path
ast.parse(Path("50_ox.py").read_text())
print("Python-Syntax OK")
PY
3. Overlay the single plugin file with a ConfigMap
First inspect existing mounts as described under Investigation. Stop if ox-syntax-test already exists or this exact file path already has an overlay; reconcile ownership rather than overwriting another experiment.
kubectl -n "$NAMESPACE" get configmap ox-syntax-test
Expected output:
Error from server (NotFound): configmaps "ox-syntax-test" not found
Use the following command to create a new configmap with including the patched 50_ox.py.
kubectl -n "$NAMESPACE" create configmap ox-syntax-test \
--from-file=50_ox.py="$STAGE/50_ox.py"
cat > "$WORK/ox-overlay.yaml" <<'YAML'
spec:
template:
spec:
volumes:
- name: ox-syntax-test
configMap:
name: ox-syntax-test
containers:
- name: main
volumeMounts:
- name: ox-syntax-test
mountPath: /usr/lib/python3/dist-packages/univention/admin/syntax.d/50_ox.py
subPath: 50_ox.py
readOnly: true
YAML
Re-check the created configmap:
kubectl -n "$NAMESPACE" get configmap ox-syntax-test
NAME DATA AGE
ox-syntax-test 1 8s
Install the patch to the ums-umc-server
kubectl -n "$NAMESPACE" patch sts ums-umc-server --type=strategic \
--patch-file "$WORK/ox-overlay.yaml"
Rollout the pod with the patch.
kubectl -n "$NAMESPACE" rollout status sts/ums-umc-server --timeout=300s
The template change normally triggers a rollout under a RollingUpdate strategy. If the StatefulSet uses OnDelete or a partition, stop and arrange an explicitly approved replacement procedure. Expect downtime with a single replica. A ConfigMap subPath mount does not update live; changing the ConfigMap later requires a pod replacement.
kubectl -n "$NAMESPACE" exec ums-umc-server-0 -c main -- cat "$PLUGIN" \
> "$WORK/50_ox.pod-after.py"
diff -u "$STAGE/50_ox.py" "$WORK/50_ox.pod-after.py"
Helm upgrades or reconciliation may overwrite temporary StatefulSet and ConfigMap changes. A durable fix belongs in the managed extension/release configuration.
Additional
Targeted rollback
Remove only this overlay. Do not use a broad rollout undo, replace the whole StatefulSet from an old backup, or delete the namespace/users.
cat > "$WORK/ox-overlay-remove.yaml" <<'YAML'
spec:
template:
spec:
containers:
- name: main
volumeMounts:
- mountPath: /usr/lib/python3/dist-packages/univention/admin/syntax.d/50_ox.py
$patch: delete
volumes:
- name: ox-syntax-test
$patch: delete
YAML
kubectl -n "$NAMESPACE" patch sts ums-umc-server --type=strategic \
--patch-file "$WORK/ox-overlay-remove.yaml"
kubectl -n "$NAMESPACE" rollout status sts/ums-umc-server --timeout=300s
kubectl -n "$NAMESPACE" exec ums-umc-server-0 -c main -- cat "$PLUGIN" \
> "$WORK/50_ox.pod-rollback.py"
diff -u "$WORK/50_ox.pod-original.py" "$WORK/50_ox.pod-rollback.py"
# Optional, only after confirming the overlay is no longer referenced:
kubectl -n "$NAMESPACE" delete configmap ox-syntax-test