diff --git a/passbook/core/templates/error/generic.html b/passbook/core/templates/error/generic.html index 7bb8ee16e..4f1753b3e 100644 --- a/passbook/core/templates/error/generic.html +++ b/passbook/core/templates/error/generic.html @@ -22,8 +22,7 @@
passbook icon - passbook branding + passbook branding
diff --git a/passbook/core/templates/login/denied.html b/passbook/core/templates/login/denied.html index 35e9d6916..fd28cdd1b 100644 --- a/passbook/core/templates/login/denied.html +++ b/passbook/core/templates/login/denied.html @@ -1,21 +1,62 @@ -{% extends 'login/base.html' %} +{% extends 'base/skeleton.html' %} {% load static %} {% load i18n %} {% load passbook_utils %} -{% block card %} -
- {% csrf_token %} - {% include 'partials/form.html' %} -
-

- - {% trans 'Access denied' %} -

+{% block body %} +
+ + + + + + + + + + + +
+ {% endblock %} diff --git a/passbook/core/templates/overview/index.html b/passbook/core/templates/overview/index.html index 0e936f0a5..69df63e7d 100644 --- a/passbook/core/templates/overview/index.html +++ b/passbook/core/templates/overview/index.html @@ -50,7 +50,7 @@
{% trans "Either no applications are defined, or you don't have access to any." %}
- {% if user.is_superuser %} {# todo: use guardian permissions instead #} + {% if user.is_superuser %} {# TODO:use guardian permissions instead #} {% trans 'Create Application' %} diff --git a/passbook/flows/templates/flows/shell.html b/passbook/flows/templates/flows/shell.html index 8957901b5..8dbdba633 100644 --- a/passbook/flows/templates/flows/shell.html +++ b/passbook/flows/templates/flows/shell.html @@ -59,7 +59,7 @@
  • {% trans 'Documentation' %}
  • - +
    diff --git a/passbook/policies/mixins.py b/passbook/policies/mixins.py index e3a528833..2e298b741 100644 --- a/passbook/policies/mixins.py +++ b/passbook/policies/mixins.py @@ -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: diff --git a/passbook/providers/oauth/views/oauth2.py b/passbook/providers/oauth/views/oauth2.py index 058e08b8e..b6a122352 100644 --- a/passbook/providers/oauth/views/oauth2.py +++ b/passbook/providers/oauth/views/oauth2.py @@ -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 diff --git a/passbook/providers/oidc/auth.py b/passbook/providers/oidc/auth.py index 0050463bf..8563b7844 100644 --- a/passbook/providers/oidc/auth.py +++ b/passbook/providers/oidc/auth.py @@ -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( diff --git a/passbook/providers/oidc/views.py b/passbook/providers/oidc/views.py index 337490cfa..5bdbe7351 100644 --- a/passbook/providers/oidc/views.py +++ b/passbook/providers/oidc/views.py @@ -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 diff --git a/passbook/providers/saml/views.py b/passbook/providers/saml/views.py index a20709cbe..f2c55d0f6 100644 --- a/passbook/providers/saml/views.py +++ b/passbook/providers/saml/views.py @@ -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: