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
This commit is contained in:
Rodrigo Barbieri 2022-09-07 10:52:48 -03:00 committed by Vishal Manchanda
parent a645545584
commit 6eeaf98524
2 changed files with 58 additions and 3 deletions

View File

@ -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)
@ -995,7 +996,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

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