diff options
author | Rodrigo Barbieri <rodrigo.barbieri2010@gmail.com> | 2022-09-07 10:52:48 -0300 |
---|---|---|
committer | Rodrigo Barbieri <rodrigo.barbieri@canonical.com> | 2022-11-22 18:47:55 +0000 |
commit | aad971e54c54f9255ebb0a9ab3d0dd097ec2a192 (patch) | |
tree | 7382740a9b46ff655174bf20dde9d7c551a8ab6f | |
parent | e63515ae660614aba72f6b5b6cbc4f9223d76ed4 (diff) | |
download | horizon-aad971e54c54f9255ebb0a9ab3d0dd097ec2a192.tar.gz |
Fix app cred create without project_id for domain admins
Users with domain admin role that are not cloud admins are
not able to get scoped context and create an application
credential with project_id, so this change forces the
scoped context in that particular case.
Closes-bug: #1827120
Change-Id: I076a97a6f943ab74a2db8bc5179a7db194009db4
(cherry picked from commit 6eeaf9852478e25ff77c21117664ac126c5357a4)
(cherry picked from commit 778a52e66aeab883b31db729e04944eeecfec6a2)
(cherry picked from commit 13e821a079134a458b24593d9593e0e5318e6cd6)
(cherry picked from commit 084ee8aaea703d99720c0cdc2751b6479dab3b2f)
(cherry picked from commit 2f8aaa03e8ed4c2c8e3628f1f723f304b24b1f82)
(cherry picked from commit 37caed80e67fe71abf44a877908ffdf708239515)
-rw-r--r-- | openstack_dashboard/api/keystone.py | 17 | ||||
-rw-r--r-- | openstack_dashboard/test/unit/api/test_keystone.py | 44 |
2 files changed, 58 insertions, 3 deletions
diff --git a/openstack_dashboard/api/keystone.py b/openstack_dashboard/api/keystone.py index 74691f0e8..0933a1749 100644 --- a/openstack_dashboard/api/keystone.py +++ b/openstack_dashboard/api/keystone.py @@ -120,7 +120,7 @@ def _get_endpoint_url(request, endpoint_type, catalog=None): return url -def keystoneclient(request, admin=False): +def keystoneclient(request, admin=False, force_scoped=False): """Returns a client connected to the Keystone backend. Several forms of authentication are supported: @@ -152,7 +152,8 @@ def keystoneclient(request, admin=False): # If user is Cloud Admin, Domain Admin or Mixed Domain Admin and there # is no domain context specified, use domain scoped token - if is_domain_admin(request) and not is_domain_context_specified: + if (is_domain_admin(request) and not is_domain_context_specified and + not force_scoped): domain_token = request.session.get('domain_token') if domain_token: token_id = getattr(domain_token, 'auth_token', None) @@ -1008,7 +1009,17 @@ def application_credential_create(request, name, secret=None, roles=None, unrestricted=False, access_rules=None): user = request.user.id - manager = keystoneclient(request).application_credentials + # NOTE(ganso): users with domain admin role that are not cloud admins are + # not able to get scoped context and create an application credential with + # project_id, so only in this particular case we force a scoped context + force_scoped = False + if (request.user.project_id and request.session.get("domain_token") and + not policy.check( + (("identity", "identity:update_domain"),), request)): + force_scoped = True + + manager = keystoneclient( + request, force_scoped=force_scoped).application_credentials try: return manager.create(name=name, user=user, secret=secret, description=description, expires_at=expires_at, diff --git a/openstack_dashboard/test/unit/api/test_keystone.py b/openstack_dashboard/test/unit/api/test_keystone.py index 3513a1a7c..de253b2a3 100644 --- a/openstack_dashboard/test/unit/api/test_keystone.py +++ b/openstack_dashboard/test/unit/api/test_keystone.py @@ -21,6 +21,7 @@ from unittest import mock from openstack_dashboard import api +from openstack_dashboard import policy from openstack_dashboard.test import helpers as test @@ -113,3 +114,46 @@ class APIVersionTests(test.APIMockTestCase): keystoneclient.session.get_endpoint_data.assert_called_once_with( service_type='identity') self.assertEqual((3, 10), api_version) + + +class ApplicationCredentialsAPITests(test.APIMockTestCase): + + @mock.patch.object(policy, 'check') + @mock.patch.object(api.keystone, 'keystoneclient') + def test_application_credential_create_domain_token_removed( + self, mock_keystoneclient, mock_policy): + self.request.session['domain_token'] = 'some_token' + mock_policy.return_value = False + api.keystone.application_credential_create(self.request, None) + mock_keystoneclient.assert_called_once_with( + self.request, force_scoped=True) + + @mock.patch.object(policy, 'check') + @mock.patch.object(api.keystone, 'keystoneclient') + def test_application_credential_create_domain_token_not_removed_policy_true( + self, mock_keystoneclient, mock_policy): + self.request.session['domain_token'] = 'some_token' + mock_policy.return_value = True + api.keystone.application_credential_create(self.request, None) + mock_keystoneclient.assert_called_once_with( + self.request, force_scoped=False) + + @mock.patch.object(policy, 'check') + @mock.patch.object(api.keystone, 'keystoneclient') + def test_application_credential_create_domain_token_not_removed_no_token( + self, mock_keystoneclient, mock_policy): + mock_policy.return_value = True + api.keystone.application_credential_create(self.request, None) + mock_keystoneclient.assert_called_once_with( + self.request, force_scoped=False) + + @mock.patch.object(policy, 'check') + @mock.patch.object(api.keystone, 'keystoneclient') + def test_application_credential_create_domain_token_not_removed_no_project( + self, mock_keystoneclient, mock_policy): + self.request.session['domain_token'] = 'some_token' + mock_policy.return_value = True + self.request.user.project_id = None + api.keystone.application_credential_create(self.request, None) + mock_keystoneclient.assert_called_once_with( + self.request, force_scoped=False) |