source: asadb/mit/__init__.py @ b42118c

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

kinit when creating a MoiraList? object

This allows group/diffs.py to work without kinit'ing outside the script, fixing
the key deficiency in ac9b167bcf85a9f723e27967649c2c033f2259da.

  • Property mode set to 100644
File size: 5.5 KB
Line 
1import os
2import subprocess
3import tempfile
4import ldap
5import ldap.filter
6
7from django.contrib.auth.middleware import RemoteUserMiddleware
8from django.contrib.auth.backends import RemoteUserBackend
9from django.contrib.auth.views import login
10from django.contrib.auth import REDIRECT_FIELD_NAME
11from django.http import HttpResponseRedirect
12from django.contrib import auth
13from django.core.exceptions import ObjectDoesNotExist
14from django.core.validators import URLValidator, ValidationError
15
16from django.conf import settings
17
18def 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
25def 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
34def 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
55def pag_check_call(args, **kwargs):
56    return pag_check_helper(subprocess.check_call, args, **kwargs)
57def pag_check_output(args, **kwargs):
58    return pag_check_helper(subprocess.check_output, args, **kwargs)
59
60def 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
72class ScriptsRemoteUserMiddleware(RemoteUserMiddleware):
73    header = 'SSL_CLIENT_S_DN_Email'
74
75class 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.password = "ScriptsSSLAuth"
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
112def 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
130def scripts_login(request, **kwargs):
131    host = request.META['HTTP_HOST'].split(':')[0]
132    if host == 'localhost':
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)
Note: See TracBrowser for help on using the repository browser.