From 4d81172a48090786e3ffb86b09d099cb58d29ef4 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sat, 20 Jun 2020 23:30:53 +0200 Subject: [PATCH] providers/oauth: add support for consent stage, cleanup --- passbook/providers/oauth/models.py | 2 +- .../templates/oauth2_provider/authorize.html | 73 ------------------- .../oauth/templates/oauth2_provider/base.html | 1 - .../templates/providers/oauth/consent.html | 20 +++++ .../oauth}/setup_url_modal.html | 0 passbook/providers/oauth/views/oauth2.py | 18 ++++- 6 files changed, 36 insertions(+), 78 deletions(-) delete mode 100644 passbook/providers/oauth/templates/oauth2_provider/authorize.html delete mode 100644 passbook/providers/oauth/templates/oauth2_provider/base.html create mode 100644 passbook/providers/oauth/templates/providers/oauth/consent.html rename passbook/providers/oauth/templates/{oauth2_provider => providers/oauth}/setup_url_modal.html (100%) diff --git a/passbook/providers/oauth/models.py b/passbook/providers/oauth/models.py index c42d3bcb4..157f8a21a 100644 --- a/passbook/providers/oauth/models.py +++ b/passbook/providers/oauth/models.py @@ -23,7 +23,7 @@ class OAuth2Provider(Provider, AbstractApplication): def html_setup_urls(self, request: HttpRequest) -> Optional[str]: """return template and context modal with URLs for authorize, token, openid-config, etc""" return render_to_string( - "oauth2_provider/setup_url_modal.html", + "providers/oauth/setup_url_modal.html", { "provider": self, "authorize_url": request.build_absolute_uri( diff --git a/passbook/providers/oauth/templates/oauth2_provider/authorize.html b/passbook/providers/oauth/templates/oauth2_provider/authorize.html deleted file mode 100644 index 24635ad37..000000000 --- a/passbook/providers/oauth/templates/oauth2_provider/authorize.html +++ /dev/null @@ -1,73 +0,0 @@ -{% extends "login/base.html" %} - -{% load passbook_utils %} -{% load i18n %} - -{% block card_title %} -{% trans 'Authorize Application' %} -{% endblock %} - -{% block card %} -
- {% csrf_token %} - {% if not error %} - {% csrf_token %} - {% for field in form %} - {% if field.is_hidden %} - {{ field }} - {% endif %} - {% endfor %} -
-

- {% blocktrans with remote=application.name %} - You're about to sign into {{ remote }}. - {% endblocktrans %} -

-

{% trans "Application requires following permissions" %}

-
    - {% for scope in scopes_descriptions %} -
  • {{ scope }}
  • - {% endfor %} -
- {{ form.errors }} - {{ form.non_field_errors }} -
-
-

- {% blocktrans with user=user %} - You are logged in as {{ user }}. Not you? - {% endblocktrans %} - {% trans 'Logout' %} -

-
- - - {% else %} - - {% endif %} -
-{% endblock %} - -{% block scripts %} - -{% endblock %} diff --git a/passbook/providers/oauth/templates/oauth2_provider/base.html b/passbook/providers/oauth/templates/oauth2_provider/base.html deleted file mode 100644 index 8759a6fae..000000000 --- a/passbook/providers/oauth/templates/oauth2_provider/base.html +++ /dev/null @@ -1 +0,0 @@ -{% extends "base/skeleton.html" %} \ No newline at end of file diff --git a/passbook/providers/oauth/templates/providers/oauth/consent.html b/passbook/providers/oauth/templates/providers/oauth/consent.html new file mode 100644 index 000000000..0fb2170c7 --- /dev/null +++ b/passbook/providers/oauth/templates/providers/oauth/consent.html @@ -0,0 +1,20 @@ +{% extends 'login/form_with_user.html' %} + +{% load i18n %} + +{% block beneath_form %} +
+

+ {% blocktrans with name=context.application.name %} + You're about to sign into {{ name }}. + {% endblocktrans %} +

+

{% trans "Application requires following permissions" %}

+ + {{ hidden_inputs }} +
+{% endblock %} diff --git a/passbook/providers/oauth/templates/oauth2_provider/setup_url_modal.html b/passbook/providers/oauth/templates/providers/oauth/setup_url_modal.html similarity index 100% rename from passbook/providers/oauth/templates/oauth2_provider/setup_url_modal.html rename to passbook/providers/oauth/templates/providers/oauth/setup_url_modal.html diff --git a/passbook/providers/oauth/views/oauth2.py b/passbook/providers/oauth/views/oauth2.py index 0196be52a..95d5a93d8 100644 --- a/passbook/providers/oauth/views/oauth2.py +++ b/passbook/providers/oauth/views/oauth2.py @@ -1,9 +1,11 @@ """passbook OAuth2 Views""" from django.contrib import messages +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.views import View from oauth2_provider.exceptions import OAuthToolkitError +from oauth2_provider.scopes import get_scopes_backend from oauth2_provider.views.base import AuthorizationView from structlog import get_logger @@ -20,6 +22,7 @@ from passbook.flows.stage import StageView from passbook.flows.views import SESSION_KEY_PLAN from passbook.lib.utils.urls import redirect_with_qs from passbook.providers.oauth.models import OAuth2Provider +from passbook.stages.consent.stage import PLAN_CONTEXT_CONSENT_TEMPLATE LOGGER = get_logger() @@ -32,9 +35,10 @@ PLAN_CONTEXT_CODE_CHALLENGE = "code_challenge" PLAN_CONTEXT_CODE_CHALLENGE_METHOD = "code_challenge_method" PLAN_CONTEXT_SCOPE = "scope" PLAN_CONTEXT_NONCE = "nonce" +PLAN_CONTEXT_SCOPE_DESCRIPTION = "scope_descriptions" -class AuthorizationFlowInitView(AccessMixin, View): +class AuthorizationFlowInitView(AccessMixin, LoginRequiredMixin, View): """OAuth2 Flow initializer, checks access to application and starts flow""" # pylint: disable=unused-argument @@ -54,8 +58,11 @@ class AuthorizationFlowInitView(AccessMixin, View): return redirect("passbook_providers_oauth:oauth2-permission-denied") # Regardless, we start the planner and return to it planner = FlowPlanner(provider.authorization_flow) - # planner.use_cache = False planner.allow_empty_flows = True + # Save scope descriptions + scopes = request.GET.get(PLAN_CONTEXT_SCOPE) + all_scopes = get_scopes_backend().get_all_scopes() + plan = planner.plan( self.request, { @@ -65,10 +72,15 @@ class AuthorizationFlowInitView(AccessMixin, View): PLAN_CONTEXT_REDIRECT_URI: request.GET.get(PLAN_CONTEXT_REDIRECT_URI), PLAN_CONTEXT_RESPONSE_TYPE: request.GET.get(PLAN_CONTEXT_RESPONSE_TYPE), PLAN_CONTEXT_STATE: request.GET.get(PLAN_CONTEXT_STATE), - PLAN_CONTEXT_SCOPE: request.GET.get(PLAN_CONTEXT_SCOPE), + PLAN_CONTEXT_SCOPE: scopes, PLAN_CONTEXT_NONCE: request.GET.get(PLAN_CONTEXT_NONCE), + PLAN_CONTEXT_SCOPE_DESCRIPTION: [ + all_scopes[scope] for scope in scopes.split(" ") + ], + PLAN_CONTEXT_CONSENT_TEMPLATE: "providers/oauth/consent.html", }, ) + plan.append(in_memory_stage(OAuth2Stage)) self.request.session[SESSION_KEY_PLAN] = plan return redirect_with_qs(