You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2021/07/18 19:27:00 UTC

[airavata-django-portal] branch staging updated (fc3748b -> fabcc8f)

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a change to branch staging
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git.


    from fc3748b  AIRAVATA-3490 Fixes gateway admin check
     new e725c11  AIRAVATA-3319 Require login for user profile editor
     new 5e515b7  Handle refresh token failure
     new a481226  authz_token should already exist on request in login signal
     new fabcc8f  Fixes bug where missing ACCESS_TOKEN was interpreted as a good, unexpired token

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 django_airavata/apps/auth/backends.py | 20 ++++++++++++------
 django_airavata/apps/auth/signals.py  |  7 +++----
 django_airavata/apps/auth/utils.py    | 39 ++++++++++++++++++++++++++---------
 django_airavata/apps/auth/views.py    |  1 +
 4 files changed, 47 insertions(+), 20 deletions(-)

[airavata-django-portal] 01/04: AIRAVATA-3319 Require login for user profile editor

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch staging
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit e725c116092af18d3c103b8a84651e8ccdc36846
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Sun Jul 18 15:00:15 2021 -0400

    AIRAVATA-3319 Require login for user profile editor
---
 django_airavata/apps/auth/views.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/django_airavata/apps/auth/views.py b/django_airavata/apps/auth/views.py
index 45f3b79..4174b4f 100644
--- a/django_airavata/apps/auth/views.py
+++ b/django_airavata/apps/auth/views.py
@@ -532,6 +532,7 @@ def access_token_redirect(request):
                     f"{quote(request.authz_token.accessToken)}")
 
 
+@login_required
 def user_profile(request):
     return render(request, "django_airavata_auth/base.html", {
         'bundle_name': "user-profile"

[airavata-django-portal] 02/04: Handle refresh token failure

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch staging
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 5e515b7135b666751d3e33f4530c85f1f1be7a27
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Sun Jul 18 15:23:22 2021 -0400

    Handle refresh token failure
---
 django_airavata/apps/auth/backends.py | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/django_airavata/apps/auth/backends.py b/django_airavata/apps/auth/backends.py
index 349d4d2..91a9e7b 100644
--- a/django_airavata/apps/auth/backends.py
+++ b/django_airavata/apps/auth/backends.py
@@ -54,6 +54,8 @@ class KeycloakBackend(object):
                 logger.debug("Refreshing token...")
                 token, userinfo = \
                     self._get_token_and_userinfo_from_refresh_token(request)
+                if token is None:  # refresh failed
+                    return None
                 self._process_token(request, token)
                 # user is already logged in
                 user = request.user
@@ -63,6 +65,8 @@ class KeycloakBackend(object):
                 token, userinfo = \
                     self._get_token_and_userinfo_from_refresh_token(
                         request, refresh_token=refresh_token)
+                if token is None:  # refresh failed
+                    return None
                 self._process_token(request, token)
                 user = self._process_userinfo(request, userinfo)
                 access_token = token['access_token']
@@ -161,12 +165,16 @@ class KeycloakBackend(object):
         # refresh_token doesn't take client_secret kwarg, so create auth
         # explicitly
         auth = requests.auth.HTTPBasicAuth(client_id, client_secret)
-        token = oauth2_session.refresh_token(token_url=token_url,
-                                             refresh_token=refresh_token_,
-                                             auth=auth,
-                                             verify=verify)
-        userinfo = oauth2_session.get(userinfo_url).json()
-        return token, userinfo
+        try:
+            token = oauth2_session.refresh_token(token_url=token_url,
+                                                 refresh_token=refresh_token_,
+                                                 auth=auth,
+                                                 verify=verify)
+            userinfo = oauth2_session.get(userinfo_url).json()
+            return token, userinfo
+        except InvalidGrantError as e:
+            logger.warning(f"Failed to refresh token {refresh_token_}: {e}")
+            return None, None
 
     def _get_userinfo_from_token(self, request, token):
         client_id = settings.KEYCLOAK_CLIENT_ID

[airavata-django-portal] 03/04: authz_token should already exist on request in login signal

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch staging
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit a48122659ab6f844850b201b2e1df6912fa2b249
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Sun Jul 18 15:24:10 2021 -0400

    authz_token should already exist on request in login signal
---
 django_airavata/apps/auth/signals.py | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/django_airavata/apps/auth/signals.py b/django_airavata/apps/auth/signals.py
index dfc76cd..eb12e17 100644
--- a/django_airavata/apps/auth/signals.py
+++ b/django_airavata/apps/auth/signals.py
@@ -38,12 +38,11 @@ def initialize_user_profile(sender, request, user, **kwargs):
     # have an Airavata user profile (See IAMAdminServices.enableUser). The
     # following is necessary for users coming from federated login who don't
     # need to verify their email.
-    authz_token = utils.get_authz_token(request)
-    if authz_token is not None:
-        if not user_profile_client_pool.doesUserExist(authz_token,
+    if request.authz_token is not None:
+        if not user_profile_client_pool.doesUserExist(request.authz_token,
                                                       user.username,
                                                       settings.GATEWAY_ID):
-            user_profile_client_pool.initializeUserProfile(authz_token)
+            user_profile_client_pool.initializeUserProfile(request.authz_token)
             log.info("initialized user profile for {}".format(user.username))
             # Since user profile created, inform admins of new user
             utils.send_new_user_email(

[airavata-django-portal] 04/04: Fixes bug where missing ACCESS_TOKEN was interpreted as a good, unexpired token

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch staging
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit fabcc8fce1c3081d690a6a0fe91481b189b1b6e6
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Sun Jul 18 15:26:44 2021 -0400

    Fixes bug where missing ACCESS_TOKEN was interpreted as a good, unexpired token
---
 django_airavata/apps/auth/utils.py | 39 ++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/django_airavata/apps/auth/utils.py b/django_airavata/apps/auth/utils.py
index 747cdca..bb9e82d 100644
--- a/django_airavata/apps/auth/utils.py
+++ b/django_airavata/apps/auth/utils.py
@@ -18,7 +18,9 @@ def get_authz_token(request, user=None, access_token=None):
     """Construct AuthzToken instance from session; refresh token if needed."""
     if access_token is not None:
         return _create_authz_token(request, user=user, access_token=access_token)
-    elif not is_access_token_expired(request, user=user):
+    elif is_request_access_token(request):
+        return _create_authz_token(request, user=user)
+    elif is_session_access_token(request) and not is_session_access_token_expired(request, user=user):
         return _create_authz_token(request, user=user, access_token=access_token)
     elif not is_refresh_token_expired(request):
         # Have backend reauthenticate the user with the refresh token
@@ -64,21 +66,38 @@ def _create_authz_token(request, user=None, access_token=None):
                                  'userName': username})
 
 
-def _get_access_token(request):
+def _get_access_token_source(request):
     if hasattr(request, 'auth') and request.auth is not None:
-        return request.auth
+        return 'request'
+    elif 'ACCESS_TOKEN' in request.session:
+        return 'session'
     else:
+        return None
+
+
+def _get_access_token(request):
+    source = _get_access_token_source(request)
+    if source == 'request':
+        return request.auth
+    elif source == 'session':
         return request.session['ACCESS_TOKEN']
+    else:
+        return None
+
+
+def is_session_access_token(request):
+    """Return True if access token is stored in the user's session."""
+    return _get_access_token_source(request) == 'session'
+
+
+def is_request_access_token(request):
+    """Return True if access token passed in request, e.g., a Bearer token."""
+    return _get_access_token_source(request) == 'request'
 
 
-def is_access_token_expired(request, user=None):
-    """Return True if access_token is not available or is expired."""
-    # If access token not stored in session, then token expiration/refreshing
-    # isn't supported. When token is provided by REST API client it is expected
-    # that the client will manage the token lifetime.
+def is_session_access_token_expired(request, user=None):
+    """Return True if session access_token is not available or is expired."""
     user = user if user is not None else request.user
-    if 'ACCESS_TOKEN' not in request.session:
-        return False
     now = time.time()
     return not user.is_authenticated \
         or 'ACCESS_TOKEN' not in request.session \