1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
'''
Created on Dec 13, 2010
@author: leifj
'''
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
from coip.apps.user.models import Identifier
from django_extensions.utils import uuid
from django.contrib import auth
from django.contrib.auth.models import UNUSABLE_PASSWORD
def _headers(request,attr):
v = request.META.get(attr)
if not v:
return None
values = filter(lambda x: x != "(null)",v.split(";"))
return values;
def meta1(request,attr):
v = _headers(request,attr)
if v:
return v[0]
else:
return None
class COIPRemoteUserMiddleware(object):
"""
Middleware for utilizing Web-server-provided authentication.
If request.user is not authenticated, then this middleware attempts to
authenticate the username passed in the ``REMOTE_USER`` request header.
If authentication is successful, the user is automatically logged in to
persist the user in the session.
The header used is configurable and defaults to ``REMOTE_USER``. Subclass
this class and change the ``header`` attribute if you need to use a
different header.
"""
# Name of request header to grab username from. This will be the key as
# used in the request.META dictionary, i.e. the normalization of headers to
# all uppercase and the addition of "HTTP_" prefix apply.
header = "REMOTE_USER"
def process_request(self, request):
# AuthenticationMiddleware is required so that request.user exists.
if not hasattr(request, 'user'):
raise ImproperlyConfigured(
"The Django remote user auth middleware requires the"
" authentication middleware to be installed. Edit your"
" MIDDLEWARE_CLASSES setting to insert"
" 'django.contrib.auth.middleware.AuthenticationMiddleware'"
" before the RemoteUserMiddleware class.")
if request.user.is_authenticated():
# this is to make internal users work too...
if not request.user.is_anonymous():
user = request.user
identifier,created = Identifier.objects.get_or_create(user=user,value=user.username,type=Identifier.INTERNAL,verified=True)
user.get_profile().identifier = identifier
return
try:
username = request.META[self.header]
except KeyError:
# If specified header doesn't exist then return (leaving
# request.user set to AnonymousUser by the
# AuthenticationMiddleware).
return
idp = meta1(request,'Shib-Identity-Provider')
if not idp:
raise Exception("No IdP information in request")
user = None
identifier = None
try:
# Try to find a user based on the identifier received. If we find it we turn
# around and authenticate the username as if it was received in the header.
idp = meta1(request,'Shib-Identity-Provider')
identifier = Identifier.objects.get(value=username,type=Identifier.FEDERATION,idp=idp,verified=True)
user = auth.authenticate(remote_user=identifier.user.username)
except ObjectDoesNotExist:
pass
if user == None:
# We've never seen this identifier before. Create a new random uuid for the
# django username and associate the identifier with it.
user = auth.authenticate(remote_user=uuid.uuid4());
user.password = UNUSABLE_PASSWORD
user.save()
identifier = Identifier.objects.create(user=user,value=username,type=Identifier.FEDERATION,idp=idp,verified=True)
if not identifier:
raise Exception("Unable to create user/id mapping")
update = False
cn = meta1(request,'cn')
fn = meta1(request,'givenName')
ln = meta1(request,'sn')
if not cn:
cn = meta1(request,'displayName')
if not cn and fn and ln:
cn = "%s %s" % (fn,ln)
if not cn:
cn = "%s according to %s" % (identifier.value,identifier.idp)
if identifier.display_name != cn:
identifier.display_name = cn
identifier.save()
mail = meta1(request,'mail')
if mail:
mail_id,created = Identifier.objects.get_or_create(user=user,value=mail,type=Identifier.EMAIL,verified=True)
user.email = mail
update = True
if fn:
identifier.user.first_name = fn
update = True
if ln:
identifier.user.last_name = ln
update = True
if update:
identifier.user.save()
if user:
# User is valid. Set request.user and persist user in the session
# by logging the user in.
user.get_profile().identifier = identifier
auth.login(request, user)
def clean_username(self, username, request):
"""
Allows the backend to clean the username, if the backend defines a
clean_username method.
"""
backend_str = request.session[auth.BACKEND_SESSION_KEY]
backend = auth.load_backend(backend_str)
try:
username = backend.clean_username(username)
except AttributeError: # Backend has no clean_username method.
pass
return username
|