diff --git a/api-ref/source/v3-ext/federation/identity-provider/idp.inc b/api-ref/source/v3-ext/federation/identity-provider/idp.inc index 9896082aad..79492f7102 100644 --- a/api-ref/source/v3-ext/federation/identity-provider/idp.inc +++ b/api-ref/source/v3-ext/federation/identity-provider/idp.inc @@ -16,6 +16,7 @@ Parameters ~~~~~~~~~~ .. rest_parameters:: federation/identity-provider/parameters.yaml + - authorization_ttl: authorization_ttl - domain_id: domain_id - description: description - enabled: enabled @@ -39,6 +40,7 @@ Parameters .. rest_parameters:: federation/identity-provider/parameters.yaml + - authorization_ttl: authorization_ttl - domain_id: domain_id - description: description - enabled: enabled @@ -131,6 +133,7 @@ Parameters .. rest_parameters:: federation/identity-provider/parameters.yaml + - authorization_ttl: authorization_ttl - domain_id: domain_id - description: description - enabled: enabled @@ -221,6 +224,7 @@ Parameters .. rest_parameters:: federation/identity-provider/parameters.yaml + - authorization_ttl: authorization_ttl - domain_id: domain_id - description: description - enabled: enabled @@ -460,4 +464,4 @@ Status Codes .. rest_status_code:: success ../v3/status.yaml - - 204 \ No newline at end of file + - 204 diff --git a/api-ref/source/v3-ext/federation/identity-provider/parameters.yaml b/api-ref/source/v3-ext/federation/identity-provider/parameters.yaml index c8722803bd..42281575c7 100644 --- a/api-ref/source/v3-ext/federation/identity-provider/parameters.yaml +++ b/api-ref/source/v3-ext/federation/identity-provider/parameters.yaml @@ -33,6 +33,15 @@ id_query: # variables in body +authorization_ttl: + description: | + The length of validity in minutes for group memberships carried over + through mapping and persisted in the database. If left unset, the + default value configured in keystone will be used, if enabled. + in: body + required: false + type: integer + description: description: | The Identity Provider description diff --git a/api-ref/source/v3-ext/federation/identity-provider/samples/get-response.json b/api-ref/source/v3-ext/federation/identity-provider/samples/get-response.json index ef38ad966f..34227b8928 100644 --- a/api-ref/source/v3-ext/federation/identity-provider/samples/get-response.json +++ b/api-ref/source/v3-ext/federation/identity-provider/samples/get-response.json @@ -1,5 +1,6 @@ { "identity_provider": { + "authorization_ttl": null, "domain_id": "1789d1", "description": "Stores ACME identities", "remote_ids": ["acme_id_1", "acme_id_2"], @@ -10,4 +11,4 @@ "self": "http://example.com/identity/v3/OS-FEDERATION/identity_providers/ACME" } } -} \ No newline at end of file +} diff --git a/api-ref/source/v3-ext/federation/identity-provider/samples/update-response.json b/api-ref/source/v3-ext/federation/identity-provider/samples/update-response.json index 55f7d445c6..064b50a967 100644 --- a/api-ref/source/v3-ext/federation/identity-provider/samples/update-response.json +++ b/api-ref/source/v3-ext/federation/identity-provider/samples/update-response.json @@ -1,5 +1,6 @@ { "identity_provider": { + "authorization_ttl": null, "domain_id": "1789d1", "description": "Beta dev idp", "remote_ids": ["beta_id_1", "beta_id_2"], @@ -10,4 +11,4 @@ "self": "http://example.com/identity/v3/OS-FEDERATION/identity_providers/ACME" } } -} \ No newline at end of file +} diff --git a/keystone/api/os_federation.py b/keystone/api/os_federation.py index 6be4523c53..408722f6b7 100644 --- a/keystone/api/os_federation.py +++ b/keystone/api/os_federation.py @@ -74,7 +74,8 @@ class IdentityProvidersResource(_ResourceBase): member_key = 'identity_provider' api_prefix = '/OS-FEDERATION' _public_parameters = frozenset(['id', 'enabled', 'description', - 'remote_ids', 'links', 'domain_id' + 'remote_ids', 'links', 'domain_id', + 'authorization_ttl' ]) _id_path_param_name_override = 'idp_id' diff --git a/keystone/common/validation/parameter_types.py b/keystone/common/validation/parameter_types.py index b12331f943..abe8da6e4a 100644 --- a/keystone/common/validation/parameter_types.py +++ b/keystone/common/validation/parameter_types.py @@ -69,3 +69,8 @@ email = { 'type': 'string', 'format': 'email' } + +integer_min0 = { + 'type': 'integer', + 'minimum': 0 +} diff --git a/keystone/federation/schema.py b/keystone/federation/schema.py index 77d4e63fff..9e9ee51488 100644 --- a/keystone/federation/schema.py +++ b/keystone/federation/schema.py @@ -82,6 +82,7 @@ _identity_provider_properties_create = { 'enabled': parameter_types.boolean, 'description': validation.nullable(parameter_types.description), 'domain_id': validation.nullable(parameter_types.id_string), + 'authorization_ttl': validation.nullable(parameter_types.integer_min0), 'remote_ids': { 'type': ['array', 'null'], 'items': { @@ -94,6 +95,7 @@ _identity_provider_properties_create = { _identity_provider_properties_update = { 'enabled': parameter_types.boolean, 'description': validation.nullable(parameter_types.description), + 'authorization_ttl': validation.nullable(parameter_types.integer_min0), 'remote_ids': { 'type': ['array', 'null'], 'items': { diff --git a/keystone/tests/unit/test_v3_federation.py b/keystone/tests/unit/test_v3_federation.py index 804320a27e..d4b0d513a1 100644 --- a/keystone/tests/unit/test_v3_federation.py +++ b/keystone/tests/unit/test_v3_federation.py @@ -1132,6 +1132,18 @@ class FederatedIdentityProviderTests(test_v3.RestfulTestCase): keys_to_check=keys_to_check, ref=expected) + def test_create_idp_authorization_ttl(self): + keys_to_check = list(self.idp_keys) + keys_to_check.append('authorization_ttl') + body = self.default_body.copy() + body['description'] = uuid.uuid4().hex + body['authorization_ttl'] = 10080 + resp = self._create_default_idp(body) + expected = body.copy() + self.assertValidResponse(resp, 'identity_provider', dummy_validator, + keys_to_check=keys_to_check, + ref=expected) + def test_update_idp_remote_ids(self): """Update IdP's remote_ids parameter.""" body = self.default_body.copy() @@ -1216,6 +1228,32 @@ class FederatedIdentityProviderTests(test_v3.RestfulTestCase): self.assertIn('Duplicate remote ID', resp_data['error']['message']) + def test_update_idp_authorization_ttl(self): + body = self.default_body.copy() + body['authorization_ttl'] = 10080 + default_resp = self._create_default_idp(body=body) + default_idp = self._fetch_attribute_from_response(default_resp, + 'identity_provider') + idp_id = default_idp.get('id') + url = self.base_url(suffix=idp_id) + self.assertIsNotNone(idp_id) + + body['authorization_ttl'] = None + + body = {'identity_provider': body} + resp = self.patch(url, body=body) + updated_idp = self._fetch_attribute_from_response(resp, + 'identity_provider') + body = body['identity_provider'] + self.assertEqual(body['authorization_ttl'], + updated_idp.get('authorization_ttl')) + + resp = self.get(url) + returned_idp = self._fetch_attribute_from_response(resp, + 'identity_provider') + self.assertEqual(body['authorization_ttl'], + returned_idp.get('authorization_ttl')) + def test_list_head_idps(self, iterations=5): """List all available IdentityProviders.