67 lines
1.7 KiB
Python
67 lines
1.7 KiB
Python
import re
|
|
import ldap
|
|
from webapp import config
|
|
|
|
def is_valid_name(name):
|
|
"""`true` if `name` is a safe ldap uid/cn"""
|
|
return re.match(r'^[a-zA-Z_][a-zA-Z0-9-_\.]*\Z', name) is not None
|
|
|
|
def validate_name(name):
|
|
"""Raises `RuntimeError` if `name` is not a safe ldap uid/cn"""
|
|
if not is_valid_name(name):
|
|
raise RuntimeError('Invalid name')
|
|
|
|
def user_dn(uid):
|
|
validate_name(uid)
|
|
return config.ldap_user_dn_format.format(uid)
|
|
|
|
def group_dn(cn):
|
|
validate_name(cn)
|
|
return config.ldap_group_dn_format.format(cn)
|
|
|
|
def wrap(filter):
|
|
if len(filter) and filter[0] == '(' and filter[-1] == ')':
|
|
return filter
|
|
else:
|
|
return f'({filter})'
|
|
|
|
def _or(*filters):
|
|
wrapped = ''.join(wrap(f) for f in filters)
|
|
return f'(|{wrapped})'
|
|
|
|
def _and(*filters):
|
|
wrapped = ''.join(wrap(f) for f in filters)
|
|
return f'(&{wrapped})'
|
|
|
|
def _not(filter):
|
|
wrapped = wrap(filter)
|
|
return f'(!{wrapped})'
|
|
|
|
def member_of_any(groups):
|
|
"""Returns a filter that matches users that are a member of any of the given group names"""
|
|
return _or(*(f'memberOf={group_dn(group)}' for group in groups))
|
|
|
|
def groups_of_user(uid):
|
|
"""Returns a filter that matches groups that have the given user as a member"""
|
|
return f'(&(objectClass=groupOfUniqueNames)(uniqueMember={user_dn(uid)}))'
|
|
|
|
def normalized_entries(entries):
|
|
"""
|
|
Converts ldap entries from python-ldap format into a more convenient
|
|
List[Tuple[
|
|
dn,
|
|
List[tuple[attr_name, attr_value]]
|
|
]]
|
|
"""
|
|
normalized = []
|
|
for dn, attrs in entries:
|
|
normalized_attrs = []
|
|
for attr, values in attrs.items():
|
|
for value in values:
|
|
normalized_attrs.append((attr, value.decode()))
|
|
normalized.append((dn, normalized_attrs))
|
|
|
|
return normalized
|
|
|
|
|