diff --git a/awx/sso/fields.py b/awx/sso/fields.py index cd3e2195de..e2d46d9362 100644 --- a/awx/sso/fields.py +++ b/awx/sso/fields.py @@ -614,6 +614,7 @@ class SocialSingleOrganizationMapField(HybridDictField): users = SocialMapField(allow_null=True, required=False) remove_admins = fields.BooleanField(required=False) remove_users = fields.BooleanField(required=False) + organization_alias = SocialMapField(allow_null=True, required=False) child = _Forbidden() @@ -723,7 +724,6 @@ class SAMLTeamAttrTeamOrgMapField(HybridDictField): team = fields.CharField(required=True, allow_null=False) team_alias = fields.CharField(required=False, allow_null=True) organization = fields.CharField(required=True, allow_null=False) - organization_alias = fields.CharField(required=False, allow_null=True) child = _Forbidden() diff --git a/awx/sso/pipeline.py b/awx/sso/pipeline.py index 6b07fed978..13549861bb 100644 --- a/awx/sso/pipeline.py +++ b/awx/sso/pipeline.py @@ -77,7 +77,7 @@ def _update_m2m_from_expression(user, related, expr, remove=True): related.remove(user) -def _update_org_from_attr(user, related, attr, remove, remove_admins, remove_auditors): +def _update_org_from_attr(user, related, attr, remove, remove_admins, remove_auditors, backend): from awx.main.models import Organization from django.conf import settings @@ -86,7 +86,15 @@ def _update_org_from_attr(user, related, attr, remove, remove_admins, remove_aud for org_name in attr: try: if settings.SAML_AUTO_CREATE_OBJECTS: - org = Organization.objects.get_or_create(name=org_name)[0] + try: + organization_alias = backend.setting('ORGANIZATION_MAP').get(org_name).get('organization_alias') + if organization_alias is not None: + organization_name = organization_alias + else: + organization_name = org_name + except Exception: + organization_name = org_name + org = Organization.objects.get_or_create(name=organization_name)[0] org.create_default_galaxy_credential() else: org = Organization.objects.get(name=org_name) @@ -117,7 +125,12 @@ def update_user_orgs(backend, details, user=None, *args, **kwargs): org_map = backend.setting('ORGANIZATION_MAP') or {} for org_name, org_opts in org_map.items(): - org = Organization.objects.get_or_create(name=org_name)[0] + organization_alias = org_opts.get('organization_alias') + if organization_alias: + organization_name = organization_alias + else: + organization_name = org_name + org = Organization.objects.get_or_create(name=organization_name)[0] org.create_default_galaxy_credential() # Update org admins from expression(s). @@ -173,9 +186,9 @@ def update_user_orgs_by_saml_attr(backend, details, user=None, *args, **kwargs): attr_admin_values = kwargs.get('response', {}).get('attributes', {}).get(org_map.get('saml_admin_attr'), []) attr_auditor_values = kwargs.get('response', {}).get('attributes', {}).get(org_map.get('saml_auditor_attr'), []) - _update_org_from_attr(user, "member_role", attr_values, remove, False, False) - _update_org_from_attr(user, "admin_role", attr_admin_values, False, remove_admins, False) - _update_org_from_attr(user, "auditor_role", attr_auditor_values, False, False, remove_auditors) + _update_org_from_attr(user, "member_role", attr_values, remove, False, False, backend) + _update_org_from_attr(user, "admin_role", attr_admin_values, False, remove_admins, False, backend) + _update_org_from_attr(user, "auditor_role", attr_auditor_values, False, False, remove_auditors, backend) def update_user_teams_by_saml_attr(backend, details, user=None, *args, **kwargs): @@ -195,16 +208,12 @@ def update_user_teams_by_saml_attr(backend, details, user=None, *args, **kwargs) team_name = team_name_map.get('team', None) team_alias = team_name_map.get('team_alias', None) organization_name = team_name_map.get('organization', None) - organization_alias = team_name_map.get('organization_alias', None) if team_name in saml_team_names: if not organization_name: # Settings field validation should prevent this. logger.error("organization name invalid for team {}".format(team_name)) continue - if organization_alias: - organization_name = organization_alias - try: if settings.SAML_AUTO_CREATE_OBJECTS: org = Organization.objects.get_or_create(name=organization_name)[0] diff --git a/awx/sso/tests/functional/test_pipeline.py b/awx/sso/tests/functional/test_pipeline.py index 953336d389..6ed084a9d7 100644 --- a/awx/sso/tests/functional/test_pipeline.py +++ b/awx/sso/tests/functional/test_pipeline.py @@ -32,7 +32,16 @@ class TestSAMLMap: def backend(self): class Backend: s = { - 'ORGANIZATION_MAP': {'Default': {'remove': True, 'admins': 'foobar', 'remove_admins': True, 'users': 'foo', 'remove_users': True}}, + 'ORGANIZATION_MAP': { + 'Default': { + 'remove': True, + 'admins': 'foobar', + 'remove_admins': True, + 'users': 'foo', + 'remove_users': True, + 'organization_alias': '', + } + }, 'TEAM_MAP': {'Blue': {'organization': 'Default', 'remove': True, 'users': ''}, 'Red': {'organization': 'Default', 'remove': True, 'users': ''}}, } @@ -77,6 +86,11 @@ class TestSAMLMap: assert org.admin_role.members.count() == 2 assert org.member_role.members.count() == 2 + # Test organization alias feature + backend.setting('ORGANIZATION_MAP')['Default']['organization_alias'] = 'Default_Alias' + update_user_orgs(backend, None, u1) + assert Organization.objects.get(name="Default_Alias") is not None + for o in Organization.objects.all(): assert o.galaxy_credentials.count() == 1 assert o.galaxy_credentials.first().name == 'Ansible Galaxy' @@ -191,7 +205,28 @@ class TestSAMLAttr: return MockSettings() - def test_update_user_orgs_by_saml_attr(self, orgs, users, galaxy_credential, kwargs, mock_settings): + @pytest.fixture + def backend(self): + class Backend: + s = { + 'ORGANIZATION_MAP': { + 'Default1': { + 'remove': True, + 'admins': 'foobar', + 'remove_admins': True, + 'users': 'foo', + 'remove_users': True, + 'organization_alias': 'o1_alias', + } + } + } + + def setting(self, key): + return self.s[key] + + return Backend() + + def test_update_user_orgs_by_saml_attr(self, orgs, users, galaxy_credential, kwargs, mock_settings, backend): with mock.patch('django.conf.settings', mock_settings): o1, o2, o3 = orgs u1, u2, u3 = users @@ -224,6 +259,9 @@ class TestSAMLAttr: assert o2.member_role.members.count() == 3 assert o3.member_role.members.count() == 1 + update_user_orgs_by_saml_attr(backend, None, u1, **kwargs) + assert Organization.objects.get(name="o1_alias").member_role.members.count() == 1 + for o in Organization.objects.all(): assert o.galaxy_credentials.count() == 1 assert o.galaxy_credentials.first().name == 'Ansible Galaxy' @@ -298,11 +336,11 @@ class TestSAMLAttr: update_user_teams_by_saml_attr(None, None, u1, **kwargs) assert Team.objects.filter(name='Yellow', organization__name='Default4').count() == 0 - assert Team.objects.filter(name='Yellow_Alias', organization__name='Default4_Alias').count() == 1 - assert Team.objects.get(name='Yellow_Alias', organization__name='Default4_Alias').member_role.members.count() == 1 + assert Team.objects.filter(name='Yellow_Alias', organization__name='Default4').count() == 1 + assert Team.objects.get(name='Yellow_Alias', organization__name='Default4').member_role.members.count() == 1 # only Org 4 got created/updated - org = Organization.objects.get(name='Default4_Alias') + org = Organization.objects.get(name='Default4') assert org.galaxy_credentials.count() == 1 assert org.galaxy_credentials.first().name == 'Ansible Galaxy' diff --git a/awx/sso/tests/unit/test_fields.py b/awx/sso/tests/unit/test_fields.py index 48dd31c0df..463daa3b3e 100644 --- a/awx/sso/tests/unit/test_fields.py +++ b/awx/sso/tests/unit/test_fields.py @@ -79,7 +79,7 @@ class TestSAMLTeamAttrField: 'remove': True, 'saml_attr': 'foobar', 'team_org_map': [ - {'team': 'Engineering', 'team_alias': 'Engineering Team', 'organization': 'Ansible', 'organization_alias': 'Awesome Org'}, + {'team': 'Engineering', 'team_alias': 'Engineering Team', 'organization': 'Ansible'}, {'team': 'Engineering', 'organization': 'Ansible2'}, {'team': 'Engineering2', 'organization': 'Ansible'}, ],