mirror of https://github.com/OpenKMIP/PyKMIP.git
Merge pull request #128 from viktorTarasov/feature/discover-versions/server
server: implement 'discover-versions'
This commit is contained in:
commit
cfb85190fa
|
@ -33,6 +33,7 @@ from kmip.core.factories.secrets import SecretFactory
|
||||||
from kmip.core.messages.contents import ResultStatus
|
from kmip.core.messages.contents import ResultStatus
|
||||||
from kmip.core.messages.contents import ResultReason
|
from kmip.core.messages.contents import ResultReason
|
||||||
from kmip.core.messages.contents import ResultMessage
|
from kmip.core.messages.contents import ResultMessage
|
||||||
|
from kmip.core.messages.contents import ProtocolVersion
|
||||||
|
|
||||||
from kmip.core.misc import KeyFormatType
|
from kmip.core.misc import KeyFormatType
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ from kmip.services.results import GetResult
|
||||||
from kmip.services.results import OperationResult
|
from kmip.services.results import OperationResult
|
||||||
from kmip.services.results import RegisterResult
|
from kmip.services.results import RegisterResult
|
||||||
from kmip.services.results import LocateResult
|
from kmip.services.results import LocateResult
|
||||||
|
from kmip.services.results import DiscoverVersionsResult
|
||||||
|
|
||||||
|
|
||||||
class KMIP(object):
|
class KMIP(object):
|
||||||
|
@ -85,6 +87,9 @@ class KMIP(object):
|
||||||
credential=None):
|
credential=None):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def discover_versions(self, protocol_versions=None):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
class KMIPImpl(KMIP):
|
class KMIPImpl(KMIP):
|
||||||
|
|
||||||
|
@ -95,6 +100,10 @@ class KMIPImpl(KMIP):
|
||||||
self.secret_factory = SecretFactory()
|
self.secret_factory = SecretFactory()
|
||||||
self.attribute_factory = AttributeFactory()
|
self.attribute_factory = AttributeFactory()
|
||||||
self.repo = MemRepo()
|
self.repo = MemRepo()
|
||||||
|
self.protocol_versions = [
|
||||||
|
ProtocolVersion.create(1, 1),
|
||||||
|
ProtocolVersion.create(1, 0)
|
||||||
|
]
|
||||||
|
|
||||||
def create(self, object_type, template_attribute, credential=None):
|
def create(self, object_type, template_attribute, credential=None):
|
||||||
self.logger.debug('create() called')
|
self.logger.debug('create() called')
|
||||||
|
@ -279,6 +288,32 @@ class KMIPImpl(KMIP):
|
||||||
return LocateResult(ResultStatus(RS.OPERATION_FAILED),
|
return LocateResult(ResultStatus(RS.OPERATION_FAILED),
|
||||||
result_reason=reason, result_message=msg)
|
result_reason=reason, result_message=msg)
|
||||||
|
|
||||||
|
def discover_versions(self, protocol_versions=None):
|
||||||
|
self.logger.debug(
|
||||||
|
"discover_versions(protocol_versions={0}) called".format(
|
||||||
|
protocol_versions))
|
||||||
|
msg = 'get protocol versions supported by server'
|
||||||
|
|
||||||
|
result_versions = list()
|
||||||
|
if protocol_versions:
|
||||||
|
msg += " and client; client versions {0}".format(protocol_versions)
|
||||||
|
for version in protocol_versions:
|
||||||
|
if version in self.protocol_versions:
|
||||||
|
result_versions.append(version)
|
||||||
|
else:
|
||||||
|
result_versions = self.protocol_versions
|
||||||
|
|
||||||
|
self.logger.debug(msg)
|
||||||
|
try:
|
||||||
|
return DiscoverVersionsResult(ResultStatus(RS.SUCCESS),
|
||||||
|
protocol_versions=result_versions)
|
||||||
|
except Exception:
|
||||||
|
msg = ResultMessage('DiscoverVersions Operation Failed')
|
||||||
|
reason = ResultReason(ResultReasonEnum.GENERAL_FAILURE)
|
||||||
|
return DiscoverVersionsResult(ResultStatus(RS.OPERATION_FAILED),
|
||||||
|
result_reason=reason,
|
||||||
|
result_message=msg)
|
||||||
|
|
||||||
def _validate_req_field(self, attrs, name, expected, msg, required=True):
|
def _validate_req_field(self, attrs, name, expected, msg, required=True):
|
||||||
self.logger.debug('Validating attribute %s' % name)
|
self.logger.debug('Validating attribute %s' % name)
|
||||||
seen = False
|
seen = False
|
||||||
|
|
|
@ -33,6 +33,8 @@ from kmip.core.messages.payloads.get import GetResponsePayload
|
||||||
from kmip.core.messages.payloads.destroy import DestroyResponsePayload
|
from kmip.core.messages.payloads.destroy import DestroyResponsePayload
|
||||||
from kmip.core.messages.payloads.register import RegisterResponsePayload
|
from kmip.core.messages.payloads.register import RegisterResponsePayload
|
||||||
from kmip.core.messages.payloads.locate import LocateResponsePayload
|
from kmip.core.messages.payloads.locate import LocateResponsePayload
|
||||||
|
from kmip.core.messages.payloads.discover_versions import \
|
||||||
|
DiscoverVersionsResponsePayload
|
||||||
|
|
||||||
from kmip.core.enums import Operation
|
from kmip.core.enums import Operation
|
||||||
from kmip.core.enums import ResultStatus as RS
|
from kmip.core.enums import ResultStatus as RS
|
||||||
|
@ -173,7 +175,10 @@ class Processor(object):
|
||||||
return self._process_register_request(payload)
|
return self._process_register_request(payload)
|
||||||
elif op is Operation.LOCATE:
|
elif op is Operation.LOCATE:
|
||||||
return self._process_locate_request(payload)
|
return self._process_locate_request(payload)
|
||||||
|
elif op is Operation.DISCOVER_VERSIONS:
|
||||||
|
return self._process_discover_versions_request(payload)
|
||||||
else:
|
else:
|
||||||
|
self.logger.debug("Process operation: Not implemented")
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def _process_create_request(self, payload):
|
def _process_create_request(self, payload):
|
||||||
|
@ -276,3 +281,19 @@ class Processor(object):
|
||||||
resp_pl = LocateResponsePayload(unique_identifiers=uuids)
|
resp_pl = LocateResponsePayload(unique_identifiers=uuids)
|
||||||
|
|
||||||
return (result_status, result_reason, result_message, resp_pl)
|
return (result_status, result_reason, result_message, resp_pl)
|
||||||
|
|
||||||
|
def _process_discover_versions_request(self, payload):
|
||||||
|
protocol_versions = payload.protocol_versions
|
||||||
|
|
||||||
|
result = self._handler.discover_versions(
|
||||||
|
protocol_versions=protocol_versions)
|
||||||
|
|
||||||
|
result_status = result.result_status
|
||||||
|
result_reason = result.result_reason
|
||||||
|
result_protocol_versions = result.protocol_versions
|
||||||
|
result_message = result.result_message
|
||||||
|
|
||||||
|
resp_pl = DiscoverVersionsResponsePayload(
|
||||||
|
protocol_versions=result_protocol_versions)
|
||||||
|
|
||||||
|
return (result_status, result_reason, result_message, resp_pl)
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
# Copyright (c) 2016 The Johns Hopkins University/Applied Physics Laboratory
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 mock
|
||||||
|
import testtools
|
||||||
|
from binascii import unhexlify as hex2bin
|
||||||
|
|
||||||
|
from kmip.core.server import KMIPImpl
|
||||||
|
from kmip.services.server.processor import Processor
|
||||||
|
from kmip.services.server.kmip_protocol import KMIPProtocolFactory
|
||||||
|
|
||||||
|
|
||||||
|
class TestServerProcessor(testtools.TestCase):
|
||||||
|
"""
|
||||||
|
Integration test suite for the Kmip Server Processor.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _setTimeStamp(self, data, ref):
|
||||||
|
"""
|
||||||
|
Take raw TimeStamp data from 'ref' and update with it
|
||||||
|
the TimeStamp in 'data'.
|
||||||
|
|
||||||
|
Applied to the data blob sent by processor before comparing it
|
||||||
|
with the reference response data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
time_stamp_pattern = hex2bin('4200920900000008')
|
||||||
|
try:
|
||||||
|
idx_data = data.index(time_stamp_pattern)
|
||||||
|
idx_ref = ref.index(time_stamp_pattern)
|
||||||
|
except Exception:
|
||||||
|
return data
|
||||||
|
data = data[:idx_data] + ref[idx_ref:idx_ref+16] + data[idx_data+16:]
|
||||||
|
return data
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestServerProcessor, self).setUp()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(TestServerProcessor, self).tearDown()
|
||||||
|
|
||||||
|
def test_init(self):
|
||||||
|
"""
|
||||||
|
Test that a Kmip Server Processor can be created without errors.
|
||||||
|
"""
|
||||||
|
|
||||||
|
handler = KMIPImpl()
|
||||||
|
Processor(handler)
|
||||||
|
|
||||||
|
def _integration_test_process(self, request, expected):
|
||||||
|
"""
|
||||||
|
Semi-integration test of the Request processing;
|
||||||
|
includes the encode/decode of messages and operation specific
|
||||||
|
Payloads.
|
||||||
|
|
||||||
|
WF is mocked on the socket level:
|
||||||
|
- request blob data are supplied to socket in two chunks:
|
||||||
|
-- Request tag/type/length;
|
||||||
|
-- Request Message data.
|
||||||
|
- data sent by socket are restored from the mock-calls and compared
|
||||||
|
with expected data (excluding the TimeStamp data -- TODO).
|
||||||
|
"""
|
||||||
|
|
||||||
|
socket = mock.MagicMock()
|
||||||
|
socket.recv = mock.MagicMock(side_effect=[request[:8], request[8:]])
|
||||||
|
|
||||||
|
socket.sendall = mock.MagicMock()
|
||||||
|
|
||||||
|
factory = KMIPProtocolFactory()
|
||||||
|
protocol = factory.getProtocol(socket)
|
||||||
|
|
||||||
|
handler = KMIPImpl()
|
||||||
|
processor = Processor(handler)
|
||||||
|
|
||||||
|
processor.process(protocol, protocol)
|
||||||
|
|
||||||
|
(args, kwargs) = socket.sendall.call_args
|
||||||
|
to_cmp = self._setTimeStamp(args[0], expected)
|
||||||
|
self.assertEqual(expected, to_cmp, "Unexpected error")
|
||||||
|
|
||||||
|
def test_process_discovery_versions(self):
|
||||||
|
"""
|
||||||
|
'DiscoveryVersion':
|
||||||
|
- request:
|
||||||
|
-- header with protocol version and credential authentication;
|
||||||
|
-- batch item 'Operation DiscoverVersions' without parameters
|
||||||
|
- expected:
|
||||||
|
-- response header with procotol-version, time stamp, batch count
|
||||||
|
-- batch item with two versions supported by server
|
||||||
|
"""
|
||||||
|
request = hex2bin(
|
||||||
|
'42007801000000b04200770100000088420069010000002042006a02000000040'
|
||||||
|
'00000010000000042006b0200000004000000010000000042000c010000004842'
|
||||||
|
'00230100000040420024050000000400000001000000004200250100000028420'
|
||||||
|
'099070000000a4b6d6970436c69656e740000000000004200a10700000006436f'
|
||||||
|
'75636f75000042000d0200000004000000010000000042000f010000001842005'
|
||||||
|
'c05000000040000001e000000004200790100000000')
|
||||||
|
response = hex2bin(
|
||||||
|
'42007b01000000d042007a0100000048420069010000002042006a02000000040'
|
||||||
|
'00000010000000042006b02000000040000000100000000420092090000000800'
|
||||||
|
'00000056bda8eb42000d0200000004000000010000000042000f0100000078420'
|
||||||
|
'05c05000000040000001e0000000042007f050000000400000000000000004200'
|
||||||
|
'7c0100000050420069010000002042006a0200000004000000010000000042006'
|
||||||
|
'b02000000040000000100000000420069010000002042006a0200000004000000'
|
||||||
|
'010000000042006b02000000040000000000000000')
|
||||||
|
|
||||||
|
self._integration_test_process(request, response)
|
||||||
|
|
||||||
|
def test_process_create_symmetric_key(self):
|
||||||
|
"""
|
||||||
|
'Create':
|
||||||
|
- request:
|
||||||
|
-- header with protocol version and credential authentication;
|
||||||
|
-- batch item 'Operation Create':
|
||||||
|
-- object type : symmetric key
|
||||||
|
-- attributes:
|
||||||
|
-- Cryptographic Algorithm: AES
|
||||||
|
-- Cryptographic Usage Mask
|
||||||
|
-- Cryptographic Length: 128
|
||||||
|
-- Name
|
||||||
|
- expected:
|
||||||
|
-- response header with procotol-version, time stamp, batch count
|
||||||
|
-- batch item with:
|
||||||
|
-- operation: Create;
|
||||||
|
-- result status: Success;
|
||||||
|
-- response payload:
|
||||||
|
-- object type: symmetric key;
|
||||||
|
-- UID: '1';
|
||||||
|
-- attribute template:
|
||||||
|
-- 'Unique Identifier': '1'
|
||||||
|
"""
|
||||||
|
request = hex2bin(
|
||||||
|
'42007801000001b04200770100000088420069010000002042006a02000000040'
|
||||||
|
'00000010000000042006b0200000004000000010000000042000c010000004842'
|
||||||
|
'00230100000040420024050000000400000001000000004200250100000028420'
|
||||||
|
'099070000000a4b6d6970436c69656e740000000000004200a10700000006436f'
|
||||||
|
'75636f75000042000d0200000004000000010000000042000f010000011842005'
|
||||||
|
'c0500000004000000010000000042007901000001004200570500000004000000'
|
||||||
|
'020000000042009101000000e8420008010000003042000a07000000174372797'
|
||||||
|
'0746f6772617068696320416c676f726974686d0042000b050000000400000003'
|
||||||
|
'00000000420008010000003042000a070000001843727970746f6772617068696'
|
||||||
|
'3205573616765204d61736b42000b02000000040000000c000000004200080100'
|
||||||
|
'00003042000a070000001443727970746f67726170686963204c656e677468000'
|
||||||
|
'0000042000b02000000040000008000000000420008010000003842000a070000'
|
||||||
|
'00044e616d650000000042000b0100000020420055070000000854657374204b6'
|
||||||
|
'57942005405000000040000000100000000')
|
||||||
|
response = hex2bin(
|
||||||
|
'42007b01000000e042007a0100000048420069010000002042006a02000000040'
|
||||||
|
'00000010000000042006b02000000040000000100000000420092090000000800'
|
||||||
|
'00000056c488d742000d0200000004000000010000000042000f0100000088420'
|
||||||
|
'05c0500000004000000010000000042007f050000000400000000000000004200'
|
||||||
|
'7c010000006042005705000000040000000200000000420094070000000131000'
|
||||||
|
'000000000004200910100000038420008010000003042000a0700000011556e69'
|
||||||
|
'717565204964656e7469666965720000000000000042000b07000000013100000'
|
||||||
|
'000000000')
|
||||||
|
|
||||||
|
self._integration_test_process(request, response)
|
Loading…
Reference in New Issue