mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-02-04 08:13:38 +00:00
Closes: #2178. - Don't bother with the redirection to the next page using the ?next= URL parameter. Always redirect to the home (index) page. - Show a message that logout was successful. - Ensure that SSO cookie is removed. Tests: - Logout and notice that redirection has been performed to the home page. - "Logged out successfully." message is shown. - When logged as a user with a language set, logging out preserves the language of the user who was just logged out. - Login. Click logout while having browser developer tool open. Notice that Logout request has SSO cookie. The response does not have the cookie set. The next request is to the home page and it does not have SSO cookie in the request. - Login to tt-rss app that needs SSO to work. Logout from FreedomBox interface using another page. Refresh the tt-rss page and notice that user was logged out and redirect to FreedomBox login page. - Logout. Again, manually visit the URL https://10.42.0.203/plinth/accounts/logout/. The page is still required to home page and success is still shown even though the user is already logged out. - Repeat the logout test as non-admin user. Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
113 lines
3.7 KiB
Python
113 lines
3.7 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""
|
|
Views for the Single Sign On app of FreedomBox.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import urllib
|
|
|
|
import axes.utils
|
|
from axes.decorators import axes_form_invalid
|
|
from django import shortcuts
|
|
from django.contrib import messages
|
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
|
from django.contrib.auth import logout as auth_logout
|
|
from django.contrib.auth.views import LoginView
|
|
from django.http import HttpResponseRedirect
|
|
from django.utils.translation import gettext as _
|
|
|
|
from plinth import actions, translation, utils, web_framework
|
|
|
|
from .forms import AuthenticationForm, CaptchaAuthenticationForm
|
|
|
|
PRIVATE_KEY_FILE_NAME = 'privkey.pem'
|
|
SSO_COOKIE_NAME = 'auth_pubtkt'
|
|
KEYS_DIRECTORY = '/etc/apache2/auth-pubtkt-keys'
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def set_ticket_cookie(user, response):
|
|
"""Generate and set a mod_auth_pubtkt as a cookie in the provided
|
|
response.
|
|
"""
|
|
tokens = list(map(lambda g: g.name, user.groups.all()))
|
|
private_key_file = os.path.join(KEYS_DIRECTORY, PRIVATE_KEY_FILE_NAME)
|
|
ticket = actions.superuser_run('auth-pubtkt', [
|
|
'generate-ticket', '--uid', user.username, '--private-key-file',
|
|
private_key_file, '--tokens', ','.join(tokens)
|
|
])
|
|
response.set_cookie(SSO_COOKIE_NAME, urllib.parse.quote(ticket))
|
|
return response
|
|
|
|
|
|
class SSOLoginView(LoginView):
|
|
"""View to login to FreedomBox and set a auth_pubtkt cookie.
|
|
|
|
Cookie will be used to provide Single Sign On for some other applications.
|
|
|
|
"""
|
|
redirect_authenticated_user = True
|
|
template_name = 'login.html'
|
|
form_class = AuthenticationForm
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
response = super(SSOLoginView, self).dispatch(request, *args, **kwargs)
|
|
if request.user.is_authenticated:
|
|
translation.set_language(request, response,
|
|
request.user.userprofile.language)
|
|
return set_ticket_cookie(request.user, response)
|
|
|
|
return response
|
|
|
|
# XXX: Use axes middleware and authentication backend instead of
|
|
# axes_form_invalid when axes >= 5.0.0 becomes available in Debian stable.
|
|
@axes_form_invalid
|
|
def form_invalid(self, *args, **kwargs):
|
|
return super(SSOLoginView, self).form_invalid(*args, **kwargs)
|
|
|
|
|
|
class CaptchaLoginView(LoginView):
|
|
redirect_authenticated_user = True
|
|
template_name = 'login.html'
|
|
form_class = CaptchaAuthenticationForm
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
response = super(CaptchaLoginView,
|
|
self).dispatch(request, *args, **kwargs)
|
|
if not request.POST:
|
|
return response
|
|
|
|
if not request.user.is_authenticated:
|
|
return response
|
|
|
|
# Successful authentication
|
|
if utils.is_axes_old():
|
|
ip_address = web_framework.get_ip_address_from_request(request)
|
|
axes.utils.reset(ip=ip_address)
|
|
logger.info(
|
|
'Login attempts reset for IP after successful login: %s',
|
|
ip_address)
|
|
|
|
return set_ticket_cookie(request.user, response)
|
|
|
|
|
|
def logout(request):
|
|
"""Logout an authenticated user, remove SSO cookie and redirect to home."""
|
|
auth_logout(request)
|
|
response = shortcuts.redirect('index')
|
|
response.delete_cookie(SSO_COOKIE_NAME)
|
|
messages.success(request, _('Logged out successfully.'))
|
|
return response
|
|
|
|
|
|
def refresh(request):
|
|
"""Simulate cookie refresh - redirect logged in user with a new cookie"""
|
|
redirect_url = request.GET.get(REDIRECT_FIELD_NAME, '')
|
|
response = HttpResponseRedirect(redirect_url)
|
|
response.delete_cookie(SSO_COOKIE_NAME)
|
|
# Redirect with cookie doesn't work with 300 series
|
|
response.status_code = 200
|
|
return set_ticket_cookie(request.user, response)
|