Skip to content

Commit 3d78c61

Browse files
project-usermap requested changes
1 parent 3fd7723 commit 3d78c61

File tree

2 files changed

+58
-107
lines changed

2 files changed

+58
-107
lines changed

comanage_scripts_utils.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import json
77
import urllib.error
88
import urllib.request
9-
from ldap3 import Server, Connection, ALL, ALL_ATTRIBUTES, SAFE_SYNC
9+
from ldap3 import Server, Connection, ALL, SAFE_SYNC
1010

1111

1212
MIN_TIMEOUT = 5
@@ -42,6 +42,14 @@ def mkauthstr(user, passwd):
4242
return encodebytes(raw_authstr.encode()).decode().replace("\n", "")
4343

4444

45+
def get_ldap_authtok(ldap_authfile):
46+
if ldap_authfile is not None:
47+
ldap_authtok = open(ldap_authfile).readline().rstrip("\n")
48+
else:
49+
raise PermissionError
50+
return ldap_authtok
51+
52+
4553
def mkrequest(method, target, data, endpoint, authstr, **kw):
4654
url = os.path.join(endpoint, target)
4755
if kw:
@@ -135,12 +143,35 @@ def get_ldap_groups(ldap_server, ldap_user, ldap_authtok):
135143
ldap_group_osggids = set()
136144
server = Server(ldap_server, get_info=ALL)
137145
connection = Connection(server, ldap_user, ldap_authtok, client_strategy=SAFE_SYNC, auto_bind=True)
138-
_, _, response, _ = connection.search("ou=groups,o=OSG,o=CO,dc=cilogon,dc=org", "(cn=*)", attributes=ALL_ATTRIBUTES)
146+
_, _, response, _ = connection.search("ou=groups,o=OSG,o=CO,dc=cilogon,dc=org", "(cn=*)", attributes=["gidNumber"])
139147
for group in response:
140148
ldap_group_osggids.add(group["attributes"]["gidNumber"])
141149
return ldap_group_osggids
142150

143151

152+
def get_ldap_group_members(ldap_gid, ldap_server, ldap_user, ldap_authtok):
153+
ldap_group_members = set()
154+
server = Server(ldap_server, get_info=ALL)
155+
connection = Connection(server, ldap_user, ldap_authtok, client_strategy=SAFE_SYNC, auto_bind=True)
156+
_, _, response, _ = connection.search("ou=groups,o=OSG,o=CO,dc=cilogon,dc=org", f"(&(gidNumber={ldap_gid})(cn=*))", attributes=["hasMember"])
157+
for group in response:
158+
ldap_group_members.update(group["attributes"]["hasMember"])
159+
return ldap_group_members
160+
161+
162+
def get_ldap_active_users(ldap_server, ldap_user, ldap_authtok, filter_group_name=None):
163+
ldap_active_users = set()
164+
filter_str = ("(isMemberOf=CO:members:active)" if filter_group_name is None
165+
else f"(&(isMemberOf={filter_group_name})(isMemberOf=CO:members:active))")
166+
server = Server(ldap_server, get_info=ALL)
167+
connection = Connection(server, ldap_user, ldap_authtok, client_strategy=SAFE_SYNC, auto_bind=True)
168+
_, _, response, _ = connection.search("ou=people,o=OSG,o=CO,dc=cilogon,dc=org", filter_str, attributes=["employeeNumber"])
169+
for person in response:
170+
# the "employeeNumber" is the person's name in the first.last format
171+
ldap_active_users.add(person["attributes"]["employeeNumber"])
172+
return ldap_active_users
173+
174+
144175
def identifier_from_list(id_list, id_type):
145176
id_type_list = [id["Type"] for id in id_list]
146177
try:

osg-comanage-project-usermap.py

Lines changed: 25 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,32 @@
11
#!/usr/bin/env python3
22

3-
import re
43
import os
54
import sys
6-
import json
75
import time
86
import getopt
9-
import subprocess
107
import urllib.error
118
import urllib.request
129
import comanage_scripts_utils as utils
1310

1411

1512
SCRIPT = os.path.basename(__file__)
1613
ENDPOINT = "https://registry-test.cilogon.org/registry/"
14+
LDAP_SERVER = "ldaps://ldap-test.cilogon.org"
15+
LDAP_USER = "uid=registry_user,ou=system,o=OSG,o=CO,dc=cilogon,dc=org"
1716
OSG_CO_ID = 8
18-
MINTIMEOUT = 5
19-
MAXTIMEOUT = 625
20-
TIMEOUTMULTIPLE = 5
2117
CACHE_FILENAME = "COmanage_Projects_cache.txt"
2218
CACHE_LIFETIME_HOURS = 0.5
2319

24-
LDAP_AUTH_COMMAND = [
25-
"awk", "/ldap_default_authtok/ {print $3}", "/etc/sssd/conf.d/0060_domain_CILOGON.ORG.conf",
26-
]
27-
28-
LDAP_GROUP_MEMBERS_COMMAND = [
29-
"ldapsearch",
30-
"-H",
31-
"ldaps://ldap.cilogon.org",
32-
"-D",
33-
"uid=readonly_user,ou=system,o=OSG,o=CO,dc=cilogon,dc=org",
34-
"-w", "{auth}",
35-
"-b",
36-
"ou=groups,o=OSG,o=CO,dc=cilogon,dc=org",
37-
"-s",
38-
"one",
39-
"(cn=*)",
40-
]
41-
42-
LDAP_ACTIVE_USERS_COMMAND = [
43-
"ldapsearch",
44-
"-LLL",
45-
"-H", "ldaps://ldap.cilogon.org",
46-
"-D", "uid=readonly_user,ou=system,o=OSG,o=CO,dc=cilogon,dc=org",
47-
"-x",
48-
"-w", "{auth}",
49-
"-b", "ou=people,o=OSG,o=CO,dc=cilogon,dc=org",
50-
"{filter}", "voPersonApplicationUID",
51-
"|", "grep", "voPersonApplicationUID",
52-
"|", "sort",
53-
]
5420

5521
_usage = f"""\
5622
usage: [PASS=...] {SCRIPT} [OPTIONS]
5723
5824
OPTIONS:
5925
-u USER[:PASS] specify USER and optionally PASS on command line
6026
-c OSG_CO_ID specify OSG CO ID (default = {OSG_CO_ID})
27+
-s LDAP_SERVER specify LDAP server to read data from
28+
-l LDAP_USER specify LDAP user for reading data from LDAP server
29+
-a ldap_authfile specify path to file to open and read LDAP authtok
6130
-d passfd specify open fd to read PASS
6231
-f passfile specify path to file to open and read PASS
6332
-e ENDPOINT specify REST endpoint
@@ -87,6 +56,9 @@ class Options:
8756
osg_co_id = OSG_CO_ID
8857
outfile = None
8958
authstr = None
59+
ldap_server = LDAP_SERVER
60+
ldap_user = LDAP_USER
61+
ldap_authtok = None
9062
filtergrp = None
9163

9264

@@ -110,14 +82,8 @@ def co_group_is_project(gid):
11082

11183

11284
def get_co_group_osggid(gid):
113-
resp_data = get_co_group_identifiers(gid)
114-
data = get_datalist(resp_data, "Identifiers")
115-
return list(filter(lambda x : x["Type"] == "osggid", data))[0]["Identifier"]
116-
117-
118-
def get_co_group_osggid(gid):
119-
resp_data = get_co_group_identifiers(gid)
120-
data = get_datalist(resp_data, "Identifiers")
85+
resp_data = utils.get_co_group_identifiers(gid, options.endpoint, options.authstr)
86+
data = utils.get_datalist(resp_data, "Identifiers")
12187
return list(filter(lambda x : x["Type"] == "osggid", data))[0]["Identifier"]
12288

12389

@@ -138,7 +104,7 @@ def get_co_person_osguser(pid):
138104

139105
def parse_options(args):
140106
try:
141-
ops, args = getopt.getopt(args, 'u:c:d:f:g:e:o:h')
107+
ops, args = getopt.getopt(args, 'u:c:s:l:a:d:f:g:e:o:h')
142108
except getopt.GetoptError:
143109
usage()
144110

@@ -147,11 +113,15 @@ def parse_options(args):
147113

148114
passfd = None
149115
passfile = None
116+
ldap_authfile = None
150117

151118
for op, arg in ops:
152119
if op == '-h': usage()
153120
if op == '-u': options.user = arg
154121
if op == '-c': options.osg_co_id = int(arg)
122+
if op == '-s': options.ldap_server= arg
123+
if op == '-l': options.ldap_user = arg
124+
if op == '-a': ldap_authfile = arg
155125
if op == '-d': passfd = int(arg)
156126
if op == '-f': passfile = arg
157127
if op == '-e': options.endpoint = arg
@@ -161,69 +131,20 @@ def parse_options(args):
161131
try:
162132
user, passwd = utils.getpw(options.user, passfd, passfile)
163133
options.authstr = utils.mkauthstr(user, passwd)
134+
options.ldap_authtok = utils.get_ldap_authtok(ldap_authfile)
164135
except PermissionError:
165136
usage("PASS required")
166137

167138

168-
def get_ldap_group_members_data():
169-
gidNumber_str = "gidNumber: "
170-
gidNumber_regex = re.compile(gidNumber_str)
171-
member_str = "hasMember: "
172-
member_regex = re.compile(member_str)
173-
174-
auth_str = subprocess.run(
175-
LDAP_AUTH_COMMAND,
176-
stdout=subprocess.PIPE
177-
).stdout.decode('utf-8').strip()
178-
179-
ldap_group_members_command = LDAP_GROUP_MEMBERS_COMMAND
180-
ldap_group_members_command[LDAP_GROUP_MEMBERS_COMMAND.index("{auth}")] = auth_str
181-
182-
data_file = subprocess.run(
183-
ldap_group_members_command, stdout=subprocess.PIPE).stdout.decode('utf-8').split('\n')
184-
185-
search_results = list(filter(
186-
lambda x: not re.compile("#|dn:|cn:|objectClass:").match(x),
187-
(line for line in data_file)))
188-
189-
search_results.reverse()
190-
139+
def get_ldap_group_members_dict():
191140
group_data_dict = dict()
192-
index = 0
193-
while index < len(search_results) - 1:
194-
while not gidNumber_regex.match(search_results[index]):
195-
index += 1
196-
gid = search_results[index].replace(gidNumber_str, "")
197-
members_list = []
198-
while search_results[index] != "":
199-
if member_regex.match(search_results[index]):
200-
members_list.append(search_results[index].replace(member_str, ""))
201-
index += 1
202-
group_data_dict[gid] = members_list
203-
index += 1
141+
for group_gid in utils.get_ldap_groups(options.ldap_server, options.ldap_user, options.ldap_authtok):
142+
group_members = utils.get_ldap_group_members(group_gid, options.ldap_server, options.ldap_user, options.ldap_authtok)
143+
group_data_dict[group_gid] = group_members
204144

205145
return group_data_dict
206146

207147

208-
def get_ldap_active_users(filter_group_name):
209-
auth_str = subprocess.run(
210-
LDAP_AUTH_COMMAND,
211-
stdout=subprocess.PIPE
212-
).stdout.decode('utf-8').strip()
213-
214-
filter_str = ("(isMemberOf=CO:members:active)" if filter_group_name is None
215-
else f"(&(isMemberOf={filter_group_name})(isMemberOf=CO:members:active))")
216-
217-
ldap_active_users_command = LDAP_ACTIVE_USERS_COMMAND
218-
ldap_active_users_command[LDAP_ACTIVE_USERS_COMMAND.index("{auth}")] = auth_str
219-
ldap_active_users_command[LDAP_ACTIVE_USERS_COMMAND.index("{filter}")] = filter_str
220-
221-
active_users = subprocess.run(ldap_active_users_command, stdout=subprocess.PIPE).stdout.decode('utf-8').split('\n')
222-
users = set(line.replace("voPersonApplicationUID: ", "") if re.compile("dn: voPerson*")
223-
else "" for line in active_users)
224-
return users
225-
226-
227148
def create_user_to_projects_map(project_to_user_map, active_users, osggids_to_names):
228149
users_to_projects_map = dict()
229150
for osggid in project_to_user_map:
@@ -256,26 +177,25 @@ def get_co_api_data():
256177
for entry in entries:
257178
osggid_name_pair = entry.split(":")
258179
if len(osggid_name_pair) == 2:
259-
project_osggids_to_name[osggid_name_pair[0]] = osggid_name_pair[1]
180+
project_osggids_to_name[int(osggid_name_pair[0])] = osggid_name_pair[1].strip()
181+
r.close()
260182
else:
183+
r.close()
261184
raise OSError
262185
except OSError:
263186
with open(CACHE_FILENAME, "w") as w:
264187
project_osggids_to_name = get_groups_data_from_api()
265188
print(time.time(), file=w)
266189
for osggid, name in project_osggids_to_name.items():
267190
print(f"{osggid}:{name}", file=w)
268-
finally:
269-
if r:
270-
r.close()
271191

272192
return project_osggids_to_name
273193

274194

275195
def get_osguser_groups(filter_group_name=None):
276196
project_osggids_to_name = get_co_api_data()
277-
ldap_groups_members = get_ldap_group_members_data()
278-
ldap_users = get_ldap_active_users(filter_group_name)
197+
ldap_groups_members = get_ldap_group_members_dict()
198+
ldap_users = utils.get_ldap_active_users(options.ldap_server, options.ldap_user, options.ldap_authtok, filter_group_name)
279199

280200
active_project_osggids = set(ldap_groups_members.keys()).intersection(set(project_osggids_to_name.keys()))
281201
project_to_user_map = {

0 commit comments

Comments
 (0)