8
8
# * Make sure the view "login" from this module is used for login
9
9
# * Map an url somwehere (typically /auth_receive/) to the auth_receive
10
10
# view.
11
+ # * To get notified when a user is created from upstream, connect to the signal
12
+ # auth_user_created_from_upstream.
11
13
# * To receive live updates (not just during login), map an url somewhere
12
14
# (typically /auth_api/) to the auth_api view.
13
15
# * To receive live updates, also connect to the signal auth_user_data_received.
44
46
import time
45
47
46
48
49
+ # This signal fires when a user is created based on data from upstream.
50
+ auth_user_created_from_upstream = Signal (providing_args = ['user' , ])
51
+
47
52
# This signal fires whenever new user data has been received. Note that this
48
53
# happens *after* first_name, last_name and email has been updated on the user
49
54
# record, so those are not included in the userdata struct.
@@ -104,10 +109,15 @@ def auth_receive(request):
104
109
return HttpResponse ("Missing data in url!" , status = 400 )
105
110
106
111
# Set up an AES object and decrypt the data we received
107
- decryptor = AES .new (base64 .b64decode (settings .PGAUTH_KEY ),
108
- AES .MODE_CBC ,
109
- base64 .b64decode (str (request .GET ['i' ]), "-_" ))
110
- s = decryptor .decrypt (base64 .b64decode (str (request .GET ['d' ]), "-_" )).rstrip (b' ' ).decode ('utf8' )
112
+ try :
113
+ decryptor = AES .new (base64 .b64decode (settings .PGAUTH_KEY ),
114
+ AES .MODE_CBC ,
115
+ base64 .b64decode (str (request .GET ['i' ]), "-_" ))
116
+ s = decryptor .decrypt (base64 .b64decode (str (request .GET ['d' ]), "-_" )).rstrip (b' ' ).decode ('utf8' )
117
+ except UnicodeDecodeError :
118
+ return HttpResponse ("Badly encoded data found" , 400 )
119
+ except Exception :
120
+ return HttpResponse ("Could not decrypt data" , status = 400 )
111
121
112
122
# Now un-urlencode it
113
123
try :
@@ -174,6 +184,8 @@ def auth_receive(request):
174
184
)
175
185
user .save ()
176
186
187
+ auth_user_created_from_upstream .send (sender = auth_receive , user = user )
188
+
177
189
# Ok, we have a proper user record. Now tell django that
178
190
# we're authenticated so it persists it in the session. Before
179
191
# we do that, we have to annotate it with the backend information.
@@ -281,7 +293,7 @@ def _conditionally_update_record(rectype, recordkey, structkey, fieldmap, struct
281
293
# Unlike the authentication, searching does not involve the browser - we just make
282
294
# a direct http call.
283
295
def user_search (searchterm = None , userid = None ):
284
- # If upsteam isn't responding quickly, it's not going to respond at all, and
296
+ # If upstream isn't responding quickly, it's not going to respond at all, and
285
297
# 10 seconds is already quite long.
286
298
socket .setdefaulttimeout (10 )
287
299
if userid :
@@ -308,6 +320,30 @@ def user_search(searchterm=None, userid=None):
308
320
return j
309
321
310
322
323
+ # Subscribe to any changes about this user on the community auth upstream
324
+ def subscribe_to_user_changes (userid ):
325
+ socket .setdefaulttimeout (10 )
326
+
327
+ body = json .dumps ({
328
+ 'u' : userid ,
329
+ })
330
+
331
+ h = hmac .digest (
332
+ base64 .b64decode (settings .PGAUTH_KEY ),
333
+ msg = bytes (body , 'utf-8' ),
334
+ digest = 'sha512' ,
335
+ )
336
+
337
+ # Ignore the result code, just post it
338
+ requests .post (
339
+ '{0}subscribe/' .format (settings .PGAUTH_REDIRECT ),
340
+ data = body ,
341
+ headers = {
342
+ 'X-pgauth-sig' : base64 .b64encode (h ),
343
+ },
344
+ )
345
+
346
+
311
347
# Import a user into the local authentication system. Will initially
312
348
# make a search for it, and if anything other than one entry is returned
313
349
# the import will fail.
@@ -335,4 +371,6 @@ def user_import(uid):
335
371
)
336
372
u .save ()
337
373
374
+ auth_user_created_from_upstream .send (sender = user_import , user = u )
375
+
338
376
return u
0 commit comments