From e971558fb1013af2055468ec16f0e2e9fcfca085 Mon Sep 17 00:00:00 2001 From: Beto Dealmeida Date: Tue, 12 Feb 2019 11:16:27 -0800 Subject: [PATCH 1/3] Redirect after login/register --- flask_appbuilder/security/decorators.py | 6 ++--- flask_appbuilder/security/views.py | 25 +++++++++++++++++-- .../general/security/login_oauth.html | 9 ++++--- rtd_requirements.txt | 1 + setup.py | 1 + 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/flask_appbuilder/security/decorators.py b/flask_appbuilder/security/decorators.py index 135e8e9ed..f1cbea005 100644 --- a/flask_appbuilder/security/decorators.py +++ b/flask_appbuilder/security/decorators.py @@ -1,7 +1,7 @@ import logging import functools -from flask import flash, redirect, url_for, make_response, jsonify +from flask import flash, redirect, url_for, make_response, jsonify, request from .._compat import as_unicode from ..const import LOGMSG_ERR_SEC_ACCESS_DENIED, FLAMSG_ERR_SEC_ACCESS_DENIED, PERMISSION_PREFIX @@ -27,7 +27,7 @@ def wraps(self, *args, **kwargs): else: log.warning(LOGMSG_ERR_SEC_ACCESS_DENIED.format(permission_str, self.__class__.__name__)) flash(as_unicode(FLAMSG_ERR_SEC_ACCESS_DENIED), "danger") - return redirect(url_for(self.appbuilder.sm.auth_view.__class__.__name__ + ".login")) + return redirect(url_for(self.appbuilder.sm.auth_view.__class__.__name__ + ".login", next=request.url)) f._permission_name = permission_str return functools.update_wrapper(wraps, f) @@ -56,7 +56,7 @@ def wraps(self, *args, **kwargs): 'severity': 'danger'}), 401) response.headers['Content-Type'] = "application/json" return response - return redirect(url_for(self.appbuilder.sm.auth_view.__class__.__name__ + ".login")) + return redirect(url_for(self.appbuilder.sm.auth_view.__class__.__name__ + ".login", next=request.url)) f._permission_name = permission_str return functools.update_wrapper(wraps, f) diff --git a/flask_appbuilder/security/views.py b/flask_appbuilder/security/views.py index 6d5f7742b..5b6d309b6 100644 --- a/flask_appbuilder/security/views.py +++ b/flask_appbuilder/security/views.py @@ -7,6 +7,7 @@ from wtforms.validators import EqualTo from flask_babel import lazy_gettext from flask_login import login_user, logout_user +import jwt from ..views import ModelView, SimpleFormView, expose from ..baseviews import BaseView @@ -503,11 +504,18 @@ def login(self, provider=None, register=None): appbuilder=self.appbuilder) else: log.debug("Going to call authorize for: {0}".format(provider)) + state = jwt.encode( + request.args.to_dict(flat=False), + self.appbuilder.app.config['SECRET_KEY'], + algorithm='HS256') try: if register: log.debug('Login to Register') session['register'] = True - return self.appbuilder.sm.oauth_remotes[provider].authorize(callback=url_for('.oauth_authorized',provider=provider, _external=True)) + return self.appbuilder.sm.oauth_remotes[provider].authorize( + callback=url_for + ('.oauth_authorized', provider=provider, _external=True), + state=state) except Exception as e: log.error("Error on OAuth authorize: {0}".format(e)) flash(as_unicode(self.invalid_login_message), 'warning') @@ -550,7 +558,20 @@ def oauth_authorized(self, provider): return redirect('login') else: login_user(user) - return redirect(self.appbuilder.get_url_for_index) + try: + state = jwt.decode( + request.args['state'], + self.appbuilder.app.config['SECRET_KEY'], + algorithms=['HS256']) + except jwt.InvalidTokenError: + raise AuthenticationError('State signature is not valid!') + + try: + next_url = state['next'][0] + except (KeyError, IndexError): + next_url = self.appbuilder.get_url_for_index + + return redirect(next_url) class AuthRemoteUserView(AuthView): diff --git a/flask_appbuilder/templates/appbuilder/general/security/login_oauth.html b/flask_appbuilder/templates/appbuilder/general/security/login_oauth.html index 1dff72e53..4e524cf4f 100644 --- a/flask_appbuilder/templates/appbuilder/general/security/login_oauth.html +++ b/flask_appbuilder/templates/appbuilder/general/security/login_oauth.html @@ -5,8 +5,9 @@