Merge "Add CRUD operations for Federated Protocols."
This commit is contained in:
@@ -10,13 +10,16 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import httpretty
|
import httpretty
|
||||||
|
|
||||||
|
from keystoneclient import exceptions
|
||||||
from keystoneclient.tests.v3 import utils
|
from keystoneclient.tests.v3 import utils
|
||||||
from keystoneclient.v3.contrib.federation import identity_providers
|
from keystoneclient.v3.contrib.federation import identity_providers
|
||||||
from keystoneclient.v3.contrib.federation import mappings
|
from keystoneclient.v3.contrib.federation import mappings
|
||||||
|
from keystoneclient.v3.contrib.federation import protocols
|
||||||
|
|
||||||
|
|
||||||
class IdentityProviderTests(utils.TestCase, utils.CrudTests):
|
class IdentityProviderTests(utils.TestCase, utils.CrudTests):
|
||||||
@@ -125,3 +128,198 @@ class MappingTests(utils.TestCase, utils.CrudTests):
|
|||||||
req_ref[attr],
|
req_ref[attr],
|
||||||
'Expected different %s' % attr)
|
'Expected different %s' % attr)
|
||||||
self.assertEntityRequestBodyIs(manager_ref)
|
self.assertEntityRequestBodyIs(manager_ref)
|
||||||
|
|
||||||
|
|
||||||
|
class ProtocolTests(utils.TestCase, utils.CrudTests):
|
||||||
|
def setUp(self):
|
||||||
|
super(ProtocolTests, self).setUp()
|
||||||
|
self.key = 'protocol'
|
||||||
|
self.collection_key = 'protocols'
|
||||||
|
self.model = protocols.Protocol
|
||||||
|
self.manager = self.client.federation.protocols
|
||||||
|
self.path_prefix = 'OS-FEDERATION/identity_providers'
|
||||||
|
|
||||||
|
def _transform_to_response(self, ref):
|
||||||
|
"""Rebuild dictionary so it can be used as a
|
||||||
|
reference response body.
|
||||||
|
|
||||||
|
"""
|
||||||
|
response = copy.deepcopy(ref)
|
||||||
|
response['id'] = response.pop('protocol_id')
|
||||||
|
del response['identity_provider']
|
||||||
|
return response
|
||||||
|
|
||||||
|
def new_ref(self, **kwargs):
|
||||||
|
kwargs.setdefault('mapping', uuid.uuid4().hex)
|
||||||
|
kwargs.setdefault('identity_provider', uuid.uuid4().hex)
|
||||||
|
kwargs.setdefault('protocol_id', uuid.uuid4().hex)
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def build_parts(self, identity_provider, protocol_id=None):
|
||||||
|
"""Build array used to construct httpretty URL/
|
||||||
|
|
||||||
|
Construct and return array with URL parts later used
|
||||||
|
by methods like utils.TestCase.stub_entity().
|
||||||
|
Example of URL:
|
||||||
|
``OS-FEDERATION/identity_providers/{idp_id}/
|
||||||
|
protocols/{protocol_id}``
|
||||||
|
|
||||||
|
"""
|
||||||
|
parts = ['OS-FEDERATION', 'identity_providers',
|
||||||
|
identity_provider, 'protocols']
|
||||||
|
if protocol_id:
|
||||||
|
parts.append(protocol_id)
|
||||||
|
return parts
|
||||||
|
|
||||||
|
def test_build_url_provide_base_url(self):
|
||||||
|
base_url = uuid.uuid4().hex
|
||||||
|
parameters = {'base_url': base_url}
|
||||||
|
url = self.manager.build_url(dict_args_in_out=parameters)
|
||||||
|
self.assertEqual('/'.join([base_url, self.collection_key]), url)
|
||||||
|
|
||||||
|
def test_build_url_w_idp_id(self):
|
||||||
|
"""Test whether kwargs ``base_url`` discards object's base_url
|
||||||
|
|
||||||
|
This test shows, that when ``base_url`` is specified in the
|
||||||
|
dict_args_in_out dictionary, values like ``identity_provider_id``
|
||||||
|
are not taken into consideration while building the url.
|
||||||
|
|
||||||
|
"""
|
||||||
|
base_url, identity_provider_id = uuid.uuid4().hex, uuid.uuid4().hex
|
||||||
|
parameters = {
|
||||||
|
'base_url': base_url,
|
||||||
|
'identity_provider_id': identity_provider_id
|
||||||
|
}
|
||||||
|
url = self.manager.build_url(dict_args_in_out=parameters)
|
||||||
|
self.assertEqual('/'.join([base_url, self.collection_key]), url)
|
||||||
|
|
||||||
|
def test_build_url_default_base_url(self):
|
||||||
|
identity_provider_id = uuid.uuid4().hex
|
||||||
|
parameters = {
|
||||||
|
'identity_provider_id': identity_provider_id
|
||||||
|
}
|
||||||
|
|
||||||
|
url = self.manager.build_url(dict_args_in_out=parameters)
|
||||||
|
self.assertEqual(
|
||||||
|
'/'.join([self.manager.base_url, identity_provider_id,
|
||||||
|
self.manager.collection_key]), url)
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_create(self):
|
||||||
|
"""Test creating federation protocol tied to an Identity Provider.
|
||||||
|
|
||||||
|
URL to be tested: PUT /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols/$protocol
|
||||||
|
|
||||||
|
"""
|
||||||
|
request_args = self.new_ref()
|
||||||
|
expected = self._transform_to_response(request_args)
|
||||||
|
parts = self.build_parts(request_args['identity_provider'],
|
||||||
|
request_args['protocol_id'])
|
||||||
|
self.stub_entity(httpretty.PUT, entity=expected,
|
||||||
|
parts=parts, status=201)
|
||||||
|
returned = self.manager.create(**request_args)
|
||||||
|
self.assertEqual(expected, returned.to_dict())
|
||||||
|
request_body = {'mapping_id': request_args['mapping']}
|
||||||
|
self.assertEntityRequestBodyIs(request_body)
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_get(self):
|
||||||
|
"""Fetch federation protocol object.
|
||||||
|
|
||||||
|
URL to be tested: GET /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols/$protocol
|
||||||
|
|
||||||
|
"""
|
||||||
|
request_args = self.new_ref()
|
||||||
|
expected = self._transform_to_response(request_args)
|
||||||
|
|
||||||
|
parts = self.build_parts(request_args['identity_provider'],
|
||||||
|
request_args['protocol_id'])
|
||||||
|
self.stub_entity(httpretty.GET, entity=expected,
|
||||||
|
parts=parts, status=201)
|
||||||
|
|
||||||
|
returned = self.manager.get(request_args['identity_provider'],
|
||||||
|
request_args['protocol_id'])
|
||||||
|
self.assertIsInstance(returned, self.model)
|
||||||
|
self.assertEqual(expected, returned.to_dict())
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_delete(self):
|
||||||
|
"""Delete federation protocol object.
|
||||||
|
|
||||||
|
URL to be tested: DELETE /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols/$protocol
|
||||||
|
|
||||||
|
"""
|
||||||
|
request_args = self.new_ref()
|
||||||
|
parts = self.build_parts(request_args['identity_provider'],
|
||||||
|
request_args['protocol_id'])
|
||||||
|
|
||||||
|
self.stub_entity(httpretty.DELETE, parts=parts, status=204)
|
||||||
|
|
||||||
|
self.manager.delete(request_args['identity_provider'],
|
||||||
|
request_args['protocol_id'])
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_list(self):
|
||||||
|
"""Test listing all federation protocols tied to the Identity Provider.
|
||||||
|
|
||||||
|
URL to be tested: GET /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols
|
||||||
|
|
||||||
|
"""
|
||||||
|
def _ref_protocols():
|
||||||
|
return {
|
||||||
|
'id': uuid.uuid4().hex,
|
||||||
|
'mapping_id': uuid.uuid4().hex
|
||||||
|
}
|
||||||
|
|
||||||
|
request_args = self.new_ref()
|
||||||
|
expected = [_ref_protocols() for _ in range(3)]
|
||||||
|
parts = self.build_parts(request_args['identity_provider'])
|
||||||
|
self.stub_entity(httpretty.GET, parts=parts,
|
||||||
|
entity=expected, status=200)
|
||||||
|
|
||||||
|
returned = self.manager.list(request_args['identity_provider'])
|
||||||
|
for obj, ref_obj in zip(returned, expected):
|
||||||
|
self.assertEqual(obj.to_dict(), ref_obj)
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_list_params(self):
|
||||||
|
request_args = self.new_ref()
|
||||||
|
filter_kwargs = {uuid.uuid4().hex: uuid.uuid4().hex}
|
||||||
|
parts = self.build_parts(request_args['identity_provider'])
|
||||||
|
|
||||||
|
# Return HTTP 401 as we don't accept such requests.
|
||||||
|
self.stub_entity(httpretty.GET, parts=parts, status=401)
|
||||||
|
self.assertRaises(exceptions.Unauthorized,
|
||||||
|
self.manager.list,
|
||||||
|
request_args['identity_provider'],
|
||||||
|
**filter_kwargs)
|
||||||
|
self.assertQueryStringContains(**filter_kwargs)
|
||||||
|
|
||||||
|
@httpretty.activate
|
||||||
|
def test_update(self):
|
||||||
|
"""Test updating federation protocol
|
||||||
|
|
||||||
|
URL to be tested: PATCH /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols/$protocol
|
||||||
|
|
||||||
|
"""
|
||||||
|
request_args = self.new_ref()
|
||||||
|
expected = self._transform_to_response(request_args)
|
||||||
|
|
||||||
|
parts = self.build_parts(request_args['identity_provider'],
|
||||||
|
request_args['protocol_id'])
|
||||||
|
|
||||||
|
self.stub_entity(httpretty.PATCH, parts=parts,
|
||||||
|
entity=expected, status=200)
|
||||||
|
|
||||||
|
returned = self.manager.update(request_args['identity_provider'],
|
||||||
|
request_args['protocol_id'],
|
||||||
|
mapping=request_args['mapping'])
|
||||||
|
self.assertIsInstance(returned, self.model)
|
||||||
|
self.assertEqual(expected, returned.to_dict())
|
||||||
|
request_body = {'mapping_id': request_args['mapping']}
|
||||||
|
self.assertEntityRequestBodyIs(request_body)
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
from keystoneclient.v3.contrib.federation import identity_providers
|
from keystoneclient.v3.contrib.federation import identity_providers
|
||||||
from keystoneclient.v3.contrib.federation import mappings
|
from keystoneclient.v3.contrib.federation import mappings
|
||||||
|
from keystoneclient.v3.contrib.federation import protocols
|
||||||
|
|
||||||
|
|
||||||
class FederationManager(object):
|
class FederationManager(object):
|
||||||
@@ -19,3 +20,4 @@ class FederationManager(object):
|
|||||||
self.identity_providers = identity_providers.IdentityProviderManager(
|
self.identity_providers = identity_providers.IdentityProviderManager(
|
||||||
api)
|
api)
|
||||||
self.mappings = mappings.MappingManager(api)
|
self.mappings = mappings.MappingManager(api)
|
||||||
|
self.protocols = protocols.ProtocolManager(api)
|
||||||
|
145
keystoneclient/v3/contrib/federation/protocols.py
Normal file
145
keystoneclient/v3/contrib/federation/protocols.py
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from keystoneclient import base
|
||||||
|
from keystoneclient import utils
|
||||||
|
|
||||||
|
|
||||||
|
class Protocol(base.Resource):
|
||||||
|
"""An object representing federation protocol container.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
* id: user-defined unique per Identity Provider string identifying
|
||||||
|
federation protocol.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ProtocolManager(base.CrudManager):
|
||||||
|
"""Manager class for manipulating federation protocols."""
|
||||||
|
|
||||||
|
resource_class = Protocol
|
||||||
|
collection_key = 'protocols'
|
||||||
|
key = 'protocol'
|
||||||
|
base_url = 'OS-FEDERATION/identity_providers'
|
||||||
|
|
||||||
|
def build_url(self, dict_args_in_out=None):
|
||||||
|
"""Build URL for federation protocols."""
|
||||||
|
|
||||||
|
if dict_args_in_out is None:
|
||||||
|
dict_args_in_out = {}
|
||||||
|
|
||||||
|
identity_provider_id = dict_args_in_out.pop('identity_provider_id',
|
||||||
|
None)
|
||||||
|
if identity_provider_id:
|
||||||
|
base_url = '/'.join([self.base_url, identity_provider_id])
|
||||||
|
else:
|
||||||
|
base_url = self.base_url
|
||||||
|
|
||||||
|
dict_args_in_out.setdefault('base_url', base_url)
|
||||||
|
return super(ProtocolManager, self).build_url(dict_args_in_out)
|
||||||
|
|
||||||
|
def _build_url_and_put(self, request_body=None, **kwargs):
|
||||||
|
url = self.build_url(dict_args_in_out=kwargs)
|
||||||
|
body = {self.key: request_body}
|
||||||
|
return self._update(url, body=body,
|
||||||
|
response_key=self.key,
|
||||||
|
method='PUT')
|
||||||
|
|
||||||
|
@utils.positional.method(3)
|
||||||
|
def create(self, protocol_id, identity_provider, mapping, **kwargs):
|
||||||
|
"""Create federation protocol object and tie to the Identity Provider.
|
||||||
|
|
||||||
|
Utilize Identity API operation:
|
||||||
|
PUT /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols/$protocol
|
||||||
|
|
||||||
|
:param protocol_id: a string type parameter identifying a federation
|
||||||
|
protocol
|
||||||
|
:param identity_provider: a string type parameter identifying an
|
||||||
|
Identity Provider
|
||||||
|
:param mapping: a base.Resource object with federation mapping id
|
||||||
|
|
||||||
|
"""
|
||||||
|
return self._build_url_and_put(
|
||||||
|
request_body={'mapping_id': base.getid(mapping)},
|
||||||
|
identity_provider_id=base.getid(identity_provider),
|
||||||
|
protocol_id=protocol_id, **kwargs)
|
||||||
|
|
||||||
|
def get(self, identity_provider, protocol, **kwargs):
|
||||||
|
"""Fetch federation protocol object tied to the Identity Provider.
|
||||||
|
|
||||||
|
Utilize Identity API operation:
|
||||||
|
GET /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols/$protocol
|
||||||
|
|
||||||
|
:param identity_provider: a base.Resource type object with Identity
|
||||||
|
Provider id stored inside
|
||||||
|
:param protocol: a base.Resource type object with federation protocol
|
||||||
|
id stored inside
|
||||||
|
|
||||||
|
"""
|
||||||
|
return super(ProtocolManager, self).get(
|
||||||
|
identity_provider_id=base.getid(identity_provider),
|
||||||
|
protocol_id=base.getid(protocol), **kwargs)
|
||||||
|
|
||||||
|
def list(self, identity_provider, **kwargs):
|
||||||
|
"""List all federation protocol objects tied to the Identity Provider.
|
||||||
|
|
||||||
|
Utilize Identity API operation:
|
||||||
|
GET /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols
|
||||||
|
|
||||||
|
:param identity_provider: a base.Resource type object with Identity
|
||||||
|
Provider id stored inside
|
||||||
|
|
||||||
|
"""
|
||||||
|
return super(ProtocolManager, self).list(
|
||||||
|
identity_provider_id=base.getid(identity_provider), **kwargs)
|
||||||
|
|
||||||
|
def update(self, identity_provider, protocol, mapping, **kwargs):
|
||||||
|
"""Update Protocol object tied to the Identity Provider.
|
||||||
|
|
||||||
|
Utilize Identity API operation:
|
||||||
|
PATCH /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols/$protocol
|
||||||
|
|
||||||
|
:param identity_provider: a base.Resource type object with Identity
|
||||||
|
Provider id stored inside
|
||||||
|
:param protocol: a base.Resource type object with federation protocol
|
||||||
|
id stored inside
|
||||||
|
:param mapping: a base.Resource object with federation mapping id
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
return super(ProtocolManager, self).update(
|
||||||
|
identity_provider_id=base.getid(identity_provider),
|
||||||
|
protocol_id=base.getid(protocol), mapping_id=base.getid(mapping),
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
def delete(self, identity_provider, protocol):
|
||||||
|
"""Delete Protocol object tied to the Identity Provider.
|
||||||
|
|
||||||
|
Utilize Identity API operation:
|
||||||
|
DELETE /OS-FEDERATION/identity_providers/
|
||||||
|
$identity_provider/protocols/$protocol
|
||||||
|
|
||||||
|
:param identity_provider: a base.Resource type object with
|
||||||
|
Identity Provider id stored inside
|
||||||
|
:param protocol: a base.Resource type object with federation
|
||||||
|
protocol id stored inside
|
||||||
|
|
||||||
|
"""
|
||||||
|
return super(ProtocolManager, self).delete(
|
||||||
|
identity_provider_id=base.getid(identity_provider),
|
||||||
|
protocol_id=base.getid(protocol))
|
Reference in New Issue
Block a user