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-14 18:45:31 +0000 |
commit | 37caed80e67fe71abf44a877908ffdf708239515 (patch) | |
tree | b4729a5bc849cb85746ebe0198eb5081569ce096 | |
parent | 04b1f1275282478168d6700fc4dd617a93a69200 (diff) | |
download | horizon-37caed80e67fe71abf44a877908ffdf708239515.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)
-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 cd34dfc26..cdbf9e0ff 100644 --- a/openstack_dashboard/api/keystone.py +++ b/openstack_dashboard/api/keystone.py @@ -121,7 +121,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: @@ -153,7 +153,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) @@ -999,7 +1000,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 260aab5dc..1a8fe8d77 100644 --- a/openstack_dashboard/test/unit/api/test_keystone.py +++ b/openstack_dashboard/test/unit/api/test_keystone.py @@ -20,6 +20,7 @@ from unittest import mock from django.test.utils import override_settings from openstack_dashboard import api +from openstack_dashboard import policy from openstack_dashboard.test import helpers as test @@ -142,3 +143,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) |