Skip to content
Snippets Groups Projects
Commit c912b51e authored by Julian Rother's avatar Julian Rother
Browse files

Regex filter option for groups (--group-filter-regex)

parent 5872cfae
No related branches found
No related tags found
No related merge requests found
Pipeline #13832 passed
......@@ -9,3 +9,4 @@
#SERVER_BIND_PASSWORD="SECRET-BIND-PASSWORD"
#SERVER_CACHE_TTL="60"
#SERVER_GROUP_FILTER_REGEX=""
......@@ -4,6 +4,7 @@ import sys
import socketserver
import logging
import socket
import re
import click
import requests
......@@ -89,6 +90,7 @@ class UffdLDAPRequestHandler(ldapserver.LDAPRequestHandler):
api = None
dn_base = None
bind_password = None # if None anonymous reads are allowed
group_filter_regex = None
def do_bind_simple_authenticated(self, dn, password):
dn = self.subschema.DN.from_str(dn)
......@@ -186,6 +188,8 @@ class UffdLDAPRequestHandler(ldapserver.LDAPRequestHandler):
if value.is_direct_child_of(self.subschema.DN(self.dn_base, ou='groups')) and value.object_attribute == 'cn':
request_params = {'group': normalize_group_name(value.object_value)}
break
if 'group' in request_params and not self.group_filter_regex.match(request_params['group']):
return
for user in self.api.get_users(**request_params):
yield template.create_entry(user['loginname'],
cn=[user['displayname']],
......@@ -195,7 +199,9 @@ class UffdLDAPRequestHandler(ldapserver.LDAPRequestHandler):
mail=[user['email']],
uid=[user['loginname']],
uidNumber=[user['id']],
memberOf=[self.subschema.DN(self.subschema.DN(self.dn_base, ou='groups'), cn=group) for group in user['groups']],
memberOf=[self.subschema.DN(self.subschema.DN(self.dn_base, ou='groups'), cn=group)
for group in user['groups']
if self.group_filter_regex.match(group)],
)
def do_search_groups(self, baseobj, scope, filterobj):
......@@ -220,20 +226,25 @@ class UffdLDAPRequestHandler(ldapserver.LDAPRequestHandler):
if value.is_direct_child_of(self.subschema.DN(self.dn_base, ou='users')) and value.object_attribute == 'uid':
request_params = {'member': normalize_user_loginname(value.object_value)}
break
if 'name' in request_params and not self.group_filter_regex.match(request_params['name']):
return
for group in self.api.get_groups(**request_params):
if not self.group_filter_regex.match(group['name']):
continue
yield template.create_entry(group['name'],
cn=[group['name']],
gidNumber=[group['id']],
uniqueMember=[self.subschema.DN(self.subschema.DN(self.dn_base, ou='users'), uid=user) for user in group['members']],
)
def make_requesthandler(api, dn_base, bind_password=None):
def make_requesthandler(api, dn_base, bind_password=None, group_filter_regex=None):
class RequestHandler(UffdLDAPRequestHandler):
pass
dn_base = RequestHandler.subschema.DN.from_str(dn_base)
RequestHandler.api = api
RequestHandler.dn_base = dn_base
RequestHandler.bind_password = bind_password.encode() if bind_password else None
RequestHandler.group_filter_regex = re.compile(group_filter_regex) if group_filter_regex else re.compile('')
return RequestHandler
class FilenoUnixStreamServer(socketserver.UnixStreamServer):
......@@ -284,7 +295,8 @@ class StdoutFilter(logging.Filter):
@click.option('--cache-ttl', default=60, help='Time-to-live for API response caching in seconds')
@click.option('--base-dn', required=True, help='Base DN for user, group and system objects. E.g. "dc=example,dc=com"')
@click.option('--bind-password', help='Authentication password for the service connection to LDAP. Bind DN is always "cn=service,ou=system,BASEDN". If set, anonymous access is disabled.')
def main(socket_address, socket_path, socket_fd, api_url, api_user, api_secret, cache_ttl, base_dn, bind_password):
@click.option('--group-filter-regex', help='Python regular expression that group names must match for the group to be visible to LDAP clients')
def main(socket_address, socket_path, socket_fd, api_url, api_user, api_secret, cache_ttl, base_dn, bind_password, group_filter_regex):
# pylint: disable=too-many-locals
if (socket_address is not None) \
+ (socket_path is not None) \
......@@ -302,7 +314,7 @@ def main(socket_address, socket_path, socket_fd, api_url, api_user, api_secret,
root_logger.addHandler(stderr_handler)
api = UffdAPI(api_url, api_user, api_secret, cache_ttl)
RequestHandler = make_requesthandler(api, base_dn, bind_password)
RequestHandler = make_requesthandler(api, base_dn, bind_password, group_filter_regex)
if socket_address is not None:
host, port = parse_network_address(socket_address)
server = socketserver.ThreadingTCPServer((host, int(port)), RequestHandler)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment