Merge "Add authorization_ttl for identity providers"
This commit is contained in:
commit
36f58c2ad7
@ -63,6 +63,16 @@ class CreateIdentityProvider(command.ShowOne):
|
|||||||
'specified, a domain will be created automatically. '
|
'specified, a domain will be created automatically. '
|
||||||
'(Name or ID)'),
|
'(Name or ID)'),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--authorization-ttl',
|
||||||
|
metavar='<authorization-ttl>',
|
||||||
|
type=int,
|
||||||
|
help=_('Time to keep the role assignments for users '
|
||||||
|
'authenticating via this identity provider. '
|
||||||
|
'When not provided, global default configured in the '
|
||||||
|
'Identity service will be used. '
|
||||||
|
'Available since Identity API version 3.14 (Ussuri).'),
|
||||||
|
)
|
||||||
enable_identity_provider = parser.add_mutually_exclusive_group()
|
enable_identity_provider = parser.add_mutually_exclusive_group()
|
||||||
enable_identity_provider.add_argument(
|
enable_identity_provider.add_argument(
|
||||||
'--enable',
|
'--enable',
|
||||||
@ -95,12 +105,23 @@ class CreateIdentityProvider(command.ShowOne):
|
|||||||
domain_id = common.find_domain(identity_client,
|
domain_id = common.find_domain(identity_client,
|
||||||
parsed_args.domain).id
|
parsed_args.domain).id
|
||||||
|
|
||||||
|
# TODO(pas-ha) actually check for 3.14 microversion
|
||||||
|
kwargs = {}
|
||||||
|
auth_ttl = parsed_args.authorization_ttl
|
||||||
|
if auth_ttl is not None:
|
||||||
|
if auth_ttl < 0:
|
||||||
|
msg = (_("%(param)s must be positive integer or zero."
|
||||||
|
) % {"param": "authorization-ttl"})
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
kwargs['authorization_ttl'] = auth_ttl
|
||||||
|
|
||||||
idp = identity_client.federation.identity_providers.create(
|
idp = identity_client.federation.identity_providers.create(
|
||||||
id=parsed_args.identity_provider_id,
|
id=parsed_args.identity_provider_id,
|
||||||
remote_ids=remote_ids,
|
remote_ids=remote_ids,
|
||||||
description=parsed_args.description,
|
description=parsed_args.description,
|
||||||
domain_id=domain_id,
|
domain_id=domain_id,
|
||||||
enabled=parsed_args.enabled)
|
enabled=parsed_args.enabled,
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
idp._info.pop('links', None)
|
idp._info.pop('links', None)
|
||||||
remote_ids = format_columns.ListColumn(idp._info.pop('remote_ids', []))
|
remote_ids = format_columns.ListColumn(idp._info.pop('remote_ids', []))
|
||||||
@ -205,6 +226,14 @@ class SetIdentityProvider(command.Command):
|
|||||||
help=_('Name of a file that contains many remote IDs to associate '
|
help=_('Name of a file that contains many remote IDs to associate '
|
||||||
'with the identity provider, one per line'),
|
'with the identity provider, one per line'),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--authorization-ttl',
|
||||||
|
metavar='<authorization-ttl>',
|
||||||
|
type=int,
|
||||||
|
help=_('Time to keep the role assignments for users '
|
||||||
|
'authenticating via this identity provider. '
|
||||||
|
'Available since Identity API version 3.14 (Ussuri).'),
|
||||||
|
)
|
||||||
enable_identity_provider = parser.add_mutually_exclusive_group()
|
enable_identity_provider = parser.add_mutually_exclusive_group()
|
||||||
enable_identity_provider.add_argument(
|
enable_identity_provider.add_argument(
|
||||||
'--enable',
|
'--enable',
|
||||||
@ -241,6 +270,20 @@ class SetIdentityProvider(command.Command):
|
|||||||
if parsed_args.remote_id_file or parsed_args.remote_id:
|
if parsed_args.remote_id_file or parsed_args.remote_id:
|
||||||
kwargs['remote_ids'] = remote_ids
|
kwargs['remote_ids'] = remote_ids
|
||||||
|
|
||||||
|
# TODO(pas-ha) actually check for 3.14 microversion
|
||||||
|
# TODO(pas-ha) make it possible to reset authorization_ttl
|
||||||
|
# back to None value.
|
||||||
|
# Currently not possible as filter_kwargs decorator in
|
||||||
|
# keystoneclient/base.py explicitly drops the None-valued keys
|
||||||
|
# from kwargs, and 'update' method is wrapped in this decorator.
|
||||||
|
auth_ttl = parsed_args.authorization_ttl
|
||||||
|
if auth_ttl is not None:
|
||||||
|
if auth_ttl < 0:
|
||||||
|
msg = (_("%(param)s must be positive integer or zero."
|
||||||
|
) % {"param": "authorization-ttl"})
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
kwargs['authorization_ttl'] = auth_ttl
|
||||||
|
|
||||||
federation_client.identity_providers.update(
|
federation_client.identity_providers.update(
|
||||||
parsed_args.identity_provider,
|
parsed_args.identity_provider,
|
||||||
**kwargs
|
**kwargs
|
||||||
|
@ -15,9 +15,12 @@
|
|||||||
import copy
|
import copy
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from osc_lib import exceptions
|
||||||
|
|
||||||
from openstackclient.identity.v3 import identity_provider
|
from openstackclient.identity.v3 import identity_provider
|
||||||
from openstackclient.tests.unit import fakes
|
from openstackclient.tests.unit import fakes
|
||||||
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
|
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
|
||||||
|
from openstackclient.tests.unit import utils as test_utils
|
||||||
|
|
||||||
|
|
||||||
class TestIdentityProvider(identity_fakes.TestFederatedIdentity):
|
class TestIdentityProvider(identity_fakes.TestFederatedIdentity):
|
||||||
@ -308,6 +311,86 @@ class TestIdentityProviderCreate(TestIdentityProvider):
|
|||||||
self.assertEqual(self.columns, columns)
|
self.assertEqual(self.columns, columns)
|
||||||
self.assertCountEqual(self.datalist, data)
|
self.assertCountEqual(self.datalist, data)
|
||||||
|
|
||||||
|
def test_create_identity_provider_authttl_positive(self):
|
||||||
|
arglist = [
|
||||||
|
'--authorization-ttl', '60',
|
||||||
|
identity_fakes.idp_id,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('identity_provider_id', identity_fakes.idp_id),
|
||||||
|
('authorization_ttl', 60),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'remote_ids': None,
|
||||||
|
'description': None,
|
||||||
|
'domain_id': None,
|
||||||
|
'enabled': True,
|
||||||
|
'authorization_ttl': 60,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.identity_providers_mock.create.assert_called_with(
|
||||||
|
id=identity_fakes.idp_id,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertCountEqual(self.datalist, data)
|
||||||
|
|
||||||
|
def test_create_identity_provider_authttl_zero(self):
|
||||||
|
arglist = [
|
||||||
|
'--authorization-ttl', '0',
|
||||||
|
identity_fakes.idp_id,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('identity_provider_id', identity_fakes.idp_id),
|
||||||
|
('authorization_ttl', 0),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'remote_ids': None,
|
||||||
|
'description': None,
|
||||||
|
'domain_id': None,
|
||||||
|
'enabled': True,
|
||||||
|
'authorization_ttl': 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.identity_providers_mock.create.assert_called_with(
|
||||||
|
id=identity_fakes.idp_id,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertCountEqual(self.datalist, data)
|
||||||
|
|
||||||
|
def test_create_identity_provider_authttl_negative(self):
|
||||||
|
arglist = [
|
||||||
|
'--authorization-ttl', '-60',
|
||||||
|
identity_fakes.idp_id,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('identity_provider_id', identity_fakes.idp_id),
|
||||||
|
('authorization_ttl', -60),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
def test_create_identity_provider_authttl_not_int(self):
|
||||||
|
arglist = [
|
||||||
|
'--authorization-ttl', 'spam',
|
||||||
|
identity_fakes.idp_id,
|
||||||
|
]
|
||||||
|
verifylist = []
|
||||||
|
self.assertRaises(test_utils.ParserException, self.check_parser,
|
||||||
|
self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
|
||||||
class TestIdentityProviderDelete(TestIdentityProvider):
|
class TestIdentityProviderDelete(TestIdentityProvider):
|
||||||
|
|
||||||
@ -678,6 +761,93 @@ class TestIdentityProviderSet(TestIdentityProvider):
|
|||||||
|
|
||||||
self.cmd.take_action(parsed_args)
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
def test_identity_provider_set_authttl_positive(self):
|
||||||
|
def prepare(self):
|
||||||
|
"""Prepare fake return objects before the test is executed"""
|
||||||
|
updated_idp = copy.deepcopy(identity_fakes.IDENTITY_PROVIDER)
|
||||||
|
updated_idp['authorization_ttl'] = 60
|
||||||
|
resources = fakes.FakeResource(
|
||||||
|
None,
|
||||||
|
updated_idp,
|
||||||
|
loaded=True
|
||||||
|
)
|
||||||
|
self.identity_providers_mock.update.return_value = resources
|
||||||
|
|
||||||
|
prepare(self)
|
||||||
|
arglist = [
|
||||||
|
'--authorization-ttl', '60',
|
||||||
|
identity_fakes.idp_id
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('identity_provider', identity_fakes.idp_id),
|
||||||
|
('enable', False),
|
||||||
|
('disable', False),
|
||||||
|
('remote_id', None),
|
||||||
|
('authorization_ttl', 60),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
self.identity_providers_mock.update.assert_called_with(
|
||||||
|
identity_fakes.idp_id,
|
||||||
|
authorization_ttl=60,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_identity_provider_set_authttl_zero(self):
|
||||||
|
def prepare(self):
|
||||||
|
"""Prepare fake return objects before the test is executed"""
|
||||||
|
updated_idp = copy.deepcopy(identity_fakes.IDENTITY_PROVIDER)
|
||||||
|
updated_idp['authorization_ttl'] = 0
|
||||||
|
resources = fakes.FakeResource(
|
||||||
|
None,
|
||||||
|
updated_idp,
|
||||||
|
loaded=True
|
||||||
|
)
|
||||||
|
self.identity_providers_mock.update.return_value = resources
|
||||||
|
|
||||||
|
prepare(self)
|
||||||
|
arglist = [
|
||||||
|
'--authorization-ttl', '0',
|
||||||
|
identity_fakes.idp_id
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('identity_provider', identity_fakes.idp_id),
|
||||||
|
('enable', False),
|
||||||
|
('disable', False),
|
||||||
|
('remote_id', None),
|
||||||
|
('authorization_ttl', 0),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
self.identity_providers_mock.update.assert_called_with(
|
||||||
|
identity_fakes.idp_id,
|
||||||
|
authorization_ttl=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_identity_provider_set_authttl_negative(self):
|
||||||
|
arglist = [
|
||||||
|
'--authorization-ttl', '-1',
|
||||||
|
identity_fakes.idp_id
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('identity_provider', identity_fakes.idp_id),
|
||||||
|
('enable', False),
|
||||||
|
('disable', False),
|
||||||
|
('remote_id', None),
|
||||||
|
('authorization_ttl', -1),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
def test_identity_provider_set_authttl_not_int(self):
|
||||||
|
arglist = [
|
||||||
|
'--authorization-ttl', 'spam',
|
||||||
|
identity_fakes.idp_id
|
||||||
|
]
|
||||||
|
verifylist = []
|
||||||
|
self.assertRaises(test_utils.ParserException, self.check_parser,
|
||||||
|
self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
|
||||||
class TestIdentityProviderShow(TestIdentityProvider):
|
class TestIdentityProviderShow(TestIdentityProvider):
|
||||||
|
|
||||||
|
9
releasenotes/notes/idp-auth-ttl-6632df5db65a3bdd.yaml
Normal file
9
releasenotes/notes/idp-auth-ttl-6632df5db65a3bdd.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
``identity provider create`` and ``identity provider set`` commands now
|
||||||
|
accept the ``--authorization-ttl <VALUE>`` argument, with ``<VALUE>``
|
||||||
|
being a non-negative integer.
|
||||||
|
|
||||||
|
See `note <https://docs.openstack.org/keystone/latest/admin/federation/configure_federation.html#create-a-mapping>`_
|
||||||
|
in Keystone documentations for more details on the meaning of this option.
|
Loading…
Reference in New Issue
Block a user