summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRodrigo Barbieri <rodrigo.barbieri2010@gmail.com>2022-09-07 10:52:48 -0300
committerRodrigo Barbieri <rodrigo.barbieri@canonical.com>2022-11-22 18:47:55 +0000
commitaad971e54c54f9255ebb0a9ab3d0dd097ec2a192 (patch)
tree7382740a9b46ff655174bf20dde9d7c551a8ab6f
parente63515ae660614aba72f6b5b6cbc4f9223d76ed4 (diff)
downloadhorizon-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.py17
-rw-r--r--openstack_dashboard/test/unit/api/test_keystone.py44
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)