From 2f4771cd6bb4b40178d3dc21feb8472ce59e8870 Mon Sep 17 00:00:00 2001 From: Valerij Maljulin Date: Sep 21 2020 14:50:20 +0000 Subject: [PATCH 1/3] Add support for multiple LDAP queries JIRA: RHELWF-1187 --- diff --git a/waiverdb/api_v1.py b/waiverdb/api_v1.py index c14465e..d89baa9 100644 --- a/waiverdb/api_v1.py +++ b/waiverdb/api_v1.py @@ -335,7 +335,10 @@ class WaiversResource(Resource): ldap_host = current_app.config.get('LDAP_HOST') ldap_base = current_app.config.get('LDAP_BASE') - return verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_base) + ldap_search_string = current_app.config.get('LDAP_SEARCH_STRING', '(memberUid={user})') + return verify_authorization( + user, testcase, permission_mapping, ldap_host, ldap_base, ldap_search_string + ) def _create_waiver(self, args, user): proxied_by = None diff --git a/waiverdb/authorization.py b/waiverdb/authorization.py index f56d91d..b2fa70e 100644 --- a/waiverdb/authorization.py +++ b/waiverdb/authorization.py @@ -12,7 +12,7 @@ from werkzeug.exceptions import ( log = logging.getLogger(__name__) -def get_group_membership(user, ldap_host, ldap_base): +def get_group_membership(user, ldap_host, ldap_base, search_string): try: import ldap except ImportError: @@ -21,17 +21,17 @@ def get_group_membership(user, ldap_host, ldap_base): try: con = ldap.initialize(ldap_host) - results = con.search_s(ldap_base, ldap.SCOPE_SUBTREE, f'(memberUid={user})', ['cn']) + results = con.search_s(ldap_base, ldap.SCOPE_SUBTREE, search_string.format(user), ['cn']) return [group[1]['cn'][0].decode('utf-8') for group in results] - except ldap.LDAPError: - log.exception('Some error occurred initializing the LDAP connection.') - raise Unauthorized('Some error occurred initializing the LDAP connection.') except ldap.SERVER_DOWN: log.exception('The LDAP server is not reachable.') raise BadGateway('The LDAP server is not reachable.') + except ldap.LDAPError: + log.exception('Some error occurred initializing the LDAP connection.') + raise Unauthorized('Some error occurred initializing the LDAP connection.') -def verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_base): +def verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_base, search_strings): if not (ldap_host and ldap_base): raise InternalServerError(('LDAP_HOST and LDAP_BASE also need to be defined ' 'if PERMISSION_MAPPING is defined.')) @@ -45,7 +45,19 @@ def verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_bas return True allowed_groups += permission['groups'] - group_membership = get_group_membership(user, ldap_host, ldap_base) + ldap_hosts = ldap_host.split('|||') + ldap_bases = ldap_base.split('|||') + ldap_search_strings = search_strings.split('|||') + + group_membership = set() + + for i in range(max((len(ldap_hosts), len(ldap_bases), len(ldap_search_strings)))): + ldap_host_cur = ldap_hosts[i % len(ldap_hosts)] + ldap_base_cur = ldap_bases[i % len(ldap_bases)] + search_string_cur = ldap_search_strings[i % len(ldap_search_strings)] + group_membership.update( + get_group_membership(user, ldap_host_cur, ldap_base_cur, search_string_cur) + ) if not group_membership: raise Unauthorized(f'Couldn\'t find user {user} in LDAP') From bc1fec7c9c167c6b1621ea536ad3542ff4b5501e Mon Sep 17 00:00:00 2001 From: Valerij Maljulin Date: Sep 21 2020 22:57:45 +0000 Subject: [PATCH 2/3] Rename the variable in test_monitor.py according to PEP8 --- diff --git a/tests/test_monitor.py b/tests/test_monitor.py index 7ee8317..bc02948 100644 --- a/tests/test_monitor.py +++ b/tests/test_monitor.py @@ -12,12 +12,12 @@ def test_metrics(client): r = client.get('/api/v1.0/metrics') assert r.status_code == 200 - assert len([l for l in r.get_data(as_text=True).splitlines() - if l.startswith('# TYPE messaging_') - and l.endswith(' counter')]) == 4 - assert len([l for l in r.get_data(as_text=True).splitlines() - if l.startswith('# TYPE db_') - and l.endswith(' counter')]) == 4 + assert len([line for line in r.get_data(as_text=True).splitlines() + if line.startswith('# TYPE messaging_') + and line.endswith(' counter')]) == 4 + assert len([line for line in r.get_data(as_text=True).splitlines() + if line.startswith('# TYPE db_') + and line.endswith(' counter')]) == 4 def test_standalone_metrics_server_disabled_by_default(): @@ -31,9 +31,9 @@ def test_standalone_metrics_server(): r = requests.get('http://127.0.0.1:10040/metrics') - assert len([l for l in r.text.splitlines() - if l.startswith('# TYPE messaging_') - and l.endswith(' counter')]) == 4 - assert len([l for l in r.text.splitlines() - if l.startswith('# TYPE db_') - and l.endswith(' counter')]) == 4 + assert len([line for line in r.text.splitlines() + if line.startswith('# TYPE messaging_') + and line.endswith(' counter')]) == 4 + assert len([line for line in r.text.splitlines() + if line.startswith('# TYPE db_') + and line.endswith(' counter')]) == 4 diff --git a/waiverdb/authorization.py b/waiverdb/authorization.py index b2fa70e..b7f5679 100644 --- a/waiverdb/authorization.py +++ b/waiverdb/authorization.py @@ -61,7 +61,7 @@ def verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_bas if not group_membership: raise Unauthorized(f'Couldn\'t find user {user} in LDAP') - if set(group_membership) & set(allowed_groups): + if group_membership & set(allowed_groups): return True raise Unauthorized(('You are not authorized to submit a waiver ' From 1186bdafee9b6bf45bc1a6091fde6d063c40694d Mon Sep 17 00:00:00 2001 From: Valerij Maljulin Date: Sep 23 2020 11:04:53 +0000 Subject: [PATCH 3/3] fixup! Rename the variable in test_monitor.py according to PEP8 --- diff --git a/waiverdb/api_v1.py b/waiverdb/api_v1.py index d89baa9..287aaf4 100644 --- a/waiverdb/api_v1.py +++ b/waiverdb/api_v1.py @@ -334,11 +334,12 @@ class WaiversResource(Resource): return True ldap_host = current_app.config.get('LDAP_HOST') - ldap_base = current_app.config.get('LDAP_BASE') - ldap_search_string = current_app.config.get('LDAP_SEARCH_STRING', '(memberUid={user})') - return verify_authorization( - user, testcase, permission_mapping, ldap_host, ldap_base, ldap_search_string - ) + ldap_searches = current_app.config.get('LDAP_SEARCHES') + if not ldap_searches: + ldap_base = current_app.config.get('LDAP_BASE') + ldap_search_string = current_app.config.get('LDAP_SEARCH_STRING', '(memberUid={user})') + ldap_searches = [{'BASE': ldap_base, 'SEARCH_STRING': ldap_search_string}] + return verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_searches) def _create_waiver(self, args, user): proxied_by = None diff --git a/waiverdb/authorization.py b/waiverdb/authorization.py index b7f5679..e038fe0 100644 --- a/waiverdb/authorization.py +++ b/waiverdb/authorization.py @@ -12,17 +12,16 @@ from werkzeug.exceptions import ( log = logging.getLogger(__name__) -def get_group_membership(user, ldap_host, ldap_base, search_string): +def get_group_membership(ldap, user, con, ldap_search): try: - import ldap - except ImportError: - raise InternalServerError(('If PERMISSION_MAPPING is defined, ' - 'python-ldap needs to be installed.')) - - try: - con = ldap.initialize(ldap_host) - results = con.search_s(ldap_base, ldap.SCOPE_SUBTREE, search_string.format(user), ['cn']) + results = con.search_s( + ldap_search['BASE'], ldap.SCOPE_SUBTREE, + ldap_search.get('SEARCH_STRING', '(memberUid={user})').format(user), ['cn'] + ) return [group[1]['cn'][0].decode('utf-8') for group in results] + except KeyError: + log.exception('LDAP_SEARCHES parameter should contain the BASE key') + raise InternalServerError('LDAP_SEARCHES parameter should contain the BASE key') except ldap.SERVER_DOWN: log.exception('The LDAP server is not reachable.') raise BadGateway('The LDAP server is not reachable.') @@ -31,9 +30,9 @@ def get_group_membership(user, ldap_host, ldap_base, search_string): raise Unauthorized('Some error occurred initializing the LDAP connection.') -def verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_base, search_strings): - if not (ldap_host and ldap_base): - raise InternalServerError(('LDAP_HOST and LDAP_BASE also need to be defined ' +def verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_searches): + if not (ldap_host and ldap_searches): + raise InternalServerError(('LDAP_HOST and LDAP_SEARCHES also need to be defined ' 'if PERMISSION_MAPPING is defined.')) allowed_groups = [] @@ -45,24 +44,24 @@ def verify_authorization(user, testcase, permission_mapping, ldap_host, ldap_bas return True allowed_groups += permission['groups'] - ldap_hosts = ldap_host.split('|||') - ldap_bases = ldap_base.split('|||') - ldap_search_strings = search_strings.split('|||') + try: + import ldap + except ImportError: + raise InternalServerError(('If PERMISSION_MAPPING is defined, ' + 'python-ldap needs to be installed.')) + con = ldap.initialize(ldap_host) group_membership = set() - for i in range(max((len(ldap_hosts), len(ldap_bases), len(ldap_search_strings)))): - ldap_host_cur = ldap_hosts[i % len(ldap_hosts)] - ldap_base_cur = ldap_bases[i % len(ldap_bases)] - search_string_cur = ldap_search_strings[i % len(ldap_search_strings)] + for cur_ldap_search in ldap_searches: group_membership.update( - get_group_membership(user, ldap_host_cur, ldap_base_cur, search_string_cur) + get_group_membership(ldap, user, con, cur_ldap_search) ) + if group_membership & set(allowed_groups): + return True + if not group_membership: raise Unauthorized(f'Couldn\'t find user {user} in LDAP') - if group_membership & set(allowed_groups): - return True - raise Unauthorized(('You are not authorized to submit a waiver ' f'for the test case {testcase}'))