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.
This commit is contained in:
Jeff Bradberry
2021-05-11 10:48:34 -04:00
parent 9e7f004ca6
commit 81de931711
3 changed files with 18 additions and 15 deletions

View File

@@ -7,7 +7,6 @@ from django.core.cache import cache
from django.core.signals import setting_changed from django.core.signals import setting_changed
from django.db.models.signals import post_save, pre_delete, post_delete from django.db.models.signals import post_save, pre_delete, post_delete
from django.dispatch import receiver from django.dispatch import receiver
from django.utils import timezone
# AWX # AWX
from awx.conf import settings_registry from awx.conf import settings_registry
@@ -65,25 +64,12 @@ def on_post_delete_setting(sender, **kwargs):
def disable_local_auth(**kwargs): def disable_local_auth(**kwargs):
if (kwargs['setting'], kwargs['value']) == ('DISABLE_LOCAL_AUTH', True): if (kwargs['setting'], kwargs['value']) == ('DISABLE_LOCAL_AUTH', True):
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sessions.models import Session
from oauth2_provider.models import RefreshToken from oauth2_provider.models import RefreshToken
from awx.main.models.oauth import OAuth2AccessToken from awx.main.models.oauth import OAuth2AccessToken
from awx.main.management.commands.revoke_oauth2_tokens import revoke_tokens 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) 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(RefreshToken.objects.filter(revoked=None, user__in=qs))
revoke_tokens(OAuth2AccessToken.objects.filter(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()

View File

@@ -7,6 +7,7 @@ import time
import urllib.parse import urllib.parse
from django.conf import settings from django.conf import settings
from django.contrib.auth import logout
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.migrations.executor import MigrationExecutor from django.db.migrations.executor import MigrationExecutor
from django.db import connection from django.db import connection
@@ -71,6 +72,21 @@ class SessionTimeoutMiddleware(MiddlewareMixin):
return response 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(): def _customize_graph():
from awx.main.models import Instance, Schedule, UnifiedJobTemplate from awx.main.models import Instance, Schedule, UnifiedJobTemplate

View File

@@ -914,6 +914,7 @@ MIDDLEWARE = [
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'awx.main.middleware.DisableLocalAuthMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'awx.sso.middleware.SocialAuthMiddleware', 'awx.sso.middleware.SocialAuthMiddleware',
'crum.CurrentRequestUserMiddleware', 'crum.CurrentRequestUserMiddleware',