Validate mapping exists when creating/updating a protocol

This patch validates that a mapping exists when adding or updating
a federation protocol.

Change-Id: I996f94d26eb0f2c679542ba13a03bbaa4442486a
Closes-Bug: #1571878
This commit is contained in:
Ronald De Rose 2016-08-29 20:13:35 +00:00 committed by Steve Martinelli
parent 7a78ac0999
commit de8fbcf9a0
7 changed files with 142 additions and 8 deletions

View File

@ -182,6 +182,7 @@ Add a protocol and attribute mapping to an identity provider
Relationship: ``http://docs.openstack.org/api/openstack-identity/3/ext/OS-FEDERATION/1.0/rel/identity_provider_protocol`` Relationship: ``http://docs.openstack.org/api/openstack-identity/3/ext/OS-FEDERATION/1.0/rel/identity_provider_protocol``
Normal response codes: 201 Normal response codes: 201
Error response codes: 400
Request Request
------- -------
@ -283,6 +284,7 @@ Update the attribute mapping for an identity provider and protocol
Relationship: ``http://docs.openstack.org/api/openstack-identity/3/ext/OS-FEDERATION/1.0/rel/identity_provider_protocol`` Relationship: ``http://docs.openstack.org/api/openstack-identity/3/ext/OS-FEDERATION/1.0/rel/identity_provider_protocol``
Normal response codes: 200 Normal response codes: 200
Error response codes: 400
Request Request
------- -------

View File

@ -17,7 +17,9 @@ from keystone.common import dependency
from keystone.common import extension from keystone.common import extension
from keystone.common import manager from keystone.common import manager
import keystone.conf import keystone.conf
from keystone import exception
from keystone.federation import utils from keystone.federation import utils
from keystone.i18n import _
# This is a general cache region for service providers. # This is a general cache region for service providers.
@ -101,3 +103,18 @@ class Manager(manager.Manager):
rule_processor = utils.RuleProcessor(mapping['id'], rules) rule_processor = utils.RuleProcessor(mapping['id'], rules)
mapped_properties = rule_processor.process(assertion_data) mapped_properties = rule_processor.process(assertion_data)
return mapped_properties, mapping['id'] return mapped_properties, mapping['id']
def create_protocol(self, idp_id, protocol_id, protocol):
self._validate_mapping_exists(protocol['mapping_id'])
return self.driver.create_protocol(idp_id, protocol_id, protocol)
def update_protocol(self, idp_id, protocol_id, protocol):
self._validate_mapping_exists(protocol['mapping_id'])
return self.driver.update_protocol(idp_id, protocol_id, protocol)
def _validate_mapping_exists(self, mapping_id):
try:
self.driver.get_mapping(mapping_id)
except exception.MappingNotFound:
msg = _('Invalid mapping id: %s')
raise exception.ValidationError(message=(msg % mapping_id))

View File

@ -0,0 +1,92 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import uuid
from keystone import exception
from keystone.tests import unit
from keystone.tests.unit.ksfixtures import database
from keystone.tests.unit import mapping_fixtures
class TestFederationProtocol(unit.TestCase):
def setUp(self):
super(TestFederationProtocol, self).setUp()
self.useFixture(database.Database())
self.load_backends()
self.idp = {
'id': uuid.uuid4().hex,
'enabled': True,
'description': uuid.uuid4().hex
}
self.federation_api.create_idp(self.idp['id'], self.idp)
self.mapping = mapping_fixtures.MAPPING_EPHEMERAL_USER
self.mapping['id'] = uuid.uuid4().hex
self.federation_api.create_mapping(self.mapping['id'],
self.mapping)
def test_create_protocol(self):
protocol = {
'id': uuid.uuid4().hex,
'mapping_id': self.mapping['id']
}
protocol_ret = self.federation_api.create_protocol(self.idp['id'],
protocol['id'],
protocol)
self.assertEqual(protocol['id'], protocol_ret['id'])
def test_create_protocol_with_invalid_mapping_id(self):
protocol = {
'id': uuid.uuid4().hex,
'mapping_id': uuid.uuid4().hex
}
self.assertRaises(exception.ValidationError,
self.federation_api.create_protocol,
self.idp['id'],
protocol['id'],
protocol)
def test_update_protocol(self):
protocol = {
'id': uuid.uuid4().hex,
'mapping_id': self.mapping['id']
}
protocol_ret = self.federation_api.create_protocol(self.idp['id'],
protocol['id'],
protocol)
self.assertEqual(protocol['id'], protocol_ret['id'])
new_mapping = mapping_fixtures.MAPPING_EPHEMERAL_USER
new_mapping['id'] = uuid.uuid4().hex
self.federation_api.create_mapping(new_mapping['id'], new_mapping)
protocol['mapping_id'] = new_mapping['id']
protocol_ret = self.federation_api.update_protocol(self.idp['id'],
protocol['id'],
protocol)
self.assertEqual(protocol['id'], protocol_ret['id'])
self.assertEqual(new_mapping['id'], protocol_ret['mapping_id'])
def test_update_protocol_with_invalid_mapping_id(self):
protocol = {
'id': uuid.uuid4().hex,
'mapping_id': self.mapping['id']
}
protocol_ret = self.federation_api.create_protocol(self.idp['id'],
protocol['id'],
protocol)
self.assertEqual(protocol['id'], protocol_ret['id'])
protocol['mapping_id'] = uuid.uuid4().hex
self.assertRaises(exception.ValidationError,
self.federation_api.update_protocol,
self.idp['id'],
protocol['id'],
protocol)

View File

@ -852,6 +852,7 @@ class FederatedIdentityProviderTests(test_v3.RestfulTestCase):
proto = uuid.uuid4().hex proto = uuid.uuid4().hex
if mapping_id is None: if mapping_id is None:
mapping_id = uuid.uuid4().hex mapping_id = uuid.uuid4().hex
self._create_mapping(mapping_id)
body = {'mapping_id': mapping_id} body = {'mapping_id': mapping_id}
url = url % {'idp_id': idp_id, 'protocol_id': proto} url = url % {'idp_id': idp_id, 'protocol_id': proto}
resp = self.put(url, body={'protocol': body}, **kwargs) resp = self.put(url, body={'protocol': body}, **kwargs)
@ -863,11 +864,19 @@ class FederatedIdentityProviderTests(test_v3.RestfulTestCase):
return (resp, idp_id, proto) return (resp, idp_id, proto)
def _get_protocol(self, idp_id, protocol_id): def _get_protocol(self, idp_id, protocol_id):
url = "%s/protocols/%s" % (idp_id, protocol_id) url = '%s/protocols/%s' % (idp_id, protocol_id)
url = self.base_url(suffix=url) url = self.base_url(suffix=url)
r = self.get(url) r = self.get(url)
return r return r
def _create_mapping(self, mapping_id):
mapping = mapping_fixtures.MAPPING_EPHEMERAL_USER
mapping['id'] = mapping_id
url = '/OS-FEDERATION/mappings/%s' % mapping_id
self.put(url,
body={'mapping': mapping},
expected_status=http_client.CREATED)
def test_create_idp(self): def test_create_idp(self):
"""Create the IdentityProvider entity associated to remote_ids.""" """Create the IdentityProvider entity associated to remote_ids."""
keys_to_check = list(self.idp_keys) keys_to_check = list(self.idp_keys)
@ -1386,6 +1395,7 @@ class FederatedIdentityProviderTests(test_v3.RestfulTestCase):
resp, idp_id, proto = self._assign_protocol_to_idp( resp, idp_id, proto = self._assign_protocol_to_idp(
expected_status=http_client.CREATED) expected_status=http_client.CREATED)
new_mapping_id = uuid.uuid4().hex new_mapping_id = uuid.uuid4().hex
self._create_mapping(mapping_id=new_mapping_id)
url = "%s/protocols/%s" % (idp_id, proto) url = "%s/protocols/%s" % (idp_id, proto)
url = self.base_url(suffix=url) url = self.base_url(suffix=url)

View File

@ -14,6 +14,7 @@
from tempest.lib.common.utils import data_utils from tempest.lib.common.utils import data_utils
from tempest.lib import decorators from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from keystone_tempest_plugin.tests.api.identity import base from keystone_tempest_plugin.tests.api.identity import base
from keystone_tempest_plugin.tests.api.identity.v3 import fixtures from keystone_tempest_plugin.tests.api.identity.v3 import fixtures
@ -217,9 +218,12 @@ class IndentityProvidersTest(base.BaseIdentityTest):
# a non existent mapping ID # a non existent mapping ID
mapping_id = data_utils.rand_uuid_hex() mapping_id = data_utils.rand_uuid_hex()
protocol_id = data_utils.rand_uuid_hex() protocol_id = data_utils.rand_uuid_hex()
protocol = self._create_protocol(idp_id, protocol_id, mapping_id) self.assertRaises(
lib_exc.BadRequest,
self._assert_protocol_attributes(protocol, protocol_id, mapping_id) self._create_protocol,
idp_id,
protocol_id,
mapping_id)
@decorators.idempotent_id('c73311e7-c207-4c11-998f-532a91f1b0d1') @decorators.idempotent_id('c73311e7-c207-4c11-998f-532a91f1b0d1')
def test_update_protocol_from_identity_provider_unknown_mapping(self): def test_update_protocol_from_identity_provider_unknown_mapping(self):
@ -232,7 +236,9 @@ class IndentityProvidersTest(base.BaseIdentityTest):
# Update the identity provider protocol using a non existent # Update the identity provider protocol using a non existent
# mapping_id # mapping_id
new_mapping_id = data_utils.rand_uuid_hex() new_mapping_id = data_utils.rand_uuid_hex()
protocol = self.idps_client.update_protocol_mapping( self.assertRaises(
idp_id, protocol_id, new_mapping_id)['protocol'] lib_exc.BadRequest,
self.idps_client.update_protocol_mapping,
self._assert_protocol_attributes(protocol, protocol_id, new_mapping_id) idp_id,
protocol_id,
new_mapping_id)

View File

@ -0,0 +1,7 @@
---
fixes:
- >
[`bug 1571878 <https://bugs.launchpad.net/keystone/+bug/1571878>`_]
A valid ``mapping_id`` is now required when creating or updating a
federation protocol. If the ``mapping_id`` does not exist, a
``400 - Bad Request`` will be returned.