From c877a8b30ea42e8a2c1f77eb261c72b298512e22 Mon Sep 17 00:00:00 2001 From: Andrew Eckart Date: Thu, 5 Nov 2020 22:07:54 -0600 Subject: [PATCH 1/6] Add DISABLE_USER_MGMT config value to allow opt-out of ServiceX user management system --- README.rst | 9 +++++++-- app.conf.template | 5 +++++ servicex/resources/servicex_resource.py | 15 ++++++++------- servicex/resources/users/token_refresh.py | 12 +++++++----- servicex/templates/base.html | 2 +- tests/resource_test_base.py | 5 ++++- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index bb2985af..3f82c579 100644 --- a/README.rst +++ b/README.rst @@ -15,11 +15,16 @@ services: User Management --------------- -If ``ENABLE_AUTH`` is set to True, an identity management system will be -enabled. Users will need to create accounts in order to make requests. +If ``ENABLE_AUTH`` is set to True and `DISABLE_USER_MGMT` is False, +an identity management system will be enabled. +Users will need to create accounts in order to make requests. The system consists of two components: authentication (verification of each user's identity) and authorization (control of access to API resources). +If ``ENABLE_AUTH`` and ``DISABLE_USER_MGMT`` are both set to True, then you +will need to generate your own JWT refresh tokens externally using +``JWT_SECRET_KEY``, and provide them to end users. + Authentication ************** Authentication is currently implemented via `Globus `_, diff --git a/app.conf.template b/app.conf.template index b2d63f97..3bd10dd9 100644 --- a/app.conf.template +++ b/app.conf.template @@ -10,6 +10,11 @@ DOCS_BASE_URL = 'https://servicex.readthedocs.io/en/latest/' # Enable JWT auth on public endpoints ENABLE_AUTH=False +# Disable built-in ServiceX user management system (OAuth via Globus) +# If set to True while ENABLE_AUTH is also True, then you must generate your +# own JWT refresh tokens with identity claims using the JWT_SECRET_KEY +DISABLE_USER_MGMT = False + # Globus configuration - obtained at https://auth.globus.org/v2/web/developers GLOBUS_CLIENT_ID='globus-client-id' GLOBUS_CLIENT_SECRET='globus-client-secret' diff --git a/servicex/resources/servicex_resource.py b/servicex/resources/servicex_resource.py index effb519c..a2fb9bcb 100644 --- a/servicex/resources/servicex_resource.py +++ b/servicex/resources/servicex_resource.py @@ -43,14 +43,15 @@ def _generate_advertised_endpoint(cls, endpoint): @staticmethod def get_requesting_user() -> Optional[UserModel]: """ - :return: User who submitted request for resource. - If auth is enabled, this cannot be None for JWT-protected resources - which are decorated with @auth_required or @admin_required. + :return: ServiceX user who submitted request for resource. + Returns None if auth or user management is disabled. """ - user = None - if current_app.config.get('ENABLE_AUTH'): - user = UserModel.find_by_sub(get_jwt_identity()) - return user + config = current_app.config + if not config.get('ENABLE_AUTH') or config.get('DISABLE_USER_MGMT'): + return None + sub = get_jwt_identity() + if sub is not None: + return UserModel.find_by_sub(sub) @classmethod def _get_app_version(cls): diff --git a/servicex/resources/users/token_refresh.py b/servicex/resources/users/token_refresh.py index d61677ad..a72c10ad 100644 --- a/servicex/resources/users/token_refresh.py +++ b/servicex/resources/users/token_refresh.py @@ -26,6 +26,7 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from flask import current_app from flask_restful import Resource from flask_jwt_extended import (create_access_token, get_raw_jwt, decode_token, jwt_refresh_token_required, get_jwt_identity) @@ -35,11 +36,12 @@ class TokenRefresh(Resource): @jwt_refresh_token_required def post(self): - user = UserModel.find_by_sub(get_jwt_identity()) - claims = get_raw_jwt() - decoded = decode_token(user.refresh_token) - if not claims['jti'] == decoded['jti']: - return {'message': 'Invalid or outdated refresh token'}, 401 + if not current_app.config.get('DISABLE_USER_MGMT'): + user = UserModel.find_by_sub(get_jwt_identity()) + claims = get_raw_jwt() + decoded = decode_token(user.refresh_token) + if not claims['jti'] == decoded['jti']: + return {'message': 'Invalid or outdated refresh token'}, 401 current_user = get_jwt_identity() access_token = create_access_token(identity=current_user) return {'access_token': access_token} diff --git a/servicex/templates/base.html b/servicex/templates/base.html index a6d5391d..1714b6f0 100644 --- a/servicex/templates/base.html +++ b/servicex/templates/base.html @@ -39,7 +39,7 @@ {% endif %} - {% if config['ENABLE_AUTH'] %} + {% if config['ENABLE_AUTH'] and not config['DISABLE_USER_MGMT'] %}