def do_complete(strategy, login, user=None, redirect_name='next', *args, **kwargs): # pop redirect value before the session is trashed on login() data = strategy.request_data() redirect_value = strategy.session_get(redirect_name, '') or \ data.get(redirect_name, '') is_authenticated = user_is_authenticated(user) user = is_authenticated and user or None partial = partial_pipeline_data(strategy, user, *args, **kwargs) if partial: xargs, xkwargs = partial user = strategy.continue_pipeline(*xargs, **xkwargs) else: user = strategy.complete(user=user, request=strategy.request, *args, **kwargs) if user and not isinstance(user, strategy.storage.user.user_model()): return user if is_authenticated: if not user: url = setting_url(strategy, redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(strategy, redirect_value, 'NEW_ASSOCIATION_REDIRECT_URL', 'LOGIN_REDIRECT_URL') elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, 'is_new', False) social_user = user.social_user login(strategy, user, social_user) # store last login backend name in session strategy.session_set('social_auth_last_login_backend', social_user.provider) if is_new: url = setting_url(strategy, redirect_value, 'NEW_USER_REDIRECT_URL', 'LOGIN_REDIRECT_URL') else: url = setting_url(strategy, redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(strategy, 'INACTIVE_USER_URL', 'LOGIN_ERROR_URL', 'LOGIN_URL') else: url = setting_url(strategy, 'LOGIN_ERROR_URL', 'LOGIN_URL') if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ('?' in url and '&' or '?') + \ '{0}={1}'.format(redirect_name, redirect_value) if strategy.setting('SANITIZE_REDIRECTS', True): url = sanitize_redirect(strategy.request_host(), url) or \ strategy.setting('LOGIN_REDIRECT_URL') return strategy.redirect(url)
def do_auth(backend, redirect_name='next'): # Clean any partial pipeline data backend.strategy.clean_partial_pipeline() # Save any defined next value into session data = backend.strategy.request_data(merge=False) # Save extra data into session. for field_name in backend.setting('FIELDS_STORED_IN_SESSION', []): if field_name in data: backend.strategy.session_set(field_name, data[field_name]) if redirect_name in data: # Check and sanitize a user-defined GET/POST next field value redirect_uri = data[redirect_name] if backend.setting('SANITIZE_REDIRECTS', True): allowed_hosts = backend.setting('ALLOWED_REDIRECT_HOSTS', []) + \ [backend.strategy.request_host()] redirect_uri = sanitize_redirect(allowed_hosts, redirect_uri) backend.strategy.session_set( redirect_name, redirect_uri or backend.setting('LOGIN_REDIRECT_URL') ) return backend.start()
def do_complete(strategy, login, user=None, redirect_name="next", *args, **kwargs): # pop redirect value before the session is trashed on login() data = strategy.request_data() redirect_value = strategy.session_get(redirect_name, "") or data.get(redirect_name, "") is_authenticated = user_is_authenticated(user) user = is_authenticated and user or None default_redirect = strategy.setting("LOGIN_REDIRECT_URL") url = default_redirect login_error_url = strategy.setting("LOGIN_ERROR_URL") or strategy.setting("LOGIN_URL") partial = partial_pipeline_data(strategy, user, *args, **kwargs) if partial is not None: idx, backend, xargs, xkwargs = partial if backend == strategy.backend.name: user = strategy.continue_pipeline(pipeline_index=idx, *xargs, **xkwargs) else: strategy.clean_partial_pipeline() user = strategy.complete(user=user, request=strategy.request, *args, **kwargs) else: user = strategy.complete(user=user, request=strategy.request, *args, **kwargs) if user and not isinstance(user, strategy.storage.user.user_model()): return user if is_authenticated: if not user: url = redirect_value or default_redirect else: url = redirect_value or strategy.setting("NEW_ASSOCIATION_REDIRECT_URL") or default_redirect elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, "is_new", False) social_user = user.social_user login(strategy, user) # store last login backend name in session strategy.session_set("social_auth_last_login_backend", social_user.provider) # Remove possible redirect URL from session, if this is a new # account, send him to the new-users-page if defined. new_user_redirect = strategy.setting("NEW_USER_REDIRECT_URL") if new_user_redirect and is_new: url = new_user_redirect else: url = redirect_value or default_redirect else: url = strategy.setting("INACTIVE_USER_URL", login_error_url) else: url = login_error_url if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ("?" in url and "&" or "?") + "{0}={1}".format(redirect_name, redirect_value) if strategy.setting("SANITIZE_REDIRECTS", True): url = sanitize_redirect(strategy.request_host(), url) or strategy.setting("LOGIN_REDIRECT_URL") return strategy.redirect(url)
def finish_complete(backend, login, user, is_authenticated, data, redirect_name='next', *args, **kwargs): # pop redirect value before the session is trashed on login(), but after # the pipeline so that the pipeline can change the redirect if needed redirect_value = backend.strategy.session_get(redirect_name, '') or \ data.get(redirect_name, '') user_model = backend.strategy.storage.user.user_model() if user and not isinstance(user, user_model): return user if is_authenticated: if not user: url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, redirect_value, 'NEW_ASSOCIATION_REDIRECT_URL', 'LOGIN_REDIRECT_URL') elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, 'is_new', False) social_user = user.social_user login(backend, user, social_user) # store last login backend name in session backend.strategy.session_set('social_auth_last_login_backend', social_user.provider) if is_new: url = setting_url(backend, 'NEW_USER_REDIRECT_URL', redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') else: if backend.setting('INACTIVE_USER_LOGIN', False): social_user = user.social_user login(backend, user, social_user) url = setting_url(backend, 'INACTIVE_USER_URL', 'LOGIN_ERROR_URL', 'LOGIN_URL') else: url = setting_url(backend, 'LOGIN_ERROR_URL', 'LOGIN_URL') if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ('?' in url and '&' or '?') + \ '{0}={1}'.format(redirect_name, redirect_value) if backend.setting('SANITIZE_REDIRECTS', True): allowed_hosts = backend.setting('ALLOWED_REDIRECT_HOSTS', []) + \ [backend.strategy.request_host()] url = sanitize_redirect(allowed_hosts, url) or \ backend.setting('LOGIN_REDIRECT_URL') return backend.strategy.redirect(url)
def do_complete(backend, login, user=None, redirect_name="next", *args, **kwargs): # pop redirect value before the session is trashed on login() data = backend.strategy.request_data() redirect_value = backend.strategy.session_get(redirect_name, "") or data.get(redirect_name, "") is_authenticated = user_is_authenticated(user) user = is_authenticated and user or None partial = partial_pipeline_data(backend, user, *args, **kwargs) if partial: xargs, xkwargs = partial user = backend.continue_pipeline(*xargs, **xkwargs) else: user = backend.complete(user=user, *args, **kwargs) user_model = backend.strategy.storage.user.user_model() if user and not isinstance(user, user_model): return user if is_authenticated: if not user: url = setting_url(backend, redirect_value, "LOGIN_REDIRECT_URL") else: url = setting_url(backend, redirect_value, "NEW_ASSOCIATION_REDIRECT_URL", "LOGIN_REDIRECT_URL") elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, "is_new", False) social_user = user.social_user login(backend, user, social_user) # store last login backend name in session backend.strategy.session_set("social_auth_last_login_backend", social_user.provider) if is_new: url = setting_url(backend, "NEW_USER_REDIRECT_URL", redirect_value, "LOGIN_REDIRECT_URL") else: url = setting_url(backend, redirect_value, "LOGIN_REDIRECT_URL") else: url = setting_url(backend, "INACTIVE_USER_URL", "LOGIN_ERROR_URL", "LOGIN_URL") else: url = setting_url(backend, "LOGIN_ERROR_URL", "LOGIN_URL") if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ("?" in url and "&" or "?") + "{0}={1}".format(redirect_name, redirect_value) if backend.setting("SANITIZE_REDIRECTS", True): url = sanitize_redirect(backend.strategy.request_host(), url) or backend.setting("LOGIN_REDIRECT_URL") return backend.strategy.redirect(url)
def start(self): """ Prepare to handle a login request. This method replaces social.actions.do_auth and must be kept in sync with any upstream changes in that method. In the current version of the upstream, this means replacing the logic to populate the session from request parameters, and not calling backend.start() to avoid an unwanted redirect to the non-existent login page. """ # Clean any partial pipeline data self.strategy.clean_partial_pipeline() # Save validated LTI parameters (or None if invalid or not submitted) validated_lti_params = self.get_validated_lti_params(self.strategy) # Set a auth_entry here so we don't have to receive that as a custom parameter self.strategy.session_setdefault('auth_entry', 'login') if not validated_lti_params: self.strategy.session_set(LTI_PARAMS_KEY, None) raise AuthFailed(self, "LTI parameters could not be validated.") else: self.strategy.session_set(LTI_PARAMS_KEY, validated_lti_params) # Save extra data into session. # While Basic LTI 1.0 specifies that the message is to be signed using OAuth, implying # that any GET parameters should be stripped from the base URL and included as signed # parameters, typical LTI Tool Consumer implementations do not support this behaviour. As # a workaround, we accept TPA parameters from LTI custom parameters prefixed with "tpa_". for field_name in self.setting('FIELDS_STORED_IN_SESSION', []): if 'custom_tpa_' + field_name in validated_lti_params: self.strategy.session_set( field_name, validated_lti_params['custom_tpa_' + field_name]) if 'custom_tpa_' + REDIRECT_FIELD_NAME in validated_lti_params: # Check and sanitize a user-defined GET/POST next field value redirect_uri = validated_lti_params['custom_tpa_' + REDIRECT_FIELD_NAME] if self.setting('SANITIZE_REDIRECTS', True): redirect_uri = sanitize_redirect(self.strategy.request_host(), redirect_uri) self.strategy.session_set( REDIRECT_FIELD_NAME, redirect_uri or self.setting('LOGIN_REDIRECT_URL'))
def do_auth(strategy, redirect_name="next"): # Save any defined next value into session data = strategy.request_data(merge=False) # Save extra data into session. for field_name in strategy.setting("FIELDS_STORED_IN_SESSION", []): if field_name in data: strategy.session_set(field_name, data[field_name]) if redirect_name in data: # Check and sanitize a user-defined GET/POST next field value redirect_uri = data[redirect_name] if strategy.setting("SANITIZE_REDIRECTS", True): redirect_uri = sanitize_redirect(strategy.request_host(), redirect_uri) strategy.session_set(redirect_name, redirect_uri or strategy.setting("LOGIN_REDIRECT_URL")) return strategy.start()
def auth(request, backend): # Save any defined next value into session data = request.POST if request.method == 'POST' else request.GET # Save extra data into session. for field_name in request.strategy.setting('FIELDS_STORED_IN_SESSION', []): if field_name in data: request.session[field_name] = data[field_name] if REDIRECT_FIELD_NAME in data: # Check and sanitize a user-defined GET/POST next field value redirect = data[REDIRECT_FIELD_NAME] if setting('SANITIZE_REDIRECTS', True): redirect = sanitize_redirect(request.get_host(), redirect) request.session[REDIRECT_FIELD_NAME] = redirect or DEFAULT_REDIRECT return request.strategy.start()
def _auth(self, backend): # Save any defined next value into session strategy = self.strategy # Save extra data into session. for field_name in strategy.setting('FIELDS_STORED_IN_SESSION', []): if field_name in self.data: self.session[field_name] = self.data[field_name] if 'next' in self.data: # Check and sanitize a user-defined GET/POST next field value redirect_uri = self.data['next'] if strategy.setting('SANITIZE_REDIRECTS', True): redirect_uri = sanitize_redirect(web.ctx.host, redirect_uri) self.session['next'] = redirect_uri or \ strategy.setting('LOGIN_REDIRECT_URL') return strategy.start()
def auth(backend): # Save any defined next value into session strategy = g.strategy data = request.form if request.method == "POST" else request.args # Save extra data into session. for field_name in strategy.setting("FIELDS_STORED_IN_SESSION", []): if field_name in data: session[field_name] = data[field_name] if "next" in data: # Check and sanitize a user-defined GET/POST next field value redirect_uri = data["next"] if strategy.setting("SANITIZE_REDIRECTS", True): redirect_uri = sanitize_redirect(request.host, redirect_uri) session["next"] = redirect_uri or strategy.setting("LOGIN_REDIRECT_URL") return strategy.start()
def do_auth(strategy, redirect_name='next'): # Save any defined next value into session data = strategy.request_data(merge=False) # Save extra data into session. for field_name in strategy.setting('FIELDS_STORED_IN_SESSION', []): if field_name in data: strategy.session_set(field_name, data[field_name]) if redirect_name in data: # Check and sanitize a user-defined GET/POST next field value redirect_uri = data[redirect_name] if strategy.setting('SANITIZE_REDIRECTS', True): redirect_uri = sanitize_redirect(strategy.request_host(), redirect_uri) strategy.session_set( redirect_name, redirect_uri or strategy.setting('LOGIN_REDIRECT_URL')) return strategy.start()
def start(self): """ Prepare to handle a login request. This method replaces social.actions.do_auth and must be kept in sync with any upstream changes in that method. In the current version of the upstream, this means replacing the logic to populate the session from request parameters, and not calling backend.start() to avoid an unwanted redirect to the non-existent login page. """ # Clean any partial pipeline data self.strategy.clean_partial_pipeline() # Save validated LTI parameters (or None if invalid or not submitted) validated_lti_params = self.get_validated_lti_params(self.strategy) # Set a auth_entry here so we don't have to receive that as a custom parameter self.strategy.session_setdefault('auth_entry', 'login') if not validated_lti_params: self.strategy.session_set(LTI_PARAMS_KEY, None) raise AuthFailed(self, "LTI parameters could not be validated.") else: self.strategy.session_set(LTI_PARAMS_KEY, validated_lti_params) # Save extra data into session. # While Basic LTI 1.0 specifies that the message is to be signed using OAuth, implying # that any GET parameters should be stripped from the base URL and included as signed # parameters, typical LTI Tool Consumer implementations do not support this behaviour. As # a workaround, we accept TPA parameters from LTI custom parameters prefixed with "tpa_". for field_name in self.setting('FIELDS_STORED_IN_SESSION', []): if 'custom_tpa_' + field_name in validated_lti_params: self.strategy.session_set(field_name, validated_lti_params['custom_tpa_' + field_name]) if 'custom_tpa_' + REDIRECT_FIELD_NAME in validated_lti_params: # Check and sanitize a user-defined GET/POST next field value redirect_uri = validated_lti_params['custom_tpa_' + REDIRECT_FIELD_NAME] if self.setting('SANITIZE_REDIRECTS', True): redirect_uri = sanitize_redirect(self.strategy.request_host(), redirect_uri) self.strategy.session_set(REDIRECT_FIELD_NAME, redirect_uri or self.setting('LOGIN_REDIRECT_URL'))
def do_auth(backend, redirect_name='next'): # Save any defined next value into session data = backend.strategy.request_data(merge=False) # Save extra data into session. for field_name in backend.setting('FIELDS_STORED_IN_SESSION', []): if field_name in data: backend.strategy.session_set(field_name, data[field_name]) if redirect_name in data: # Check and sanitize a user-defined GET/POST next field value redirect_uri = data[redirect_name] if backend.setting('SANITIZE_REDIRECTS', True): redirect_uri = sanitize_redirect(backend.strategy.request_host(), redirect_uri) backend.strategy.session_set( redirect_name, redirect_uri or backend.setting('LOGIN_REDIRECT_URL') ) return backend.start()
def test_multiple_hosts(self): allowed_hosts = ['myapp1.com', 'myapp2.com'] for host in allowed_hosts: url = 'http://{}/path/'.format(host) self.assertEqual(sanitize_redirect(allowed_hosts, url), url)
def test_wrong_path_redirect(self): expect(sanitize_redirect('myapp.com', 'http://notmyapp.com/path/')).to.equal(None)
def test_valid_relative_redirect(self): self.assertEqual(sanitize_redirect(['myapp.com'], '/path/'), '/path/')
def test_multiple_hosts_wrong_host(self): self.assertEqual( sanitize_redirect(['myapp1.com', 'myapp2.com'], 'http://notmyapp.com/path/'), None)
def test_dict_redirect(self): self.assertEqual(sanitize_redirect(['myapp.com'], {}), None)
def test_wrong_path_redirect(self): self.assertEqual( sanitize_redirect(['myapp.com'], 'http://notmyapp.com/path/'), None)
def test_empty_redirect(self): self.assertEqual(sanitize_redirect('myapp.com', ''), None)
def test_empty_redirect(self): expect(sanitize_redirect('myapp.com', '')).to.equal(None)
def do_complete(strategy, login, user=None, redirect_name='next', *args, **kwargs): # pop redirect value before the session is trashed on login() data = strategy.request_data() redirect_value = strategy.session_get(redirect_name, '') or \ data.get(redirect_name, '') is_authenticated = user_is_authenticated(user) user = is_authenticated and user or None default_redirect = strategy.setting('LOGIN_REDIRECT_URL') url = default_redirect login_error_url = strategy.setting('LOGIN_ERROR_URL') or \ strategy.setting('LOGIN_URL') partial = partial_pipeline_data(strategy, user, *args, **kwargs) if partial is not None: idx, backend, xargs, xkwargs = partial if backend == strategy.backend_name: user = strategy.continue_pipeline(pipeline_index=idx, *xargs, **xkwargs) else: strategy.clean_partial_pipeline() user = strategy.complete(user=user, request=strategy.request, *args, **kwargs) else: user = strategy.complete(user=user, request=strategy.request, *args, **kwargs) if user and not isinstance(user, strategy.storage.user.user_model()): return user if is_authenticated: if not user: url = redirect_value or default_redirect else: url = redirect_value or \ strategy.setting('NEW_ASSOCIATION_REDIRECT_URL') or \ default_redirect elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, 'is_new', False) social_user = user.social_user login(strategy, user) # store last login backend name in session strategy.session_set('social_auth_last_login_backend', social_user.provider) # Remove possible redirect URL from session, if this is a new # account, send him to the new-users-page if defined. new_user_redirect = strategy.setting('NEW_USER_REDIRECT_URL') if new_user_redirect and is_new: url = new_user_redirect else: url = redirect_value or default_redirect else: url = strategy.setting('INACTIVE_USER_URL', login_error_url) else: url = login_error_url if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ('?' in url and '&' or '?') + \ '{0}={1}'.format(redirect_name, redirect_value) if strategy.setting('SANITIZE_REDIRECTS', True): url = sanitize_redirect(strategy.request_host(), url) return strategy.redirect(url)
def test_none_redirect(self): self.assertEqual(sanitize_redirect('myapp.com', None), None)
def post(self, request, *args, **kwargs): # request.POST bodge # The backend tries to get data from either request.POST # or request.GET. These are empty though as DRF uses # request.DATA. We need to assing request.POST. request.POST = request.DATA serializer = self.get_serializer(data=request.DATA) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) backend = serializer.data['backend'] uri = reverse('auth:complete', args=(backend, )) strategy = load_strategy(request=request) try: backend = load_backend(strategy, backend, uri) except MissingBackend: raise Http404('Backend not found') data = backend.strategy.request_data() user = request.user is_authenticated = user_is_authenticated(user) user = is_authenticated and user or None partial = partial_pipeline_data(backend, user, *args, **kwargs) if partial: xargs, xkwargs = partial user = backend.continue_pipeline(*xargs, **xkwargs) else: user = backend.complete(user=user, *args, **kwargs) # pop redirect value before the session is trashed on login(), but after # the pipeline so that the pipeline can change the redirect if needed redirect_value = backend.strategy.session_get( REDIRECT_FIELD_NAME, '') or data.get(REDIRECT_FIELD_NAME, '') user_model = backend.strategy.storage.user.user_model() if user and not isinstance(user, user_model): return user if is_authenticated: if not user: url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, redirect_value, 'NEW_ASSOCIATION_REDIRECT_URL', 'LOGIN_REDIRECT_URL') elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, 'is_new', False) if is_new: url = setting_url(backend, 'NEW_USER_REDIRECT_URL', redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, 'INACTIVE_USER_URL', 'LOGIN_ERROR_URL', 'LOGIN_URL') return Response( { 'status': 'Unauthorized', 'message': 'The user account is disabled.', 'redirect_url': url }, status=status.HTTP_401_UNAUTHORIZED) else: url = setting_url(backend, 'LOGIN_ERROR_URL', 'LOGIN_URL') if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ('?' in url and '&' or '?') + '{0}={1}'.format( REDIRECT_FIELD_NAME, redirect_value) if backend.setting('SANITIZE_REDIRECTS', True): url = sanitize_redirect( backend.strategy.request_host(), url) or backend.setting('LOGIN_REDIRECT_URL') # Get the JWT payload for the user. payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) return Response({'token': token, 'redirect_url': url})
def test_valid_relative_redirect(self): expect(sanitize_redirect('myapp.com', '/path/')).to.equal('/path/')
def test_valid_absolute_redirect(self): expect(sanitize_redirect( 'myapp.com', 'http://myapp.com/path/')).to.equal('http://myapp.com/path/')
def test_wrong_path_redirect(self): expect(sanitize_redirect( 'myapp.com', 'http://notmyapp.com/path/' )).to.equal(None)
def test_dict_redirect(self): self.assertEqual(sanitize_redirect('myapp.com', {}), None)
def test_invalid_redirect(self): self.assertEqual(sanitize_redirect('myapp.com', {'foo': 'bar'}), None)
def test_empty_redirect(self): self.assertEqual(sanitize_redirect(['myapp.com'], ''), None)
def test_wrong_path_redirect(self): self.assertEqual( sanitize_redirect('myapp.com', 'http://notmyapp.com/path/'), None )
def test_invalid_redirect(self): self.assertEqual(sanitize_redirect(['myapp.com'], {'foo': 'bar'}), None)
def test_dict_redirect(self): expect(sanitize_redirect('myapp.com', {})).to.equal(None)
def test_valid_absolute_redirect(self): self.assertEqual( sanitize_redirect(['myapp.com'], 'http://myapp.com/path/'), 'http://myapp.com/path/')
def test_valid_relative_redirect(self): self.assertEqual(sanitize_redirect('myapp.com', '/path/'), '/path/')
def test_none_redirect(self): expect(sanitize_redirect('myapp.com', None)).to.equal(None)
def test_multiple_hosts_wrong_host(self): self.assertEqual(sanitize_redirect( ['myapp1.com', 'myapp2.com'], 'http://notmyapp.com/path/'), None)
def post(self, request, *args, **kwargs): # request.POST bodge # The backend tries to get data from either request.POST # or request.GET. These are empty though as DRF uses # request.DATA. We need to assing request.POST. request._request.POST = request._request.POST.copy() for key, value in request.data.items(): request._request.POST[key] = value serializer = self.get_serializer(data=request.data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) backend = serializer.data['backend'] uri = reverse('auth:complete', args=(backend,)) strategy = load_strategy(request=request._request) try: backend = load_backend(strategy, backend, uri) except MissingBackend: raise Http404('Backend not found') data = backend.strategy.request_data() user = request.user is_authenticated = user_is_authenticated(user) user = is_authenticated and user or None partial = partial_pipeline_data(backend, user, *args, **kwargs) if partial: xargs, xkwargs = partial user = backend.continue_pipeline(*xargs, **xkwargs) else: user = backend.complete(user=user, *args, **kwargs) # pop redirect value before the session is trashed on login(), but after # the pipeline so that the pipeline can change the redirect if needed redirect_value = backend.strategy.session_get(REDIRECT_FIELD_NAME, '') or data.get(REDIRECT_FIELD_NAME, '') user_model = backend.strategy.storage.user.user_model() if user and not isinstance(user, user_model): return user if is_authenticated: if not user: url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, redirect_value, 'NEW_ASSOCIATION_REDIRECT_URL', 'LOGIN_REDIRECT_URL') elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, 'is_new', False) if is_new: url = setting_url(backend, 'NEW_USER_REDIRECT_URL', redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, 'INACTIVE_USER_URL', 'LOGIN_ERROR_URL', 'LOGIN_URL') return Response({ 'status': 'Unauthorized', 'message': 'The user account is disabled.', 'redirect_url': url }, status=status.HTTP_401_UNAUTHORIZED) else: url = setting_url(backend, 'LOGIN_ERROR_URL', 'LOGIN_URL') if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ('?' in url and '&' or '?') + '{0}={1}'.format(REDIRECT_FIELD_NAME, redirect_value) if backend.setting('SANITIZE_REDIRECTS', True): url = sanitize_redirect(backend.strategy.request_host(), url) or backend.setting('LOGIN_REDIRECT_URL') # Get the JWT payload for the user. payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) return Response({ 'token': token, 'redirect_url': url })
def test_invalid_redirect(self): expect(sanitize_redirect('myapp.com', {'foo': 'bar'})).to.equal(None)
def do_complete(strategy, login, user=None, redirect_name="next", *args, **kwargs): # pop redirect value before the session is trashed on login() data = strategy.request_data() redirect_value = strategy.session_get(redirect_name, "") or data.get(redirect_name, "") is_authenticated = user_is_authenticated(user) user = is_authenticated and user or None partial = partial_pipeline_data(strategy, user, *args, **kwargs) if partial: xargs, xkwargs = partial user = strategy.continue_pipeline(*xargs, **xkwargs) else: user = strategy.complete(user=user, request=strategy.request, *args, **kwargs) try: is_api_call = strategy.request.COOKIES.get("is_api_call") except: try: is_api_call = strategy.session_get("is_api_call") except: is_api_call = None if user and not isinstance(user, strategy.storage.user.user_model()): return user if is_authenticated: if not user: url = setting_url(strategy, redirect_value, "LOGIN_REDIRECT_URL") else: url = setting_url(strategy, redirect_value, "NEW_ASSOCIATION_REDIRECT_URL", "LOGIN_REDIRECT_URL") if is_api_call is not None: url = "/api/login/social/success/" elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, "is_new", False) social_user = user.social_user login(strategy, user) # store last login backend name in session strategy.session_set("social_auth_last_login_backend", social_user.provider) if is_new: url = setting_url(strategy, redirect_value, "NEW_USER_REDIRECT_URL", "LOGIN_REDIRECT_URL") else: url = setting_url(strategy, redirect_value, "LOGIN_REDIRECT_URL") if is_api_call is not None: url = "/api/login/social/success/" else: url = setting_url(strategy, "INACTIVE_USER_URL", "LOGIN_ERROR_URL", "LOGIN_URL") if strategy.setting("INACTIVE_USER_REDIRECT_WITH_ID") is True: url += "?user_id=" + str(user.id) if is_api_call is not None: url = "/api/login/social/fail/" url += "?user_id=" + str(user.id) + "&reason=user_already_exist" else: url = setting_url(strategy, "LOGIN_ERROR_URL", "LOGIN_URL") if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ("?" in url and "&" or "?") + "{0}={1}".format(redirect_name, redirect_value) if strategy.setting("SANITIZE_REDIRECTS", True): url = sanitize_redirect(strategy.request_host(), url) or strategy.setting("LOGIN_REDIRECT_URL") return strategy.redirect(url)
def test_valid_absolute_redirect(self): expect(sanitize_redirect( 'myapp.com', 'http://myapp.com/path/' )).to.equal('http://myapp.com/path/')
def do_complete(backend, login, user=None, redirect_name='next', *args, **kwargs): data = backend.strategy.request_data() is_authenticated = user_is_authenticated(user) user = is_authenticated and user or None partial = partial_pipeline_data(backend, user, *args, **kwargs) if partial: xargs, xkwargs = partial user = backend.continue_pipeline(*xargs, **xkwargs) else: user = backend.complete(user=user, *args, **kwargs) # pop redirect value before the session is trashed on login(), but after # the pipeline so that the pipeline can change the redirect if needed redirect_value = backend.strategy.session_get(redirect_name, '') or \ data.get(redirect_name, '') user_model = backend.strategy.storage.user.user_model() if user and not isinstance(user, user_model): return user if is_authenticated: if not user: url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, redirect_value, 'NEW_ASSOCIATION_REDIRECT_URL', 'LOGIN_REDIRECT_URL') elif user: if user_is_active(user): # catch is_new/social_user in case login() resets the instance is_new = getattr(user, 'is_new', False) social_user = user.social_user login(backend, user, social_user) # store last login backend name in session backend.strategy.session_set('social_auth_last_login_backend', social_user.provider) if is_new: url = setting_url(backend, 'NEW_USER_REDIRECT_URL', redirect_value, 'LOGIN_REDIRECT_URL') else: url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') else: if backend.setting('INACTIVE_USER_LOGIN', False): social_user = user.social_user login(backend, user, social_user) url = setting_url(backend, 'INACTIVE_USER_URL', 'LOGIN_ERROR_URL', 'LOGIN_URL') else: url = setting_url(backend, 'LOGIN_ERROR_URL', 'LOGIN_URL') if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ('?' in url and '&' or '?') + \ '{0}={1}'.format(redirect_name, redirect_value) if backend.setting('SANITIZE_REDIRECTS', True): allowed_hosts = backend.setting('ALLOWED_REDIRECT_HOSTS', []) + \ [backend.strategy.request_host()] url = sanitize_redirect(allowed_hosts, url) or \ backend.setting('LOGIN_REDIRECT_URL') return backend.strategy.redirect(url)
def test_valid_absolute_redirect(self): self.assertEqual( sanitize_redirect('myapp.com', 'http://myapp.com/path/'), 'http://myapp.com/path/' )