From 81de9317111d9bd0f89537380f5bba9b6e637259 Mon Sep 17 00:00:00 2001 From: Jeff Bradberry Date: Tue, 11 May 2021 10:48:34 -0400 Subject: [PATCH] Add a new middleware to force-logout local-only users when the DISABLE_LOCAL_AUTH setting is set. This avoids the ugliness of getting a SuspiciousOperation error for any request/response cycles that are in flight when a user gets bounced. --- awx/conf/signals.py | 16 +--------------- awx/main/middleware.py | 16 ++++++++++++++++ awx/settings/defaults.py | 1 + 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/awx/conf/signals.py b/awx/conf/signals.py index e0788f8936..843900d9e6 100644 --- a/awx/conf/signals.py +++ b/awx/conf/signals.py @@ -7,7 +7,6 @@ from django.core.cache import cache from django.core.signals import setting_changed from django.db.models.signals import post_save, pre_delete, post_delete from django.dispatch import receiver -from django.utils import timezone # AWX from awx.conf import settings_registry @@ -65,25 +64,12 @@ def on_post_delete_setting(sender, **kwargs): def disable_local_auth(**kwargs): if (kwargs['setting'], kwargs['value']) == ('DISABLE_LOCAL_AUTH', True): from django.contrib.auth.models import User - from django.contrib.sessions.models import Session from oauth2_provider.models import RefreshToken from awx.main.models.oauth import OAuth2AccessToken from awx.main.management.commands.revoke_oauth2_tokens import revoke_tokens - logger.warning("Triggering session and token invalidation for local users.") + logger.warning("Triggering token invalidation for local users.") qs = User.objects.filter(profile__ldap_dn='', enterprise_auth__isnull=True, social_auth__isnull=True) revoke_tokens(RefreshToken.objects.filter(revoked=None, user__in=qs)) revoke_tokens(OAuth2AccessToken.objects.filter(user__in=qs)) - - user_ids = set(qs.values_list('id', flat=True)) - - start = timezone.now() - sessions = Session.objects.filter(expire_date__gte=start).iterator() - for session in sessions: - decoded = session.get_decoded() - user_id = int(decoded.get('_auth_user_id') or '-1') - if user_id in user_ids: - # The Session model instance doesn't have .flush(), we need a SessionStore instance. - session_store = session.get_session_store_class()(session.session_key) - session_store.flush() diff --git a/awx/main/middleware.py b/awx/main/middleware.py index 05c4564ffa..05e03777fb 100644 --- a/awx/main/middleware.py +++ b/awx/main/middleware.py @@ -7,6 +7,7 @@ import time import urllib.parse from django.conf import settings +from django.contrib.auth import logout from django.contrib.auth.models import User from django.db.migrations.executor import MigrationExecutor from django.db import connection @@ -71,6 +72,21 @@ class SessionTimeoutMiddleware(MiddlewareMixin): return response +class DisableLocalAuthMiddleware(MiddlewareMixin): + """ + Respects the presence of the DISABLE_LOCAL_AUTH setting and forces + local-only users to logout when they make a request. + """ + + def process_request(self, request): + if settings.DISABLE_LOCAL_AUTH: + user = request.user + if not user.pk: + return + if not (user.profile.ldap_dn or user.social_auth.exists() or user.enterprise_auth.exists()): + logout(request) + + def _customize_graph(): from awx.main.models import Instance, Schedule, UnifiedJobTemplate diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index c2ac5f4b02..33215af87f 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -914,6 +914,7 @@ MIDDLEWARE = [ 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'awx.main.middleware.DisableLocalAuthMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'awx.sso.middleware.SocialAuthMiddleware', 'crum.CurrentRequestUserMiddleware',