diff options
author | Zuul <zuul@review.opendev.org> | 2022-11-04 16:50:17 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2022-11-04 16:50:17 +0000 |
commit | 0ad2f14e9c026eb23cb87a930c0d82342fff847a (patch) | |
tree | 9eb488cfc62b0bee88578c111b7e3deb9e67cd0b | |
parent | 23beefe2f787f2e9c95f188fa4fae2107438f0e9 (diff) | |
parent | 084ee8aaea703d99720c0cdc2751b6479dab3b2f (diff) | |
download | horizon-0ad2f14e9c026eb23cb87a930c0d82342fff847a.tar.gz |
Merge "Fix app cred create without project_id for domain admins" into stable/xena
-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 38931e52d..dd6a2a97b 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) @@ -998,7 +999,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 4598c2d50..71e8a6314 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 django.test.utils import override_settings from openstack_dashboard import api +from openstack_dashboard import policy from openstack_dashboard.test import helpers as test @@ -164,3 +165,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) |