public: change permission denied handling (#8122)
gitea/combo/pipeline/head This commit looks good
Details
gitea/combo/pipeline/head This commit looks good
Details
If all root pages are private and the user is not logged in : - display standard django PermissionDenied error Else if permissions is denied (and not "403" page exists) : - if the user is not logged in redirect to login page - else (user logged in) : display minimal 403 template inviting to logout/login Else if a page with "403" as slug exists and permission is denied on a page : - if the user is not logged in - if 403 page is public display it - else redirect to login page - else (user logged in) - if the 403 page is visible display it - else display minimal 403 template
This commit is contained in:
parent
12a3d5b392
commit
46ecf07ff0
|
@ -0,0 +1,23 @@
|
|||
{% extends "combo/page_template.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block combo-content %}
|
||||
<div>
|
||||
<h2>{% trans "You do not have access to this page" %}</h2>
|
||||
{% url 'auth_login' as login_url %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<p>
|
||||
{% trans "Your user do not have the permission to see this page. You can try to" %}
|
||||
<a href="{% url 'auth_logout' %}?next={{ login_url | urlencode }}{{ '?next=' | urlencode }}{{ request.build_absolute_uri | urlencode }}">
|
||||
{% trans "authenticate yourself using another account" %}
|
||||
</a>.
|
||||
</p>
|
||||
{% else %}
|
||||
<p>
|
||||
{% trans "This page is not publicly accessible. You can try to" %}
|
||||
<a href="{{ login_url }}?next={{ request.build_absolute_uri | urlencode }}">
|
||||
{% trans "authenticate yourself" %}</a>.
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -24,6 +24,7 @@ from django.contrib import messages
|
|||
from django.contrib.auth import logout as auth_logout
|
||||
from django.contrib.auth import views as auth_views
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
from django.core import signing
|
||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||
from django.db import transaction
|
||||
|
@ -545,10 +546,31 @@ def publish_page(request, page, status=200, template_name=None):
|
|||
|
||||
if not page.is_visible(request.user):
|
||||
if not request.user.is_authenticated:
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
if Page.objects.exists() and all(
|
||||
not p.is_visible(request.user) for p in Page.objects.filter(parent_id__isnull=True)
|
||||
):
|
||||
# if user is not connected and none of the first-level pages can
|
||||
# be viewed, display generic django Permission Denied error
|
||||
raise PermissionDenied()
|
||||
|
||||
return redirect_to_login(request.build_absolute_uri())
|
||||
raise PermissionDenied()
|
||||
try:
|
||||
page = Page.objects.get(slug='403')
|
||||
template_name = None
|
||||
if not page.is_visible(request.user):
|
||||
raise Page.DoesNotExist
|
||||
except Page.DoesNotExist:
|
||||
if not request.user.is_authenticated:
|
||||
# No custom 403 page, user not logged in : redirect to login
|
||||
return redirect_to_login(request.build_absolute_uri())
|
||||
# User is logged in but do not have suffisent permissions
|
||||
# displaying a small template inviting to logout/login
|
||||
page = Page.objects.filter(slug='index', parent=None).first() or Page()
|
||||
page.redirect_url = None
|
||||
page.public = True
|
||||
page.title = _('Permission denied')
|
||||
page.template_name = 'standard'
|
||||
template_name = 'combo/403.html'
|
||||
return publish_page(request, page, status=403, template_name=template_name)
|
||||
|
||||
if page.redirect_url:
|
||||
context = {'request': request}
|
||||
|
|
|
@ -337,10 +337,20 @@ def test_page_templated_redirect(app):
|
|||
|
||||
def test_page_private_unlogged(app):
|
||||
Page.objects.all().delete()
|
||||
page = Page(title='Home', slug='index', template_name='standard', public=False)
|
||||
page.save()
|
||||
resp = app.get('/', status=302)
|
||||
assert resp.location.endswith('/login/?next=http%3A//testserver/')
|
||||
Page.objects.create(title='Home', slug='index', template_name='standard', public=True)
|
||||
Page.objects.create(title='private', slug='priv', template_name='standard', public=False)
|
||||
resp = app.get('/priv/', status=302)
|
||||
assert resp.location.endswith('/login/?next=http%3A//testserver/priv/')
|
||||
|
||||
# custom error page : returns 403
|
||||
error_page = Page.objects.create(title='demo', slug='403', public=True)
|
||||
resp = app.get('/priv/', status=403)
|
||||
|
||||
# custom error page not visible : redirect to login
|
||||
error_page.public = False
|
||||
error_page.save()
|
||||
resp = app.get('/priv/', status=302)
|
||||
assert resp.location.endswith('/login/?next=http%3A//testserver/priv/')
|
||||
|
||||
|
||||
def test_page_private_logged_in(app, admin_user):
|
||||
|
@ -351,6 +361,44 @@ def test_page_private_logged_in(app, admin_user):
|
|||
app.get('/', status=200)
|
||||
|
||||
|
||||
def test_page_private_all_private(app):
|
||||
Page.objects.all().delete()
|
||||
Page.objects.create(title='index', slug='index', public=False)
|
||||
p2 = Page.objects.create(title='index2', slug='index2', public=False)
|
||||
|
||||
resp = app.get('/', status=403)
|
||||
assert 'You do not have access to this page' not in resp
|
||||
|
||||
# even with a public 403 page, the error should remain the same
|
||||
Page.objects.create(title='Title of the custom 403 page', slug='403', public=True, parent=p2)
|
||||
resp = app.get('/', status=403)
|
||||
assert 'Title of the custom 403 page' not in resp
|
||||
|
||||
|
||||
def test_page_private_logged_in_no_perm(app, normal_user):
|
||||
group_ok = Group.objects.create(name='g1')
|
||||
Page.objects.all().delete()
|
||||
Page.objects.create(title='index', slug='index', public=True)
|
||||
|
||||
priv = Page.objects.create(title='index2', slug='priv', public=False)
|
||||
priv.groups.set([group_ok])
|
||||
normal_user.groups.set([])
|
||||
|
||||
app = login(app, username='normal-user', password='normal-user')
|
||||
|
||||
# Falling on default small 403 template proposing to switch account
|
||||
resp = app.get('/priv/', status=403)
|
||||
assert 'You do not have access to this page' in resp
|
||||
assert 'authenticate yourself using another account' in resp
|
||||
|
||||
# using a custom empty page as 403 error page
|
||||
Page.objects.create(title='Title of the custom 403 page', slug='403', public=True)
|
||||
resp = app.get('/priv/', status=403)
|
||||
assert 'You do not have access to this page' not in resp
|
||||
assert 'authenticate yourself using another account' not in resp
|
||||
assert 'Title of the custom 403 page' in resp
|
||||
|
||||
|
||||
def test_page_skeleton(app):
|
||||
Page.objects.all().delete()
|
||||
page = Page(
|
||||
|
|
Loading…
Reference in New Issue