This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/passbook/core/views/authentication.py

102 lines
3.8 KiB
Python
Raw Normal View History

2018-11-11 12:41:48 +00:00
"""Core views"""
from logging import getLogger
from typing import Dict
from django.contrib import messages
2018-11-23 08:44:30 +00:00
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
2018-11-11 12:41:48 +00:00
from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect, reverse
2018-11-11 12:41:48 +00:00
from django.utils.translation import ugettext as _
2018-11-23 08:44:30 +00:00
from django.views import View
2018-11-11 12:41:48 +00:00
from django.views.generic import FormView
from passbook.core.forms.authentication import LoginForm
from passbook.core.models import User
from passbook.lib.config import CONFIG
LOGGER = getLogger(__name__)
class LoginView(UserPassesTestMixin, FormView):
"""Allow users to sign in"""
template_name = 'login/form.html'
form_class = LoginForm
success_url = '.'
# Allow only not authenticated users to login
def test_func(self):
return not self.request.user.is_authenticated
def get_context_data(self, **kwargs):
kwargs['config'] = CONFIG.get('passbook')
kwargs['is_login'] = True
return super().get_context_data(**kwargs)
def get_user(self, uid_value) -> User:
"""Find user instance. Returns None if no user was found."""
for search_field in CONFIG.y('passbook.uid_fields'):
users = User.objects.filter(**{search_field: uid_value})
if users.exists():
return users.first()
return None
def form_valid(self, form: LoginForm) -> HttpResponse:
"""Form data is valid"""
pre_user = self.get_user(form.cleaned_data.get('uid_field'))
if not pre_user:
# No user found
2018-11-23 08:44:30 +00:00
return self.invalid_login(self.request)
2018-11-11 12:41:48 +00:00
user = authenticate(
email=pre_user.email,
username=pre_user.username,
password=form.cleaned_data.get('password'),
request=self.request)
if user:
# User authenticated successfully
2018-11-23 08:44:30 +00:00
return self.login(self.request, user, form.cleaned_data)
2018-11-11 12:41:48 +00:00
# User was found but couldn't authenticate
2018-11-23 08:44:30 +00:00
return self.invalid_login(self.request, disabled_user=pre_user)
2018-11-11 12:41:48 +00:00
2018-11-23 08:44:30 +00:00
def login(self, request: HttpRequest, user: User, cleaned_data: Dict) -> HttpResponse:
2018-11-11 12:41:48 +00:00
"""Handle actual login
Actually logs user in, sets session expiry and redirects to ?next parameter
Args:
request: The current request
user: The user to be logged in.
Returns:
Either redirect to ?next or if not present to overview
"""
if user is None:
raise ValueError("User cannot be None")
login(request, user)
if cleaned_data.get('remember') is True:
2018-11-16 10:41:14 +00:00
request.session.set_expiry(CONFIG.y('passbook.session.remember_age'))
2018-11-11 12:41:48 +00:00
else:
request.session.set_expiry(0) # Expires when browser is closed
messages.success(request, _("Successfully logged in!"))
LOGGER.debug("Successfully logged in %s", user.username)
# Check if there is a next GET parameter and redirect to that
if 'next' in request.GET:
return redirect(request.GET.get('next'))
# Otherwise just index
2018-11-16 08:10:35 +00:00
return redirect(reverse('passbook_core:overview'))
2018-11-11 12:41:48 +00:00
2018-11-23 08:44:30 +00:00
def invalid_login(self, request: HttpRequest, disabled_user: User = None) -> HttpResponse:
2018-11-11 12:41:48 +00:00
"""Handle login for disabled users/invalid login attempts"""
2018-11-23 08:44:30 +00:00
messages.error(request, _('Failed to authenticate.'))
return self.render_to_response(self.get_context_data())
class LogoutView(LoginRequiredMixin, View):
"""Log current user out"""
def dispatch(self, request):
"""Log current user out"""
logout(request)
messages.success(request, _("You've successfully been logged out."))
return redirect(reverse('passbook_core:auth-login'))