def get_login_providers(request, short=False): """ Returns a list of available login providers based on the AUTHENTICATION_BACKENDS setting. Each provider is represented as a dictionary containing the backend name, name of required parameter if required and its verbose name. """ def extract_backend_data(klass): """ Helper function which extracts information useful for use in templates from SocialAuth subclasses and returns it as a dictionary. """ return { 'name': klass.name, 'required_field': klass.REQUIRED_FIELD_NAME, 'required_field_verbose': klass.REQUIRED_FIELD_VERBOSE_NAME, } backends = (module_member(auth_backend) for auth_backend in setting('AUTHENTICATION_BACKENDS')) providers = [ extract_backend_data(backend) for backend in backends if issubclass(backend, BaseAuth) ] if short: return providers[:setting('AUTHENTICATION_PROVIDERS_BRIEF', DEFAULT_AUTHENTICATION_PROVIDERS_BRIEF)] return providers
def get_login_providers(request, short=False): """ Returns a list of available login providers based on the AUTHENTICATION_BACKENDS setting. Each provider is represented as a dictionary containing the backend name, name of required parameter if required and its verbose name. """ def extract_backend_data(klass): """ Helper function which extracts information useful for use in templates from SocialAuth subclasses and returns it as a dictionary. """ return { 'name': klass.name, 'required_field': klass.REQUIRED_FIELD_NAME, 'required_field_verbose': klass.REQUIRED_FIELD_VERBOSE_NAME, } backends = (module_member(auth_backend) for auth_backend in setting('AUTHENTICATION_BACKENDS')) providers = [extract_backend_data(backend) for backend in backends if issubclass(backend, BaseAuth)] if short: return providers[:setting('AUTHENTICATION_PROVIDERS_BRIEF', DEFAULT_AUTHENTICATION_PROVIDERS_BRIEF)] return providers
def login(request): # TODO: Remove this in favor of redirect_authenticated_user once we # drop support for Django<1.10. if request.user.is_authenticated(): next_page = request.GET.get('next', request.POST.get('next', '')) if not is_safe_url(url=next_page, host=request.get_host()): next_page = resolve_url(setting('LOGIN_REDIRECT_URL')) return HttpResponseRedirect(next_page) return auth_login(request, template_name='ksp_login/login.html', extra_context=login_providers(request))
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 register(request, creation_form=KspUserCreationForm): """ As the name suggests, registers a new user. Can replace the create_user function in the SOCIAL_AUTH pipeline (through ksp_login.pipeline.register_user, with the corresponding save_status_to_session, of course) to make it possible for the user to pick a username. Also presents additional app-specific forms listed in the KSP_LOGIN_PROFILE_FORMS setting to the user. """ if request.user.is_authenticated(): return redirect('account_settings') try: pipeline_state = request.session[setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', SOCIAL_AUTH_PARTIAL_PIPELINE_KEY)] backend = pipeline_state['backend'] pipeline_state = pipeline_state['kwargs'] standalone = False except KeyError: standalone = True form_classes = [creation_form] + get_profile_forms() if request.method == "POST": forms = [form(request.POST, request=request) for form in form_classes] if all(form.is_valid() for form in forms): user = forms[0].save() for form in forms[1:]: form.set_user(user) form.save() if standalone: return redirect('account_login') pipeline_state['user'] = user.id # This ensures the top-level session dict changes, otherwise # our changes in pipeline_state might not get stored. request.session.setdefault('ksp_login_dummy_key', 0) request.session['ksp_login_dummy_key'] += 1 return redirect('social:complete', backend=backend) else: forms = [form(request=request) for form in form_classes] return render(request, "ksp_login/registration.html", { 'forms': forms, })
def register(request, creation_form=KspUserCreationForm): """ As the name suggests, registers a new user. Can replace the create_user function in the SOCIAL_AUTH pipeline (through ksp_login.pipeline.register_user, with the corresponding save_status_to_session, of course) to make it possible for the user to pick a username. Also presents additional app-specific forms listed in the KSP_LOGIN_PROFILE_FORMS setting to the user. """ if request.user.is_authenticated(): return redirect('account_settings') try: pipeline_state = request.session[setting( 'SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', SOCIAL_AUTH_PARTIAL_PIPELINE_KEY)] backend = pipeline_state['backend'] pipeline_state = pipeline_state['kwargs'] standalone = False except KeyError: standalone = True form_classes = [creation_form] + get_profile_forms() if request.method == "POST": forms = [form(request.POST, request=request) for form in form_classes] if all(form.is_valid() for form in forms): user = forms[0].save() for form in forms[1:]: form.set_user(user) form.save() if standalone: return redirect('account_login') pipeline_state['user'] = user.id # This ensures the top-level session dict changes, otherwise # our changes in pipeline_state might not get stored. request.session.setdefault('ksp_login_dummy_key', 0) request.session['ksp_login_dummy_key'] += 1 return redirect('social:complete', backend=backend) else: forms = [form(request=request) for form in form_classes] return render(request, "ksp_login/registration.html", { 'forms': forms, })
def __init__(self, *args, **kwargs): """ If the user is registering via an external service, this gathers initial data from the service and marks the password fields as optional, otherwise it just sets the help_text of the first password field. """ try: request = kwargs['request'] del kwargs['request'] except KeyError: raise TypeError("Argument 'request' missing.") try: pipeline_state = request.session[setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', SOCIAL_AUTH_PARTIAL_PIPELINE_KEY)] pipeline_state = pipeline_state['kwargs'] self.password_required = False except KeyError: self.password_required = True pipeline_state = None if not args and 'initial' not in kwargs: kwargs['initial'] = self.get_initial_from_pipeline(pipeline_state) super(KspUserCreationForm, self).__init__(*args, **kwargs) self.fields['password1'].help_text = _( "We recommend choosing a strong passphrase but we don't " "enforce any ridiculous constraints on your passwords." ) if not self.password_required: self.fields['password1'].required = False self.fields['password2'].required = False self.fields['password1'].help_text = string_concat(_( "Since you're logging in using an external provider, " "this field is optional; however, by supplying it, you " "will be able to log in using a password. " ), self.fields['password1'].help_text)
from django.contrib.auth import login, REDIRECT_FIELD_NAME, BACKEND_SESSION_KEY from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views.decorators.http import require_POST from social.actions import do_auth, do_complete, do_disconnect from social.apps.django_app.utils import strategy, setting, BackendWrapper DEFAULT_REDIRECT = setting('LOGIN_REDIRECT_URL') LOGIN_ERROR_URL = setting('LOGIN_ERROR_URL', setting('LOGIN_URL')) @strategy('social:complete') def auth(request, backend): return do_auth(request.strategy, redirect_name=REDIRECT_FIELD_NAME) @csrf_exempt @strategy('social:complete') def complete(request, backend, *args, **kwargs): """Authentication complete view, override this view if transaction management doesn't suit your needs.""" return do_complete(request.strategy, _do_login, request.user, redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs) @login_required
def get_profile_forms(): form_names = setting('KSP_LOGIN_PROFILE_FORMS', []) return [import_string(name) for name in form_names]
from django.contrib.auth import login, REDIRECT_FIELD_NAME, BACKEND_SESSION_KEY from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views.decorators.http import require_POST from social.apps.actions import do_auth, do_complete, do_disconnect from social.apps.django_app.utils import strategy, setting, BackendWrapper DEFAULT_REDIRECT = setting('LOGIN_REDIRECT_URL') LOGIN_ERROR_URL = setting('LOGIN_ERROR_URL', setting('LOGIN_URL')) @strategy('social:complete') def auth(request, backend): return do_auth(request.strategy, redirect_name=REDIRECT_FIELD_NAME) @csrf_exempt @strategy('social:complete') def complete(request, backend, *args, **kwargs): """Authentication complete view, override this view if transaction management doesn't suit your needs.""" return do_complete(request.strategy, _do_login, request.user, redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs) @login_required @strategy() @require_POST @csrf_protect
def complete(request, backend, *args, **kwargs): """Authentication complete view, override this view if transaction management doesn't suit your needs.""" strategy = request.strategy # pop redirect value before the session is trashed on login() redirect_value = request.session.get(REDIRECT_FIELD_NAME, '') or \ request.REQUEST.get(REDIRECT_FIELD_NAME, '') is_authenticated = user_is_authenticated(request.user) user = is_authenticated and request.user or None url = DEFAULT_REDIRECT if request.session.get('partial_pipeline'): data = request.session.pop('partial_pipeline') kwargs = kwargs.copy() kwargs.setdefault('user', user) idx, xargs, xkwargs = strategy.from_session(data, request=request, *args, **kwargs) if xkwargs.get('backend', '') == backend: user = strategy.continue_pipeline(pipeline_index=idx, *xargs, **xkwargs) else: strategy.clean_partial_pipeline() user = strategy.complete(user=user, request=request, *args, **kwargs) else: user = strategy.complete(user=user, request=request, *args, **kwargs) if isinstance(user, HttpResponse): 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 flag before login() resets the instance is_new = getattr(user, 'is_new', False) login(request, user) # Hack django.auth backend loading since they create an instance # that won't know about the strategy/storage layout being used request.session['original_' + BACKEND_SESSION_KEY] = \ request.session[BACKEND_SESSION_KEY] request.session[BACKEND_SESSION_KEY] = '%s.%s' % ( BackendWrapper.__module__, BackendWrapper.__name__ ) # user.social_user is the used UserSocialAuth instance defined # in authenticate process social_user = user.social_user if setting('SESSION_EXPIRATION', True): # Set session expiration date if present and not disabled # by setting. Use last social-auth instance for current # provider, users can associate several accounts with # a same provider. expiration = social_user.expiration_datetime() if expiration: try: request.session.set_expiry(expiration) except OverflowError: # Handle django time zone overflow request.session.set_expiry(None) # store last login backend name in session request.session['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 strategy.setting('LOGIN_REDIRECT_URL') else: url = strategy.setting('INACTIVE_USER_URL', LOGIN_ERROR_URL) else: url = strategy.setting('LOGIN_ERROR_URL', LOGIN_ERROR_URL) if redirect_value and redirect_value != url: redirect_value = quote(redirect_value) url += ('?' in url and '&' or '?') + \ '%s=%s' % (REDIRECT_FIELD_NAME, redirect_value) return HttpResponseRedirect(url)