flows: cleanup denied view, use everywhere

This commit is contained in:
Jens Langhammer 2020-07-02 13:48:42 +02:00
parent 76e2ba4764
commit bead19c64c
9 changed files with 79 additions and 32 deletions

View File

@ -22,8 +22,7 @@
<div class="pf-c-login__container">
<header class="pf-c-login__header">
<img class="pf-c-brand" src="{% static 'passbook/logo.svg' %}" style="height: 60px;" alt="passbook icon" />
<img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" style="height: 60px;"
alt="passbook branding" />
<img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" style="height: 60px;" alt="passbook branding" />
</header>
<main class="pf-c-login__main" id="flow-body">
<header class="pf-c-login__main-header">
@ -50,7 +49,7 @@
<li>
<a href="https://passbook.beryju.org/">{% trans 'Documentation' %}</a>
</li>
<!-- todo: load config.passbook.footer.links -->
<!-- TODO:load config.passbook.footer.links -->
</ul>
</footer>
</div>

View File

@ -1,21 +1,62 @@
{% extends 'login/base.html' %}
{% extends 'base/skeleton.html' %}
{% load static %}
{% load i18n %}
{% load passbook_utils %}
{% block card %}
<form method="POST" class="pf-c-form">
{% csrf_token %}
{% include 'partials/form.html' %}
<div class="pf-c-form__group">
<p>
<i class="pf-icon pf-icon-error-circle-o"></i>
{% trans 'Access denied' %}
</p>
{% block body %}
<div class="pf-c-background-image">
<svg xmlns="http://www.w3.org/2000/svg" class="pf-c-background-image__filter" width="0" height="0">
<filter id="image_overlay">
<feColorMatrix type="matrix" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0"></feColorMatrix>
<feComponentTransfer color-interpolation-filters="sRGB" result="duotone">
<feFuncR type="table" tableValues="0.086274509803922 0.43921568627451"></feFuncR>
<feFuncG type="table" tableValues="0.086274509803922 0.43921568627451"></feFuncG>
<feFuncB type="table" tableValues="0.086274509803922 0.43921568627451"></feFuncB>
<feFuncA type="table" tableValues="0 1"></feFuncA>
</feComponentTransfer>
</filter>
</svg>
</div>
<div class="pf-c-login">
<div class="pf-c-login__container">
<header class="pf-c-login__header">
<img class="pf-c-brand" src="{% static 'passbook/logo.svg' %}" style="height: 60px;" alt="passbook icon" />
<img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" style="height: 60px;" alt="passbook branding" />
</header>
<main class="pf-c-login__main" id="flow-body">
<header class="pf-c-login__main-header">
<h1 class="pf-c-title pf-m-3xl">
{% trans 'Permission denied' %}
</h1>
</header>
<div class="pf-c-login__main-body">
{% block card %}
<form method="POST" class="pf-c-form">
{% csrf_token %}
{% include 'partials/form.html' %}
<div class="pf-c-form__group">
<p>
<i class="pf-icon pf-icon-error-circle-o"></i>
{% trans 'Access denied' %}
</p>
</div>
{% if 'back' in request.GET %}
<a href="{% back %}" class="btn btn-primary btn-block btn-lg">{% trans 'Back' %}</a>
{% endif %}
</form>
{% endblock %}
</div>
</main>
<footer class="pf-c-login__footer">
<p></p>
<ul class="pf-c-list pf-m-inline">
<li>
<a href="https://passbook.beryju.org/">{% trans 'Documentation' %}</a>
</li>
<!-- TODO: load config.passbook.footer.links -->
</ul>
</footer>
</div>
{% if 'back' in request.GET %}
<a href="{% back %}" class="btn btn-primary btn-block btn-lg">{% trans 'Back' %}</a>
{% endif %}
</form>
</div>
{% endblock %}

View File

@ -50,7 +50,7 @@
<div class="pf-c-empty-state__body">
{% trans "Either no applications are defined, or you don't have access to any." %}
</div>
{% if user.is_superuser %} {# todo: use guardian permissions instead #}
{% if user.is_superuser %} {# TODO:use guardian permissions instead #}
<a href="{% url 'passbook_admin:application-create' %}" class="pf-c-button pf-m-primary" type="button">
{% trans 'Create Application' %}
</a>

View File

@ -59,7 +59,7 @@
<li>
<a href="https://passbook.beryju.org/">{% trans 'Documentation' %}</a>
</li>
<!-- todo: load config.passbook.footer.links -->
<!-- TODO:load config.passbook.footer.links -->
</ul>
</footer>
</div>

View File

@ -2,7 +2,9 @@
from typing import Optional
from django.contrib import messages
from django.http import HttpRequest
from django.contrib.auth.mixins import AccessMixin
from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect
from django.utils.translation import gettext as _
from structlog import get_logger
@ -19,10 +21,14 @@ class BaseMixin:
request: HttpRequest
class PolicyAccessMixin(BaseMixin):
class PolicyAccessMixin(BaseMixin, AccessMixin):
"""Mixin class for usage in Authorization views.
Provider functions to check application access, etc"""
def handle_no_permission_authorized(self) -> HttpResponse:
"""Function called when user has no permissions but is authorized"""
return redirect("passbook_flows:denied")
def provider_to_application(self, provider: Provider) -> Application:
"""Lookup application assigned to provider, throw error if no application assigned"""
try:

View File

@ -1,7 +1,7 @@
"""passbook OAuth2 Views"""
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect
from django.shortcuts import get_object_or_404
from django.views import View
from oauth2_provider.exceptions import OAuthToolkitError
from oauth2_provider.scopes import get_scopes_backend
@ -48,11 +48,11 @@ class AuthorizationFlowInitView(PolicyAccessMixin, LoginRequiredMixin, View):
try:
application = self.provider_to_application(provider)
except Application.DoesNotExist:
return redirect("passbook_providers_oauth:oauth2-permission-denied")
return self.handle_no_permission_authorized()
# Check permissions
result = self.user_has_access(application)
if not result.passing:
return redirect("passbook_providers_oauth:oauth2-permission-denied")
return self.handle_no_permission_authorized()
# Regardless, we start the planner and return to it
planner = FlowPlanner(provider.authorization_flow)
planner.allow_empty_flows = True

View File

@ -40,11 +40,11 @@ def check_permissions(
sections/settings.html#oidc-after-userlogin-hook"""
provider = client_related_provider(client)
if not provider:
return redirect("passbook_providers_oauth:oauth2-permission-denied")
return redirect("passbook_flows:denied")
try:
application = provider.application
except Application.DoesNotExist:
return redirect("passbook_providers_oauth:oauth2-permission-denied")
return redirect("passbook_flows:denied")
LOGGER.debug(
"Checking permissions for application", user=user, application=application
)
@ -56,7 +56,7 @@ def check_permissions(
if not result.passing:
for policy_message in result.messages:
messages.error(request, policy_message)
return redirect("passbook_providers_oauth:oauth2-permission-denied")
return redirect("passbook_flows:denied")
plan: FlowPlan = request.session[SESSION_KEY_PLAN]
Event.new(

View File

@ -1,7 +1,7 @@
"""passbook OIDC Views"""
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpRequest, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, reverse
from django.shortcuts import get_object_or_404, reverse
from django.views import View
from oidc_provider.lib.endpoints.authorize import AuthorizeEndpoint
from oidc_provider.lib.utils.common import get_issuer, get_site_url
@ -41,11 +41,11 @@ class AuthorizationFlowInitView(PolicyAccessMixin, LoginRequiredMixin, View):
try:
application = self.provider_to_application(provider)
except Application.DoesNotExist:
return redirect("passbook_providers_oauth:oauth2-permission-denied")
return self.handle_no_permission_authorized()
# Check permissions
result = self.user_has_access(application)
if not result.passing:
return redirect("passbook_providers_oauth:oauth2-permission-denied")
return self.handle_no_permission_authorized()
# Extract params so we can save them in the plan context
endpoint = AuthorizeEndpoint(request)
# Regardless, we start the planner and return to it

View File

@ -2,7 +2,6 @@
from typing import Optional
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
from django.core.validators import URLValidator
from django.http import HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, redirect, render, reverse
@ -54,8 +53,10 @@ class SAMLSSOView(LoginRequiredMixin, PolicyAccessMixin, View):
self.provider: SAMLProvider = get_object_or_404(
SAMLProvider, pk=self.application.provider_id
)
if not request.user.is_authenticated:
return self.handle_no_permission()
if not self.user_has_access(self.application).passing:
raise PermissionDenied()
return self.handle_no_permission_authorized()
# Call the method handler, which checks the SAML Request
method_response = super().dispatch(request, *args, application_slug, **kwargs)
if method_response: