def browserid_login(request): """Multi-mode BrowserID authentication form processor. Handles login and register browserid verification. If the mode is login, we are done. If the mode is register then we start new profile flow. Also handles corner cases. Login and register sasl-browserid verification steps are very similar and the corner cases blur the lines, so this is best as one url. We use the form from django-browserid, but since the LDAP server does the BrowserID auth behind the scenes, we don't use it's auth code nor it's views. """ form = ModalBrowserIdForm(data=request.POST) if form.is_valid(): assertion = form.cleaned_data['assertion'] store_assertion(request, assertion) mode = form.cleaned_data['mode'] user = auth.authenticate(request=request, assertion=assertion) if user: auth.login(request, user) return redirect('profile', request.user.unique_id) else: url = absolutify("%s?link=%s" % (reverse('register'), mode)) return redirect(url) else: msg = _('Sorry, but there were problems with the info you submitted. ' 'Please review the form, correct any errors, and try again.') messages.warning(request, msg) log.warning("Form didn't validate %s" % str(request.POST)) return redirect('home')
def authenticate(self, request=None, assertion=None): """Authentication based on BrowserID assertion. ``django.contrib.auth`` backend that is SASL and BrowserID savy. Uses session to maintain assertion over multiple requests. """ if not (request and assertion): return None store_assertion(request, assertion) directory = UserSession(request) with statsd.timer('larper.sasl_bind_time'): (registered, details) = _get_registered_user(directory, request) if registered: person = directory.get_by_unique_id(details) defaults = dict(username=person.username, first_name=person.first_name, last_name=person.last_name, email=person.username) user, created = User.objects.get_or_create(username=person.username, defaults=defaults) if created: user.set_unusable_password() user.save() return user return None
def _get_registered_user(directory, request): """Checks the directory for a registered user. Function returns a tuple of registered and details. Registered is True if a user is found and False otherwise. If registered is True then details contains info about the known user. The statsd timer ``larper.sasl_bind_time`` allows IT to detect timeouts between ldap and https://browserid.org/verify. If this counter gets large, check DNS routes between slapd servers and browserid.org. The statsd counter ``browserid.unknown_error_checking_registered_user`` allows IT to detect a problem with the backend auth system. """ registered = False details = None try: (registered, details) = directory.registered_user() if registered: request.session['unique_id'] = details else: request.session['verified_email'] = details except Exception, e: # Look at syslogs on slapd hosts to investigate unknown issues messages.error(request, _("We're Sorry, but Something Went Wrong!")) statsd.incr('browserid.unknown_error_checking_registered_user') log.error("Unknown error, clearing session assertion [%s]", e) store_assertion(request, None)
def authenticate(self, request=None, assertion=None): """Authentication based on BrowserID assertion. ``django.contrib.auth`` backend that is SASL and BrowserID savy. Uses session to maintain assertion over multiple requests. """ if not (request and assertion): return None store_assertion(request, assertion) directory = UserSession(request) with statsd.timer('larper.sasl_bind_time'): (registered, details) = _get_registered_user(directory, request) if registered: person = directory.get_by_unique_id(details) defaults = dict(username=person.username, first_name=person.first_name, last_name=person.last_name, email=person.username) user, created = User.objects.get_or_create( username=person.username, defaults=defaults) if created: user.set_unusable_password() user.save() return user return None
def test_connection_pooling(self): # Don't use _mock_request, nor TestLarper since we want full control # over the request to find pooling bugs rf = RequestFactory() request = rf.get('/en-US') request.session = {} request.user = MockUser('*****@*****.**', '7f3a67u000001') larper.store_assertion(request, 'abcdefghijklmnop') R = larper.READ W = larper.WRITE directory = UserSession.connect(request) self.assertFalse(hasattr(request, 'larper_conns')) regi = RegistrarSession.connect(request) self.assertFalse(hasattr(request, 'larper_conns')) regi_W_conn = regi._ensure_conn(W) regi_W_conn2 = regi._ensure_conn(W) self.assertIs(regi_W_conn, regi_W_conn2) self.assertTrue(hasattr(request, 'larper_conns')) self.assertEqual(len(request.larper_conns[R].keys()), 0) self.assertEqual(len(request.larper_conns[W].keys()), 1) dir_W_conn = directory._ensure_conn(W) dir_W_conn2 = directory._ensure_conn(W) self.assertIs(dir_W_conn, dir_W_conn2) self.assertEqual(len(request.larper_conns[R].keys()), 0) self.assertEqual(len(request.larper_conns[W].keys()), 2) dir_R_conn = directory._ensure_conn(R) admin = AdminSession.connect(request) admin_R_conn = admin._ensure_conn(R) admin_R_conn2 = admin._ensure_conn(R) admin_W_conn = admin._ensure_conn(W) self.assertIs(admin_R_conn, admin_R_conn2) self.assertIsNot(admin_R_conn, admin_W_conn) for conn in (regi_W_conn, dir_R_conn, admin_R_conn, admin_W_conn): # nor is it dir_R_conn2 or admin_R_conn2 self.assertIsNot(dir_W_conn, conn) self.assertEqual(len(request.larper_conns[R].keys()), 2) self.assertEqual(len(request.larper_conns[W].keys()), 3) directory.disconnect(request) self.assertEqual(len(request.larper_conns[R].keys()), 0) self.assertEqual(len(request.larper_conns[W].keys()), 0)
def _mock_request(path, username='******', unique_id='7f3a67u000001', assertion='abcdefghijklmnop'): global requests rf = RequestFactory() # mock authenticated user request = rf.get(path) request.session = {} request.user = MockUser(username, unique_id) larper.store_assertion(request, assertion) requests.append(request) return request