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-14 18:45:31 +0000
commit37caed80e67fe71abf44a877908ffdf708239515 (patch)
treeb4729a5bc849cb85746ebe0198eb5081569ce096
parent04b1f1275282478168d6700fc4dd617a93a69200 (diff)
downloadhorizon-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.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 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)