From 1bb4240a6ba9b92043cb410585a95f3bf20d89bf Mon Sep 17 00:00:00 2001 From: John Westcott IV <32551173+john-westcott-iv@users.noreply.github.com> Date: Thu, 31 Aug 2023 08:41:30 -0400 Subject: [PATCH] Allow saml_admin_attr to work in conjunction with SAML Org Map (#14285) Co-authored-by: Alan Rominger --- awx/sso/saml_pipeline.py | 2 +- .../tests/functional/test_saml_pipeline.py | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/awx/sso/saml_pipeline.py b/awx/sso/saml_pipeline.py index e8c4f9ff6d..e0244a9ce3 100644 --- a/awx/sso/saml_pipeline.py +++ b/awx/sso/saml_pipeline.py @@ -87,7 +87,7 @@ def _update_user_orgs(backend, desired_org_state, orgs_to_create, user=None): is_member_expression = org_opts.get(user_type, None) remove_members = bool(org_opts.get('remove_{}'.format(user_type), remove)) has_role = _update_m2m_from_expression(user, is_member_expression, remove_members) - desired_org_state[organization_name][role_name] = has_role + desired_org_state[organization_name][role_name] = desired_org_state[organization_name].get(role_name, False) or has_role def _update_user_teams(backend, desired_team_state, teams_to_create, user=None): diff --git a/awx/sso/tests/functional/test_saml_pipeline.py b/awx/sso/tests/functional/test_saml_pipeline.py index 628d793d4e..5204dc30ae 100644 --- a/awx/sso/tests/functional/test_saml_pipeline.py +++ b/awx/sso/tests/functional/test_saml_pipeline.py @@ -637,3 +637,75 @@ class TestSAMLUserFlags: } assert expected == _check_flag(user, 'superuser', attributes, user_flags_settings) + + +@pytest.mark.django_db +def test__update_user_orgs_org_map_and_saml_attr(): + """ + This combines the action of two other tests where an org membership is defined both by + the ORGANIZATION_MAP and the SOCIAL_AUTH_SAML_ORGANIZATION_ATTR at the same time + """ + + # This data will make the user a member + class BackendClass: + s = { + 'ORGANIZATION_MAP': { + 'Default1': { + 'remove': True, + 'remove_admins': True, + 'users': 'foobar', + 'remove_users': True, + 'organization_alias': 'o1_alias', + } + } + } + + def setting(self, key): + return self.s[key] + + backend = BackendClass() + + setting = { + 'saml_attr': 'memberOf', + 'saml_admin_attr': 'admins', + 'saml_auditor_attr': 'auditors', + 'remove': True, + 'remove_admins': True, + } + + # This data from the server will make the user an admin of the organization + kwargs = { + 'username': 'foobar', + 'uid': 'idp:cmeyers@redhat.com', + 'request': {u'SAMLResponse': [], u'RelayState': [u'idp']}, + 'is_new': False, + 'response': { + 'session_index': '_0728f0e0-b766-0135-75fa-02842b07c044', + 'idp_name': u'idp', + 'attributes': { + 'admins': ['Default1'], + }, + }, + 'social': None, + 'strategy': None, + 'new_association': False, + } + + this_user = User.objects.create(username='foobar') + + with override_settings(SOCIAL_AUTH_SAML_ORGANIZATION_ATTR=setting): + desired_org_state = {} + orgs_to_create = [] + + # this should add user as an admin of the org + _update_user_orgs_by_saml_attr(backend, desired_org_state, orgs_to_create, **kwargs) + assert desired_org_state['o1_alias']['admin_role'] is True + + assert set(orgs_to_create) == set(['o1_alias']) + + # this should add user as a member of the org without reverting the admin status + _update_user_orgs(backend, desired_org_state, orgs_to_create, this_user) + assert desired_org_state['o1_alias']['member_role'] is True + assert desired_org_state['o1_alias']['admin_role'] is True + + assert set(orgs_to_create) == set(['o1_alias'])