Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove sso app #15550

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -313,8 +313,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 @@ -344,14 +342,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 @@ -386,9 +382,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 @@ -455,52 +449,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 @@ -941,7 +896,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
Loading