]> snippets.scripts.mit.edu Git - Scripts/git/.git/blob - __init__.py
dc3fefa36ca5b2c0e28cf07b59b7b98062ebced1
[Scripts/git/.git] / __init__.py
1 import os
2 import subprocess
3 import tempfile
4 import ldap
5 import ldap.filter
6
7 from django.contrib.auth.backends import RemoteUserBackend
8 from django.contrib.auth.hashers import UNUSABLE_PASSWORD
9 from django.contrib.auth.middleware import RemoteUserMiddleware
10 from django.contrib.auth.views import login
11 from django.contrib.auth import REDIRECT_FIELD_NAME
12 from django.http import HttpResponseRedirect
13 from django.contrib import auth
14 from django.core.exceptions import ObjectDoesNotExist
15 from django.core.validators import URLValidator, ValidationError
16
17 from django.conf import settings
18
19 def zephyr(msg, clas='message', instance='log', rcpt='nobody',):
20     proc = subprocess.Popen(
21         ['zwrite', '-d', '-n', '-c', clas, '-i', instance, rcpt, ],
22         stdin=subprocess.PIPE, stdout=subprocess.PIPE
23     )
24     proc.communicate(msg)
25
26 def UrlOrAfsValidator(value):
27     if value.startswith('/mit/') or value.startswith('/afs/'):
28         return
29     else:
30         try:
31             URLValidator()(value)
32         except ValidationError:
33             raise ValidationError('Provide a valid URL or AFS path')
34
35 def pag_check_helper(fn, args, aklog=False, ccname=None, **kwargs):
36     if 'executable' in kwargs:
37         raise ValueError('"executable" not supported with pag_check_*')
38
39     env = None
40     if 'env' in kwargs:
41         env = kwargs['env']
42         del kwargs['env']
43     if ccname:
44         if env is not None:
45             env = dict(env)
46         else:
47             env = dict(os.environ)
48         env['KRB5CCNAME'] = ccname
49
50     pagsh_cmd = 'exec "$@"'
51     if aklog: pagsh_cmd = "aklog && " + pagsh_cmd
52     args = ['pagsh', '-c', pagsh_cmd, 'exec', ] + args
53
54     return fn(args, env=env, **kwargs)
55
56 def pag_check_call(args, **kwargs):
57     return pag_check_helper(subprocess.check_call, args, **kwargs)
58 def pag_check_output(args, **kwargs):
59     return pag_check_helper(subprocess.check_output, args, **kwargs)
60
61 def kinit(keytab=None, principal=None, autodelete=True, ):
62     if not keytab:
63         keytab = settings.KRB_KEYTAB
64     if not principal:
65         principal = settings.KRB_PRINCIPAL
66     assert keytab and principal
67     fd = tempfile.NamedTemporaryFile(mode='rb', prefix="krb5cc_djmit_", delete=autodelete, )
68     env = dict(KRB5CCNAME=fd.name)
69     kinit_cmd = ['kinit', '-k', '-t', keytab, principal, ]
70     subprocess.check_call(kinit_cmd, env=env)
71     return fd
72
73 class ScriptsRemoteUserMiddleware(RemoteUserMiddleware):
74     header = 'SSL_CLIENT_S_DN_Email'
75
76 class ScriptsRemoteUserBackend(RemoteUserBackend):
77     def clean_username(self, username, ):
78         if '@' in username:
79             name, domain = username.split('@')
80             assert domain.upper() == 'MIT.EDU'
81             return name
82         else:
83             return username
84     def configure_user(self, user, ):
85         username = user.username
86         user.password = UNUSABLE_PASSWORD
87         con = ldap.open('ldap-too.mit.edu')
88         con.simple_bind_s("", "")
89         dn = "dc=mit,dc=edu"
90         fields = ['cn', 'sn', 'givenName', 'mail', ]
91         userfilter = ldap.filter.filter_format('uid=%s', [username])
92         result = con.search_s('dc=mit,dc=edu', ldap.SCOPE_SUBTREE, userfilter, fields)
93         if len(result) == 1:
94             user.first_name = result[0][1]['givenName'][0]
95             user.last_name = result[0][1]['sn'][0]
96             try:
97                 user.email = result[0][1]['mail'][0]
98             except KeyError:
99                 user.email = username + '@mit.edu'
100             try:
101                 user.groups.add(auth.models.Group.objects.get(name='mit'))
102             except ObjectDoesNotExist:
103                 print "Failed to retrieve mit group"
104         else:
105             raise ValueError, ("Could not find user with username '%s' (filter '%s')"%(username, userfilter))
106         try:
107             user.groups.add(auth.models.Group.objects.get(name='autocreated'))
108         except ObjectDoesNotExist:
109             print "Failed to retrieve autocreated group"
110         user.save()
111         return user
112
113 def get_or_create_mit_user(username, ):
114     """
115     Given an MIT username, return a Django user object for them.
116     If necessary, create (and save) the Django user for them.
117     If the MIT user doesn't exist, raises ValueError.
118     """
119     user, created = auth.models.User.objects.get_or_create(username=username, )
120     if created:
121         backend = ScriptsRemoteUserBackend()
122         # Raises ValueError if the user doesn't exist
123         try:
124             return backend.configure_user(user), created
125         except ValueError:
126             user.delete()
127             raise
128     else:
129         return user, created
130
131 def scripts_login(request, **kwargs):
132     host = request.META['HTTP_HOST'].split(':')[0]
133     if host == 'localhost':
134         return login(request, **kwargs)
135     elif request.META['SERVER_PORT'] == '444':
136         if request.user.is_authenticated():
137             # They're already authenticated --- go ahead and redirect
138             if 'redirect_field_name' in kwargs:
139                 redirect_field_name = kwargs['redirect_field_names']
140             else:
141                 from django.contrib.auth import REDIRECT_FIELD_NAME
142                 redirect_field_name = REDIRECT_FIELD_NAME
143             redirect_to = request.REQUEST.get(redirect_field_name, '')
144             if not redirect_to or '//' in redirect_to or ' ' in redirect_to:
145                 redirect_to = settings.LOGIN_REDIRECT_URL
146             return HttpResponseRedirect(redirect_to)
147         else:
148             return login(request, **kwargs)
149     else:
150         # Move to port 444
151         redirect_to = "https://%s:444%s" % (host, request.META['REQUEST_URI'], )
152         return HttpResponseRedirect(redirect_to)