source: asadb/util/sync_moira_authz.py @ d85ba8f

space-accessstablestage
Last change on this file since d85ba8f was c8cb9ba, checked in by Alex Dehnert <adehnert@…>, 14 years ago

Sync staff status with the asa-admin list as well

It's possible we actually want to have some whitelist of "people who should
always have staff status". Not clearly worthwhile enough for me to implement
something now, though.

  • Property mode set to 100755
File size: 5.9 KB
Line 
1#!/usr/bin/python
2
3import afs.pts
4import ldap
5import ldap.dn
6import ldap.filter
7import os
8import sys
9import subprocess
10
11if __name__ == '__main__':
12    cur_file = os.path.abspath(__file__)
13    django_dir = os.path.abspath(os.path.join(os.path.dirname(cur_file), '..'))
14    sys.path.append(django_dir)
15    os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
16
17import django.contrib.auth.models
18
19import mit
20import settings
21
22class DjangoConnector(object):
23    def __init__(self, ):
24        self.dj_groups = django.contrib.auth.models.Group.objects
25
26    def sync_helper(self, sys_name, dj_members, adder, remover, ):
27        kept = []
28        added = []
29        nonexist = []
30        created = []
31        removed = []
32        sys_members = self.get_members(sys_name)
33        dj_usernames = set([m.username for m in dj_members])
34        for username in sys_members:
35            if username in dj_usernames:
36                kept.append(username)
37            else:
38                # Need to add to the Django group
39                try:
40                    user, is_new = mit.get_or_create_mit_user(username, )
41                    if is_new: created.append(username)
42                    adder(user)
43                    added.append(username)
44                except ValueError:
45                    nonexist.append(username)
46        for user in dj_members:
47            username = user.username
48            if username in sys_members:
49                assert username in kept
50            else:
51                remover(user)
52                removed.append(username)
53        return {
54            'change' : len(added) + len(removed),
55            'keep' : kept,
56            'add'  : added,
57            'create' : created,
58            'nonexist' : nonexist,
59            'remove': removed,
60        }
61
62    def sync_staff(self, sys_name, ):
63        dj_members = django.contrib.auth.models.User.objects.filter(is_staff=True, )
64        def adder(user, ):
65            user.is_staff = True
66            user.save()
67        def remover(user, ):
68            user.is_staff = False
69            user.save()
70        return self.sync_helper(sys_name, dj_members, adder, remover, )
71
72    def sync_members(self, sys_name, dj_name, ):
73        dj_group = self.dj_groups.get(name=dj_name)
74        dj_members = dj_group.user_set.all()
75        adder = lambda user: user.groups.add(dj_group)
76        remover = lambda user: user.groups.remove(dj_group)
77        return self.sync_helper(sys_name, dj_members, adder, remover, )
78
79    def sync_many(con, what, force_print=False, ):
80        changed = False
81        results = {}
82        for sys_name, dj_group in what:
83            assert dj_group not in results
84            if dj_group == "STAFF":
85                results[dj_group] = con_afs.sync_staff(sys_name, )
86            else:
87                results[dj_group] = con_afs.sync_members(sys_name, dj_group)
88            if results[dj_group]['change']: changed = True
89        if changed or force_print:
90            for group in results:
91                print ""
92                print "Results for %s:" % (group, )
93                for key, value in results[group].items():
94                    print "%7s:\t%s" % (key, value, )
95
96
97class LDAPConnector(DjangoConnector):
98    name = "LDAP"
99
100    def __init__(self, *args, **kwargs):
101        super(LDAPConnector, self).__init__(*args, **kwargs)
102        self.con = ldap.initialize('ldaps://ldap-too.mit.edu')
103        self.con.simple_bind_s("", "")
104
105    def get_members(self, groupname):
106        base_dn = 'ou=lists,ou=moira,dc=mit,dc=edu'
107        groupfilter = ldap.filter.filter_format('(&(objectClass=group)(displayName=%s))', [groupname])
108        result = self.con.search_s(base_dn, ldap.SCOPE_SUBTREE, groupfilter, )
109        if len(result) > 1: print "WARNING: More than one result returned for %s" % groupname
110        if len(result) < 1: print "WARNING: Only no results returned for %s" % groupname
111        attrs = result[0][1]
112        members = attrs['member']
113        ret = set()
114        for member in members:
115            member_dn = ldap.dn.explode_dn(member)
116            assert len(member_dn) == 5
117            c_val, c_type, c_moira, c_mit, c_edu = member_dn
118            assert (c_moira, c_mit, c_edu, ) == ('OU=moira', 'dc=MIT', 'dc=EDU', )
119            c_val_key, c_val_sep, c_val_val = c_val.partition('=')
120            if c_type == 'OU=strings':
121                ret.add(('string', c_val_val, ))
122            elif c_type == 'OU=users':
123                ret.add(('user', c_val_val, ))
124            elif c_type == 'OU=kerberos':
125                ret.add(('kerberos', c_val_val, ))
126            else:
127                assert False, "Don't know what %s is" % (c_type, )
128        return [r[1] for r in ret if r[0] == 'user']
129
130class AFSConnector(DjangoConnector):
131    name = "AFS"
132
133    def __init__(self, *args, **kwargs):
134        super(AFSConnector, self).__init__(*args, **kwargs)
135        #self.login()
136        self.pts = afs.pts.PTS(sec=afs.pts.PTS_ENCRYPT, cell='athena.mit.edu', )
137    def login(self, ):
138        if settings.KRB_KEYTAB:
139            kinit_cmd = ['kinit', '-k', '-t', settings.KRB_KEYTAB, settings.KRB_PRINCIPAL, ]
140            subprocess.check_call(kinit_cmd)
141            subprocess.check_call(['aklog', 'athena', ])
142
143    def get_members(self, groupname, ):
144        afs_members = self.pts.getEntry("system:%s" % (groupname, )).members
145        members = [ m.name for m in afs_members ]
146        return members
147
148sync_pairs = [
149    ('asa-admin', 'STAFF', ),
150    ('asa-admin', 'asa-ebm', ),
151    ('asa-db-mit-deskworker', 'mit-deskworker', ),
152    ('asa-db-mit-offices', 'mit-offices', ),
153    ('asa-db-mit-sao', 'mit-sao', ),
154]
155
156def test_memberships(cons):
157    for sys_name, dj_group in sync_pairs:
158        for con in cons:
159            members = con.get_members(sys_name)
160            print "%s\t%s\t%s" % (con.name, sys_name, sorted(members))
161
162if __name__ == '__main__':
163    con_afs = AFSConnector()
164    #con_ldap = LDAPConnector()
165    #test_memberships([con_afs, con_ldap, ])
166    con_afs.sync_many(sync_pairs)
Note: See TracBrowser for help on using the repository browser.