keycloak: cleanup LDAP federation
This commit is contained in:
parent
b509234aee
commit
503a9264c5
@ -2,7 +2,7 @@
|
|||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
metadata:
|
metadata:
|
||||||
name: keycloak-ldap-federation-3
|
name: keycloak-ldap-federation-4
|
||||||
namespace: sso
|
namespace: sso
|
||||||
spec:
|
spec:
|
||||||
backoffLimit: 2
|
backoffLimit: 2
|
||||||
@ -60,6 +60,7 @@ spec:
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
base_url = os.environ["KEYCLOAK_SERVER"].rstrip("/")
|
base_url = os.environ["KEYCLOAK_SERVER"].rstrip("/")
|
||||||
@ -176,11 +177,21 @@ spec:
|
|||||||
raise SystemExit(f"Unexpected components response: {status}")
|
raise SystemExit(f"Unexpected components response: {status}")
|
||||||
components = components or []
|
components = components or []
|
||||||
|
|
||||||
ldap_component = None
|
ldap_components = [c for c in components if c.get("providerId") == "ldap" and c.get("id")]
|
||||||
for c in components:
|
|
||||||
if c.get("providerId") == "ldap" and c.get("name") in ("openldap", "ldap"):
|
# Select a canonical LDAP federation provider deterministically.
|
||||||
ldap_component = c
|
# Duplicate LDAP providers can cause Keycloak admin/user queries to fail if any one of them is misconfigured.
|
||||||
break
|
candidates = []
|
||||||
|
for c in ldap_components:
|
||||||
|
if c.get("name") not in ("openldap", "ldap"):
|
||||||
|
continue
|
||||||
|
cfg = c.get("config") or {}
|
||||||
|
if (cfg.get("connectionUrl") or [None])[0] == ldap_url:
|
||||||
|
candidates.append(c)
|
||||||
|
if not candidates:
|
||||||
|
candidates = [c for c in ldap_components if c.get("name") in ("openldap", "ldap")]
|
||||||
|
candidates.sort(key=lambda x: x.get("id", ""))
|
||||||
|
ldap_component = candidates[0] if candidates else None
|
||||||
ldap_component_id = ldap_component["id"] if ldap_component else None
|
ldap_component_id = ldap_component["id"] if ldap_component else None
|
||||||
|
|
||||||
desired = {
|
desired = {
|
||||||
@ -296,4 +307,56 @@ spec:
|
|||||||
)
|
)
|
||||||
if status not in (201, 204):
|
if status not in (201, 204):
|
||||||
raise SystemExit(f"Unexpected group mapper create status: {status}")
|
raise SystemExit(f"Unexpected group mapper create status: {status}")
|
||||||
|
|
||||||
|
# Cleanup duplicate LDAP federation providers and their child components (mappers, etc).
|
||||||
|
# Keep only the canonical provider we updated/created above.
|
||||||
|
try:
|
||||||
|
status, fresh_components, _ = http_json(
|
||||||
|
"GET",
|
||||||
|
f"{base_url}/admin/realms/{realm}/components",
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
if status != 200:
|
||||||
|
raise Exception(f"unexpected components status {status}")
|
||||||
|
fresh_components = fresh_components or []
|
||||||
|
|
||||||
|
dup_provider_ids = []
|
||||||
|
for c in fresh_components:
|
||||||
|
if c.get("providerId") != "ldap":
|
||||||
|
continue
|
||||||
|
if c.get("providerType") != "org.keycloak.storage.UserStorageProvider":
|
||||||
|
continue
|
||||||
|
cid = c.get("id")
|
||||||
|
if not cid or cid == ldap_component_id:
|
||||||
|
continue
|
||||||
|
dup_provider_ids.append(cid)
|
||||||
|
|
||||||
|
if dup_provider_ids:
|
||||||
|
for pid in dup_provider_ids:
|
||||||
|
# Delete child components first.
|
||||||
|
for child in fresh_components:
|
||||||
|
if child.get("parentId") != pid:
|
||||||
|
continue
|
||||||
|
child_id = child.get("id")
|
||||||
|
if not child_id:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
http_json(
|
||||||
|
"DELETE",
|
||||||
|
f"{base_url}/admin/realms/{realm}/components/{child_id}",
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(f"WARNING: failed to delete LDAP child component {child_id} (status={e.code})")
|
||||||
|
try:
|
||||||
|
http_json(
|
||||||
|
"DELETE",
|
||||||
|
f"{base_url}/admin/realms/{realm}/components/{pid}",
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(f"WARNING: failed to delete duplicate LDAP provider {pid} (status={e.code})")
|
||||||
|
print(f"Cleaned up {len(dup_provider_ids)} duplicate LDAP federation providers")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"WARNING: LDAP cleanup failed (continuing): {e}")
|
||||||
PY
|
PY
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user