Skip to content

Commit

Permalink
Remove sso app (#15550)
Browse files Browse the repository at this point in the history
Remove sso app.
  • Loading branch information
ldjebran authored and jessicamack committed Oct 15, 2024
1 parent 81e9b1a commit 3d0bb21
Show file tree
Hide file tree
Showing 44 changed files with 51 additions and 1,817 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ api-lint:
awx-link:
[ -d "/awx_devel/awx.egg-info" ] || $(PYTHON) /awx_devel/tools/scripts/egg_info_dev

TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests awx/sso/tests
TEST_DIRS ?= awx/main/tests/unit awx/main/tests/functional awx/conf/tests
PYTEST_ARGS ?= -n auto
## Run all API unit tests.
test:
Expand Down Expand Up @@ -440,7 +440,7 @@ test_unit:
@if [ "$(VENV_BASE)" ]; then \
. $(VENV_BASE)/awx/bin/activate; \
fi; \
py.test awx/main/tests/unit awx/conf/tests/unit awx/sso/tests/unit
py.test awx/main/tests/unit awx/conf/tests/unit

## Output test coverage as HTML (into htmlcov directory).
coverage_html:
Expand Down
3 changes: 1 addition & 2 deletions awx/api/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from awx.conf import fields, register, register_validate
from awx.api.fields import OAuth2ProviderField
from oauth2_provider.settings import oauth2_settings
from awx.sso.common import is_remote_auth_enabled


register(
Expand Down Expand Up @@ -109,7 +108,7 @@


def authentication_validate(serializer, attrs):
if attrs.get('DISABLE_LOCAL_AUTH', False) and not is_remote_auth_enabled():
if attrs.get('DISABLE_LOCAL_AUTH', False):
raise serializers.ValidationError(_("There are no remote authentication systems configured."))
return attrs

Expand Down
23 changes: 2 additions & 21 deletions awx/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@
# AWX Utils
from awx.api.validators import HostnameRegexValidator

from awx.sso.common import get_external_account

logger = logging.getLogger('awx.api.serializers')

# Fields that should be summarized regardless of object type.
Expand Down Expand Up @@ -961,7 +959,6 @@ def get_types(self):

class UserSerializer(BaseSerializer):
password = serializers.CharField(required=False, default='', help_text=_('Field used to change the password.'))
external_account = serializers.SerializerMethodField(help_text=_('Set if the account is managed by an external service'))
is_system_auditor = serializers.BooleanField(default=False)
show_capabilities = ['edit', 'delete']

Expand All @@ -979,20 +976,12 @@ class Meta:
'is_system_auditor',
'password',
'last_login',
'external_account',
)
extra_kwargs = {'last_login': {'read_only': True}}

def to_representation(self, obj):
ret = super(UserSerializer, self).to_representation(obj)
if self.get_external_account(obj):
# If this is an external account it shouldn't have a password field
ret.pop('password', None)
else:
# If its an internal account lets assume there is a password and return $encrypted$ to the user
ret['password'] = '$encrypted$'
if obj and type(self) is UserSerializer:
ret['auth'] = obj.social_auth.values('provider', 'uid')
ret['password'] = '$encrypted$'
return ret

def get_validation_exclusions(self, obj=None):
Expand Down Expand Up @@ -1025,12 +1014,7 @@ def validate_password(self, value):
return value

def _update_password(self, obj, new_password):
# For now we're not raising an error, just not saving password for
# users managed by external authentication services (who already have an unusable password set).
# get_external_account function will return something like social or enterprise when the user is external,
# and return None when the user isn't external.
# We want to allow a password update only for non-external accounts.
if new_password and new_password != '$encrypted$' and not self.get_external_account(obj):
if new_password and new_password != '$encrypted$':
obj.set_password(new_password)
obj.save(update_fields=['password'])

Expand All @@ -1045,9 +1029,6 @@ def _update_password(self, obj, new_password):
obj.set_unusable_password()
obj.save(update_fields=['password'])

def get_external_account(self, obj):
return get_external_account(obj)

def create(self, validated_data):
new_password = validated_data.pop('password', None)
is_system_auditor = validated_data.pop('is_system_auditor', None)
Expand Down
30 changes: 14 additions & 16 deletions awx/api/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@
# ansi2html
from ansi2html import Ansi2HTMLConverter

# Python Social Auth
from social_core.backends.utils import load_backends

# Django OAuth Toolkit
from oauth2_provider.models import get_access_token_model

Expand Down Expand Up @@ -129,6 +126,9 @@
from awx.api.pagination import UnifiedJobEventPagination
from awx.main.utils import set_environ

if 'ansible_base.authentication' in getattr(settings, "INSTALLED_APPS", []):
from ansible_base.authentication.models.authenticator import Authenticator as AnsibleBaseAuthenticator

logger = logging.getLogger('awx.api.views')


Expand Down Expand Up @@ -684,20 +684,18 @@ class AuthView(APIView):
swagger_topic = 'System Configuration'

def get(self, request):
from rest_framework.reverse import reverse

data = OrderedDict()
err_backend, err_message = request.session.get('social_auth_error', (None, None))
auth_backends = list(load_backends(settings.AUTHENTICATION_BACKENDS, force_load=True).items())
# Return auth backends in consistent order: oidc.
auth_backends.sort(key=lambda x: x[0])
for name, backend in auth_backends:
login_url = reverse('social:begin', args=(name,))
complete_url = request.build_absolute_uri(reverse('social:complete', args=(name,)))
backend_data = {'login_url': login_url, 'complete_url': complete_url}
if err_backend == name and err_message:
backend_data['error'] = err_message
data[name] = backend_data
if 'ansible_base.authentication' in getattr(settings, "INSTALLED_APPS", []):
# app is using ansible_base authentication
# add ansible_base authenticators
authenticators = AnsibleBaseAuthenticator.objects.filter(enabled=True, category="sso")
for authenticator in authenticators:
login_url = authenticator.get_login_url()
data[authenticator.name] = {
'login_url': login_url,
'name': authenticator.name,
}

return Response(data)


Expand Down
15 changes: 0 additions & 15 deletions awx/conf/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,3 @@ def on_post_delete_setting(sender, **kwargs):
key = getattr(instance, '_saved_key_', None)
if key:
handle_setting_change(key, True)


@receiver(setting_changed)
def disable_local_auth(**kwargs):
if (kwargs['setting'], kwargs['value']) == ('DISABLE_LOCAL_AUTH', True):
from django.contrib.auth.models import User
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 token invalidation for local users.")

qs = User.objects.filter(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))
4 changes: 2 additions & 2 deletions awx/main/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ def process_request(self, request):
user = request.user
if not user.pk:
return
if not (user.social_auth.exists() or user.enterprise_auth.exists()):
logout(request)

logout(request)


class URLModificationMiddleware(MiddlewareMixin):
Expand Down
2 changes: 1 addition & 1 deletion awx/main/migrations/0196_delete_profile.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.10 on 2024-08-09 16:47
# Generated by Django 4.2.10 on 2024-09-16 10:22

from django.db import migrations

Expand Down
27 changes: 27 additions & 0 deletions awx/main/migrations/0197_remove_sso_app_content.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Generated by Django 4.2.10 on 2024-09-16 15:21

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('main', '0196_delete_profile'),
]

operations = [
# delete all sso application migrations
migrations.RunSQL("DELETE FROM django_migrations WHERE app = 'sso';"),
# delete all sso application content group permissions
migrations.RunSQL(
"DELETE FROM auth_group_permissions "
"WHERE permission_id IN "
"(SELECT id FROM auth_permission WHERE content_type_id in (SELECT id FROM django_content_type WHERE app_label = 'sso'));"
),
# delete all sso application content permissions
migrations.RunSQL("DELETE FROM auth_permission " "WHERE content_type_id IN (SELECT id FROM django_content_type WHERE app_label = 'sso');"),
# delete sso application content type
migrations.RunSQL("DELETE FROM django_content_type WHERE app_label = 'sso';"),
# drop sso application created table
migrations.RunSQL("DROP TABLE IF EXISTS sso_userenterpriseauth;"),
]
10 changes: 0 additions & 10 deletions awx/main/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,16 +244,6 @@ def user_is_system_auditor(user, tf):
User.add_to_class('is_system_auditor', user_is_system_auditor)


def user_is_in_enterprise_category(user, category):
ret = (category,) in user.enterprise_auth.values_list('provider') and not user.has_usable_password()
# NOTE: this if block ensures existing enterprise users are still able to
# log in. Remove it in a future release
return ret


User.add_to_class('is_in_enterprise_category', user_is_in_enterprise_category)


def o_auth2_application_get_absolute_url(self, request=None):
return reverse('api:o_auth2_application_detail', kwargs={'pk': self.pk}, request=request)

Expand Down
12 changes: 0 additions & 12 deletions awx/main/models/oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
# Django OAuth Toolkit
from oauth2_provider.models import AbstractApplication, AbstractAccessToken
from oauth2_provider.generators import generate_client_secret
from oauthlib import oauth2

from awx.sso.common import get_external_account
from awx.main.fields import OAuth2ClientSecretField


Expand Down Expand Up @@ -123,15 +121,5 @@ def _update_last_used():
connection.on_commit(_update_last_used)
return valid

def validate_external_users(self):
if self.user and settings.ALLOW_OAUTH2_FOR_EXTERNAL_USERS is False:
external_account = get_external_account(self.user)
if external_account is not None:
raise oauth2.AccessDeniedError(
_('OAuth2 Tokens cannot be created by users associated with an external authentication provider ({})').format(external_account)
)

def save(self, *args, **kwargs):
if not self.pk:
self.validate_external_users()
super(OAuth2AccessToken, self).save(*args, **kwargs)
48 changes: 1 addition & 47 deletions awx/settings/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,6 @@
'django.contrib.messages.context_processors.messages',
'awx.ui.context_processors.csp',
'awx.ui.context_processors.version',
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
],
'builtins': ['awx.main.templatetags.swagger'],
},
Expand Down Expand Up @@ -345,14 +343,12 @@
'rest_framework',
'django_extensions',
'polymorphic',
'social_django',
'django_guid',
'corsheaders',
'awx.conf',
'awx.main',
'awx.api',
'awx.ui',
'awx.sso',
'solo',
'ansible_base.rest_filters',
'ansible_base.jwt_consumer',
Expand Down Expand Up @@ -387,9 +383,7 @@
# 'URL_FORMAT_OVERRIDE': None,
}

AUTHENTICATION_BACKENDS = (
'awx.main.backends.AWXModelBackend',
)
AUTHENTICATION_BACKENDS = ('awx.main.backends.AWXModelBackend',)


# Django OAuth Toolkit settings
Expand Down Expand Up @@ -456,52 +450,13 @@
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
CACHES = {'default': {'BACKEND': 'awx.main.cache.AWXRedisCache', 'LOCATION': 'unix:///var/run/redis/redis.sock?db=1'}}

# Social Auth configuration.
SOCIAL_AUTH_STRATEGY = 'social_django.strategy.DjangoStrategy'
SOCIAL_AUTH_STORAGE = 'social_django.models.DjangoStorage'
SOCIAL_AUTH_USER_MODEL = 'auth.User'
ROLE_SINGLETON_USER_RELATIONSHIP = ''
ROLE_SINGLETON_TEAM_RELATIONSHIP = ''

# We want to short-circuit RBAC methods to get permission to system admins and auditors
ROLE_BYPASS_SUPERUSER_FLAGS = ['is_superuser']
ROLE_BYPASS_ACTION_FLAGS = {'view': 'is_system_auditor'}

_SOCIAL_AUTH_PIPELINE_BASE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.user.get_username',
'social_core.pipeline.social_auth.associate_by_email',
'social_core.pipeline.user.create_user',
'awx.sso.social_base_pipeline.check_user_found_or_created',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'awx.sso.social_base_pipeline.set_is_active_for_new_user',
'social_core.pipeline.user.user_details',
'awx.sso.social_base_pipeline.prevent_inactive_login',
)

SOCIAL_AUTH_PIPELINE = _SOCIAL_AUTH_PIPELINE_BASE + (
'awx.sso.social_pipeline.update_user_orgs',
'awx.sso.social_pipeline.update_user_teams',
'ansible_base.resource_registry.utils.service_backed_sso_pipeline.redirect_to_resource_server',
)

SOCIAL_AUTH_LOGIN_URL = '/'
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/sso/complete/'
SOCIAL_AUTH_LOGIN_ERROR_URL = '/sso/error/'
SOCIAL_AUTH_INACTIVE_USER_URL = '/sso/inactive/'

SOCIAL_AUTH_RAISE_EXCEPTIONS = False
SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = False
# SOCIAL_AUTH_SLUGIFY_USERNAMES = True
SOCIAL_AUTH_CLEAN_USERNAMES = True

SOCIAL_AUTH_SANITIZE_REDIRECTS = True
SOCIAL_AUTH_REDIRECT_IS_HTTPS = False

# Any ANSIBLE_* settings will be passed to the task runner subprocess
# environment

Expand Down Expand Up @@ -942,7 +897,6 @@
'awx.main.middleware.DisableLocalAuthMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'awx.main.middleware.OptionalURLPrefixPath',
'awx.sso.middleware.SocialAuthMiddleware',
'crum.CurrentRequestUserMiddleware',
'awx.main.middleware.URLModificationMiddleware',
'awx.main.middleware.SessionTimeoutMiddleware',
Expand Down
2 changes: 0 additions & 2 deletions awx/sso/__init__.py

This file was deleted.

8 changes: 0 additions & 8 deletions awx/sso/apps.py

This file was deleted.

Loading

0 comments on commit 3d0bb21

Please sign in to comment.