source: asadb/mit/__init__.py

stablestage
Last change on this file was 8c0a2ff, checked in by Alex Dehnert <adehnert@…>, 12 years ago

Scripts auth: don't activate on 127.0.0.1 either

The scripts auth module has long delegated to the standard Django auth when the
hostname was localhost, in order to ignore local dev server instances. This
makes it also delegate to standard Django for 127.0.0.1 as well. I'm not sure
why this hadn't come up before now... A quick look at the Django codebase
suggests this isn't a recent change.

  • 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.backends import RemoteUserBackend
8from django.contrib.auth.middleware import RemoteUserMiddleware
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.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
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 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)
Note: See TracBrowser for help on using the repository browser.