Non-Admin can't list own projects
Due to a default Keystone policy until Newtown, and the use of resource_find, non-admins are unable to list their own projects. This patch bypasses this problem while also introducing better UX for non-admins wishing to get their project list. 'openstack project list' retains the default of 'list all projects' but on a forbidden error will default instead to 'list my projects'. This way for non-admins 'list my projects' feels like the default without breaking the expected admin default. Adding the '--my-projects' option allows admins to easily list their own projects or allows non-admins to be explicit and bypass the forbidden error fallback. Change-Id: I1021276f69fbbf28e13e17c4e567d932fce7ed8b Closes-Bug: #1627555
This commit is contained in:
parent
ad5b57fd19
commit
49f6032b69
@ -95,6 +95,7 @@ List projects
|
|||||||
openstack project list
|
openstack project list
|
||||||
[--domain <domain>]
|
[--domain <domain>]
|
||||||
[--user <user>]
|
[--user <user>]
|
||||||
|
[--my-projects]
|
||||||
[--long]
|
[--long]
|
||||||
[--sort <key>[:<direction>,<key>:<direction>,..]]
|
[--sort <key>[:<direction>,<key>:<direction>,..]]
|
||||||
|
|
||||||
@ -110,6 +111,12 @@ List projects
|
|||||||
|
|
||||||
.. versionadded:: 3
|
.. versionadded:: 3
|
||||||
|
|
||||||
|
.. option:: --my-projects
|
||||||
|
|
||||||
|
List projects for the authenticated user. Supersedes other filters.
|
||||||
|
|
||||||
|
.. versionadded:: 3
|
||||||
|
|
||||||
.. option:: --long
|
.. option:: --long
|
||||||
|
|
||||||
List additional fields in output
|
List additional fields in output
|
||||||
|
@ -188,6 +188,12 @@ class ListProject(command.Lister):
|
|||||||
metavar='<user>',
|
metavar='<user>',
|
||||||
help=_('Filter projects by <user> (name or ID)'),
|
help=_('Filter projects by <user> (name or ID)'),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--my-projects',
|
||||||
|
action='store_true',
|
||||||
|
help=_('List projects for the authenticated user. '
|
||||||
|
'Supersedes other filters.'),
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--long',
|
'--long',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@ -228,9 +234,25 @@ class ListProject(command.Lister):
|
|||||||
|
|
||||||
kwargs['user'] = user_id
|
kwargs['user'] = user_id
|
||||||
|
|
||||||
data = identity_client.projects.list(**kwargs)
|
if parsed_args.my_projects:
|
||||||
|
# NOTE(adriant): my-projects supersedes all the other filters.
|
||||||
|
kwargs = {'user': self.app.client_manager.auth_ref.user_id}
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = identity_client.projects.list(**kwargs)
|
||||||
|
except ks_exc.Forbidden:
|
||||||
|
# NOTE(adriant): if no filters, assume a forbidden is non-admin
|
||||||
|
# wanting their own project list.
|
||||||
|
if not kwargs:
|
||||||
|
user = self.app.client_manager.auth_ref.user_id
|
||||||
|
data = identity_client.projects.list(
|
||||||
|
user=user)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
if parsed_args.sort:
|
if parsed_args.sort:
|
||||||
data = utils.sort_items(data, parsed_args.sort)
|
data = utils.sort_items(data, parsed_args.sort)
|
||||||
|
|
||||||
return (columns,
|
return (columns,
|
||||||
(utils.get_item_properties(
|
(utils.get_item_properties(
|
||||||
s, columns,
|
s, columns,
|
||||||
|
@ -617,6 +617,36 @@ class TestProjectList(TestProject):
|
|||||||
|
|
||||||
self.assertEqual(datalists, tuple(data))
|
self.assertEqual(datalists, tuple(data))
|
||||||
|
|
||||||
|
def test_project_list_my_projects(self):
|
||||||
|
auth_ref = identity_fakes.fake_auth_ref(
|
||||||
|
identity_fakes.TOKEN_WITH_PROJECT_ID,
|
||||||
|
)
|
||||||
|
ar_mock = mock.PropertyMock(return_value=auth_ref)
|
||||||
|
type(self.app.client_manager).auth_ref = ar_mock
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
'--my-projects',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('my_projects', True),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
# In base command class Lister in cliff, abstract method take_action()
|
||||||
|
# returns a tuple containing the column names and an iterable
|
||||||
|
# containing the data to be listed.
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
self.projects_mock.list.assert_called_with(
|
||||||
|
user=self.app.client_manager.auth_ref.user_id)
|
||||||
|
|
||||||
|
collist = ('ID', 'Name')
|
||||||
|
self.assertEqual(collist, columns)
|
||||||
|
datalist = ((
|
||||||
|
self.project.id,
|
||||||
|
self.project.name,
|
||||||
|
), )
|
||||||
|
self.assertEqual(datalist, tuple(data))
|
||||||
|
|
||||||
|
|
||||||
class TestProjectSet(TestProject):
|
class TestProjectSet(TestProject):
|
||||||
|
|
||||||
|
9
releasenotes/notes/bug-1627555-3b47eba215e35b3c.yaml
Normal file
9
releasenotes/notes/bug-1627555-3b47eba215e35b3c.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The ``project list`` command lists all projects when called by an
|
||||||
|
admin user. For non-admin users it will now list projects for the
|
||||||
|
authenticated user instead of exiting with an authorization failure.
|
||||||
|
The ``--my-projects`` option has also been added to the ``project list``
|
||||||
|
command to allow admin users to list their own projects.
|
||||||
|
[Bug `1627555 <https://bugs.launchpad.net/bugs/1627555>`_]
|
Loading…
Reference in New Issue
Block a user