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 ResultReason
|
||||
from kmip.core.messages.contents import ResultMessage
|
||||
from kmip.core.messages.contents import ProtocolVersion
|
||||
|
||||
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 RegisterResult
|
||||
from kmip.services.results import LocateResult
|
||||
from kmip.services.results import DiscoverVersionsResult
|
||||
|
||||
|
||||
class KMIP(object):
|
||||
|
@ -85,6 +87,9 @@ class KMIP(object):
|
|||
credential=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
def discover_versions(self, protocol_versions=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class KMIPImpl(KMIP):
|
||||
|
||||
|
@ -95,6 +100,10 @@ class KMIPImpl(KMIP):
|
|||
self.secret_factory = SecretFactory()
|
||||
self.attribute_factory = AttributeFactory()
|
||||
self.repo = MemRepo()
|
||||
self.protocol_versions = [
|
||||
ProtocolVersion.create(1, 1),
|
||||
ProtocolVersion.create(1, 0)
|
||||
]
|
||||
|
||||
def create(self, object_type, template_attribute, credential=None):
|
||||
self.logger.debug('create() called')
|
||||
|
@ -279,6 +288,32 @@ class KMIPImpl(KMIP):
|
|||
return LocateResult(ResultStatus(RS.OPERATION_FAILED),
|
||||
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):
|
||||
self.logger.debug('Validating attribute %s' % name)
|
||||
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.register import RegisterResponsePayload
|
||||
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 ResultStatus as RS
|
||||
|
@ -173,7 +175,10 @@ class Processor(object):
|
|||
return self._process_register_request(payload)
|
||||
elif op is Operation.LOCATE:
|
||||
return self._process_locate_request(payload)
|
||||
elif op is Operation.DISCOVER_VERSIONS:
|
||||
return self._process_discover_versions_request(payload)
|
||||
else:
|
||||
self.logger.debug("Process operation: Not implemented")
|
||||
raise NotImplementedError()
|
||||
|
||||
def _process_create_request(self, payload):
|
||||
|
@ -276,3 +281,19 @@ class Processor(object):
|
|||
resp_pl = LocateResponsePayload(unique_identifiers=uuids)
|
||||
|
||||
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