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 6eeaf98524)
(cherry picked from commit 778a52e66a)
(cherry picked from commit 13e821a079)
(cherry picked from commit 084ee8aaea)
(cherry picked from commit 2f8aaa03e8)
This commit is contained in:
Rodrigo Barbieri 2022-09-07 10:52:48 -03:00 committed by Rodrigo Barbieri
parent 04b1f12752
commit 37caed80e6
2 changed files with 58 additions and 3 deletions

View File

@ -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,

View File

@ -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)