Added draft for nested groups

This commit is contained in:
Kevin Veen-Birkenbach 2025-07-04 23:43:38 +02:00
parent dc6454e910
commit 8cd7379419
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
5 changed files with 114 additions and 4 deletions

View File

@ -1,4 +1,3 @@
# Todos
- Implement auto memberof setup
- Create a Dockerfile (may in an own repository) with memberOf
- Find a better decoupling solution for nextcloud
- User Groups and Roles on the proper way
- Refactor the use of groups as roles in oauth2 proxy

View File

@ -35,7 +35,11 @@ docker exec -it ldap ldapsearch -Y EXTERNAL -H ldapi:/// -b "cn=config" "(olcDat
To execute the following commands set the credentials via:
```bash
export $(grep -Ev '^(#|$)' .env/env | xargs)
eval $(
grep -v '^\s*#' .env/env \
| sed -E 's/\s*#.*//' \
| sed -E 's/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/export \1="\2"/'
)
```
### Show all Entries

View File

@ -0,0 +1,77 @@
def build_ldap_nested_group_entries(applications, users, ldap):
"""
Builds structured LDAP role entries using the global `ldap` configuration.
Supports objectClasses: posixGroup (adds gidNumber, memberUid), groupOfNames (adds member).
Now nests roles under an application-level OU: application-id/role.
"""
result = {}
# Base DN components
role_dn_base = ldap["dn"]["ou"]["roles"]
user_dn_base = ldap["dn"]["ou"]["users"]
ldap_user_attr = ldap["user"]["attributes"]["id"]
# Supported objectClass flavors
flavors = ldap.get("rbac", {}).get("flavors", [])
for application_id, app_config in applications.items():
# Compute the DN for the application-level OU
app_ou_dn = f"ou={application_id},{role_dn_base}"
ou_entry = {
"dn": app_ou_dn,
"objectClass": ["top", "organizationalUnit"],
"ou": application_id,
"description": f"Roles for application {application_id}"
}
result[app_ou_dn] = ou_entry
# Standard roles with an extra 'administrator'
base_roles = app_config.get("rbac", {}).get("roles", {})
roles = {
**base_roles,
"administrator": {
"description": "Has full administrative access: manage themes, plugins, settings, and users"
}
}
group_id = app_config.get("group_id")
for role_name, role_conf in roles.items():
# Build CN under the application OU
cn = role_name
dn = f"cn={cn},{app_ou_dn}"
entry = {
"dn": dn,
"cn": cn,
"description": role_conf.get("description", ""),
"objectClass": ["top"] + flavors,
}
member_dns = []
member_uids = []
for username, user_conf in users.items():
if role_name in user_conf.get("roles", []):
member_dns.append(f"{ldap_user_attr}={username},{user_dn_base}")
member_uids.append(username)
if "posixGroup" in flavors:
entry["gidNumber"] = group_id
if member_uids:
entry["memberUid"] = member_uids
if "groupOfNames" in flavors and member_dns:
entry["member"] = member_dns
result[dn] = entry
return result
class FilterModule(object):
def filters(self):
return {
"build_ldap_nested_group_entries": build_ldap_nested_group_entries
}

View File

@ -0,0 +1,30 @@
{#
@todo: activate
{% for dn, entry in (applications | build_ldap_role_entries(users, ldap)).items() %}
dn: {{ dn }}
{% for oc in entry.objectClass %}
objectClass: {{ oc }}
{% endfor %}
{% if entry.ou is defined %}
ou: {{ entry.ou }}
{% else %}
cn: {{ entry.cn }}
{% endif %}
{% if entry.gidNumber is defined %}
gidNumber: {{ entry.gidNumber }}
{% endif %}
description: {{ entry.description }}
{% if entry.memberUid is defined %}
{% for uid in entry.memberUid %}
memberUid: {{ uid }}
{% endfor %}
{% endif %}
{% if entry.member is defined %}
{% for m in entry.member %}
member: {{ m }}
{% endfor %}
{% endif %}
{% endfor %}
#}