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