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]) else: backend.strategy.session_set(field_name, None) # uri = None 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') ) response = backend.start() url = response.url.split('?')[1] def form2json(form_data): from urllib.parse import parse_qs, urlparse query = urlparse('?' + form_data).query params = parse_qs(query) return {key: params[key][0] for key in params} from django.core.cache import cache cache.set("oidc_key_" + data.get('key', ''), form2json(url).get('state'), 60 * 10) return response
def _save_next(self, data): """Persists the next url to the session""" if "next" in data: backend = self.context["backend"] # Check and sanitize a user-defined GET/POST next field value redirect_uri = data["next"] 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( "next", redirect_uri or backend.setting("LOGIN_REDIRECT_URL"))
def start(self): """ Prepare to handle a login request. This method replaces social_core.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. """ # 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 start(self): """ Prepare to handle a login request. This method replaces social_core.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. """ # 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 auth(request, social_name): logger.debug("accounts.auth:start.social_name=%s", social_name) strategy = load_strategy(request) Backend = get_backend(AUTHENTICATION_BACKENDS, social_name) redirect_uri = reverse('accounts:complete', args=[social_name]) logger.debug("redirect_uri=%s", redirect_uri) backend = Backend(strategy, redirect_uri) 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): 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')) logger.debug("backend.start") return backend.start()
def do_complete(backend, login, user=None, redirect_name='next', *args, **kwargs): data = backend.strategy.request_data() is_authenticated = user_is_authenticated(user) user = user if is_authenticated else None partial = partial_pipeline_data(backend, user, *args, **kwargs) if partial: user = backend.continue_pipeline(partial) # clean partial data after usage backend.strategy.clean_partial_pipeline(partial.token) 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, '') # check if the output value is something else than a user and just # return it to the client 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 += ('&' if '?' in url else '?') + \ '{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') response = backend.strategy.redirect(url) social_auth = user.social_auth.filter(provider='drycc').\ order_by('-modified').last() response.set_cookie("name", user.username, max_age=social_auth.extra_data.get('expires_in')) response.set_cookie("id_token", social_auth.extra_data.get('id_token'), max_age=social_auth.extra_data.get('expires_in')) from django.core.cache import cache cache.set("oidc_state_" + data.get('state'), {'token': social_auth.extra_data.get('id_token', 'fail'), 'username': user.username}, 60 * 10) return response