Skip to content

Commit b638488

Browse files
TerryHoweTerry Howe
authored andcommitted
Domain administrator cannot do project operations
Domain administrator cannot do project operations because the require access to the domain API (which they don't have). When attempting to find a domain for project operations, ignore errors because the API returns nothing without indicating there is a problem. The domain administrators will have to use a domain id, but they will still be able to do project operations. If the user does not have permission to read the domain table, they cannot use domain names. Change-Id: Ieed5d420022a407c8296a0bb3569d9469c89d752 Closes-Bug: #1317478 Closes-Bug: #1317485
1 parent b3736fd commit b638488

3 files changed

Lines changed: 91 additions & 12 deletions

File tree

openstackclient/identity/common.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"""Common identity code"""
1717

1818
from keystoneclient import exceptions as identity_exc
19+
from keystoneclient.v3 import domains
1920
from openstackclient.common import exceptions
2021
from openstackclient.common import utils
2122

@@ -36,3 +37,23 @@ def find_service(identity_client, name_type_or_id):
3637
msg = ("No service with a type, name or ID of '%s' exists."
3738
% name_type_or_id)
3839
raise exceptions.CommandError(msg)
40+
41+
42+
def find_domain(identity_client, name_or_id):
43+
"""Find a domain.
44+
45+
If the user does not have permssions to access the v3 domain API,
46+
assume that domain given is the id rather than the name. This
47+
method is used by the project list command, so errors access the
48+
domain will be ignored and if the user has access to the project
49+
API, everything will work fine.
50+
51+
Closes bugs #1317478 and #1317485.
52+
"""
53+
try:
54+
dom = utils.find_resource(identity_client.domains, name_or_id)
55+
if dom is not None:
56+
return dom
57+
except identity_exc.Forbidden:
58+
pass
59+
return domains.Domain(None, {'id': name_or_id})

openstackclient/identity/v3/project.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
from openstackclient.common import parseractions
2626
from openstackclient.common import utils
27+
from openstackclient.identity import common
2728

2829

2930
class CreateProject(show.ShowOne):
@@ -73,10 +74,7 @@ def take_action(self, parsed_args):
7374
identity_client = self.app.client_manager.identity
7475

7576
if parsed_args.domain:
76-
domain = utils.find_resource(
77-
identity_client.domains,
78-
parsed_args.domain,
79-
).id
77+
domain = common.find_domain(identity_client, parsed_args.domain).id
8078
else:
8179
domain = None
8280

@@ -156,10 +154,8 @@ def take_action(self, parsed_args):
156154
columns = ('ID', 'Name')
157155
kwargs = {}
158156
if parsed_args.domain:
159-
kwargs['domain'] = utils.find_resource(
160-
identity_client.domains,
161-
parsed_args.domain,
162-
).id
157+
domain = common.find_domain(identity_client, parsed_args.domain)
158+
kwargs['domain'] = domain.id
163159
data = identity_client.projects.list(**kwargs)
164160
return (columns,
165161
(utils.get_item_properties(
@@ -236,10 +232,8 @@ def take_action(self, parsed_args):
236232
if parsed_args.name:
237233
kwargs['name'] = parsed_args.name
238234
if parsed_args.domain:
239-
kwargs['domain'] = utils.find_resource(
240-
identity_client.domains,
241-
parsed_args.domain,
242-
).id
235+
domain = common.find_domain(identity_client, parsed_args.domain)
236+
kwargs['domain'] = domain.id
243237
if parsed_args.description:
244238
kwargs['description'] = parsed_args.description
245239
if parsed_args.enable:

openstackclient/tests/identity/v3/test_project.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#
1515

1616
import copy
17+
import mock
1718

1819
from openstackclient.identity.v3 import project
1920
from openstackclient.tests import fakes
@@ -172,6 +173,45 @@ def test_project_create_domain(self):
172173
)
173174
self.assertEqual(data, datalist)
174175

176+
def test_project_create_domain_no_perms(self):
177+
arglist = [
178+
'--domain', identity_fakes.domain_id,
179+
identity_fakes.project_name,
180+
]
181+
verifylist = [
182+
('domain', identity_fakes.domain_id),
183+
('enable', False),
184+
('disable', False),
185+
('name', identity_fakes.project_name),
186+
]
187+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
188+
mocker = mock.Mock()
189+
mocker.return_value = None
190+
191+
with mock.patch("openstackclient.common.utils.find_resource", mocker):
192+
columns, data = self.cmd.take_action(parsed_args)
193+
194+
# Set expected values
195+
kwargs = {
196+
'name': identity_fakes.project_name,
197+
'domain': identity_fakes.domain_id,
198+
'description': None,
199+
'enabled': True,
200+
}
201+
self.projects_mock.create.assert_called_with(
202+
**kwargs
203+
)
204+
collist = ('description', 'domain_id', 'enabled', 'id', 'name')
205+
self.assertEqual(columns, collist)
206+
datalist = (
207+
identity_fakes.project_description,
208+
identity_fakes.domain_id,
209+
True,
210+
identity_fakes.project_id,
211+
identity_fakes.project_name,
212+
)
213+
self.assertEqual(data, datalist)
214+
175215
def test_project_create_enable(self):
176216
arglist = [
177217
'--enable',
@@ -411,6 +451,30 @@ def test_project_list_domain(self):
411451
), )
412452
self.assertEqual(tuple(data), datalist)
413453

454+
def test_project_list_domain_no_perms(self):
455+
arglist = [
456+
'--domain', identity_fakes.domain_id,
457+
]
458+
verifylist = [
459+
('domain', identity_fakes.domain_id),
460+
]
461+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
462+
mocker = mock.Mock()
463+
mocker.return_value = None
464+
465+
with mock.patch("openstackclient.common.utils.find_resource", mocker):
466+
columns, data = self.cmd.take_action(parsed_args)
467+
468+
self.projects_mock.list.assert_called_with(
469+
domain=identity_fakes.domain_id)
470+
collist = ('ID', 'Name')
471+
self.assertEqual(columns, collist)
472+
datalist = ((
473+
identity_fakes.project_id,
474+
identity_fakes.project_name,
475+
), )
476+
self.assertEqual(tuple(data), datalist)
477+
414478

415479
class TestProjectSet(TestProject):
416480

0 commit comments

Comments
 (0)