mirror of https://github.com/OpenKMIP/PyKMIP.git
Merge pull request #259 from OpenKMIP/maint/cleanup-old-server-code
Removing deprecated server code and supporting infrastructure
This commit is contained in:
commit
5fc2e26527
|
@ -13,44 +13,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
from kmip.core.attributes import CryptographicLength
|
||||
from kmip.core.attributes import CryptographicAlgorithm
|
||||
from kmip.core.attributes import ObjectType
|
||||
from kmip.core.attributes import UniqueIdentifier
|
||||
from kmip.core.enums import AttributeType as AT
|
||||
from kmip.core.enums import CryptographicAlgorithm as CA
|
||||
from kmip.core.enums import KeyFormatType as KeyFormatTypeEnum
|
||||
from kmip.core.enums import ObjectType as OT
|
||||
from kmip.core.enums import ResultReason as ResultReasonEnum
|
||||
from kmip.core.enums import ResultStatus as RS
|
||||
from kmip.core.factories.attributes import AttributeFactory
|
||||
from kmip.core.factories.keys import KeyFactory
|
||||
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
|
||||
|
||||
from kmip.core.objects import KeyBlock
|
||||
from kmip.core.objects import KeyMaterial
|
||||
from kmip.core.objects import KeyValue
|
||||
from kmip.core.objects import TemplateAttribute
|
||||
from kmip.core.secrets import SymmetricKey
|
||||
from kmip.services.server.repo.mem_repo import MemRepo
|
||||
from kmip.services.results import CreateResult
|
||||
from kmip.services.results import DestroyResult
|
||||
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):
|
||||
|
||||
|
@ -89,334 +51,3 @@ class KMIP(object):
|
|||
|
||||
def discover_versions(self, protocol_versions=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class KMIPImpl(KMIP):
|
||||
|
||||
def __init__(self):
|
||||
super(KMIPImpl, self).__init__()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.key_factory = KeyFactory()
|
||||
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')
|
||||
self.logger.debug('object type = %s' % object_type)
|
||||
bit_length = 256
|
||||
attributes = template_attribute.attributes
|
||||
ret_attributes = []
|
||||
if object_type.value != OT.SYMMETRIC_KEY:
|
||||
self.logger.debug('invalid object type')
|
||||
return self._get_invalid_field_result('invalid object type')
|
||||
try:
|
||||
alg_attr = self._validate_req_field(
|
||||
attributes, AT.CRYPTOGRAPHIC_ALGORITHM.value,
|
||||
(CA.AES,), 'unsupported algorithm')
|
||||
len_attr = self._validate_req_field(
|
||||
attributes, AT.CRYPTOGRAPHIC_LENGTH.value,
|
||||
(128, 256, 512), 'unsupported key length', False)
|
||||
self._validate_req_field(
|
||||
attributes, AT.CRYPTOGRAPHIC_USAGE_MASK.value, (), '')
|
||||
except InvalidFieldException as e:
|
||||
self.logger.debug('InvalidFieldException raised')
|
||||
return e.result
|
||||
|
||||
crypto_alg = CryptographicAlgorithm(CA(alg_attr.attribute_value.value))
|
||||
|
||||
if len_attr is None:
|
||||
self.logger.debug('cryptographic length not supplied')
|
||||
attribute_type = AT.CRYPTOGRAPHIC_LENGTH
|
||||
length_attribute = self.attribute_factory.\
|
||||
create_attribute(attribute_type, bit_length)
|
||||
attributes.append(length_attribute)
|
||||
ret_attributes.append(length_attribute)
|
||||
else:
|
||||
bit_length = len_attr.attribute_value.value
|
||||
|
||||
key = self._gen_symmetric_key(bit_length, crypto_alg)
|
||||
s_uuid, uuid_attribute = self._save(key, attributes)
|
||||
ret_attributes.append(uuid_attribute)
|
||||
template_attribute = TemplateAttribute(attributes=ret_attributes)
|
||||
return CreateResult(ResultStatus(RS.SUCCESS), object_type=object_type,
|
||||
uuid=UniqueIdentifier(s_uuid),
|
||||
template_attribute=template_attribute)
|
||||
|
||||
def create_key_pair(self, common_template_attribute,
|
||||
private_key_template_attribute,
|
||||
public_key_template_attribute):
|
||||
raise NotImplementedError()
|
||||
|
||||
def register(self, object_type, template_attribute, secret,
|
||||
credential=None):
|
||||
self.logger.debug('register() called')
|
||||
self.logger.debug('object type = %s' % object_type)
|
||||
attributes = template_attribute.attributes
|
||||
ret_attributes = []
|
||||
if object_type is None:
|
||||
self.logger.debug('invalid object type')
|
||||
return self._get_missing_field_result('object type')
|
||||
if object_type.value != OT.SYMMETRIC_KEY:
|
||||
self.logger.debug('invalid object type')
|
||||
return self._get_invalid_field_result('invalid object type')
|
||||
if secret is None or not isinstance(secret, SymmetricKey):
|
||||
msg = 'object type does not match that of secret'
|
||||
self.logger.debug(msg)
|
||||
return self._get_invalid_field_result(msg)
|
||||
|
||||
self.logger.debug('Collecting all attributes')
|
||||
if attributes is None:
|
||||
attributes = []
|
||||
attributes.extend(self._get_key_block_attributes(secret.key_block))
|
||||
|
||||
self.logger.debug('Verifying all attributes are valid and set')
|
||||
try:
|
||||
self._validate_req_field(
|
||||
attributes, AT.CRYPTOGRAPHIC_ALGORITHM.value, (CA.AES,),
|
||||
'unsupported algorithm')
|
||||
self._validate_req_field(
|
||||
attributes, AT.CRYPTOGRAPHIC_LENGTH.value, (128, 256, 512),
|
||||
'unsupported key length')
|
||||
self._validate_req_field(
|
||||
attributes, AT.CRYPTOGRAPHIC_USAGE_MASK.value, (), '')
|
||||
except InvalidFieldException as e:
|
||||
self.logger.debug('InvalidFieldException raised')
|
||||
return RegisterResult(e.result.result_status,
|
||||
e.result.result_reason,
|
||||
e.result.result_message)
|
||||
|
||||
s_uuid, uuid_attribute = self._save(secret, attributes)
|
||||
ret_attributes.append(uuid_attribute)
|
||||
template_attribute = TemplateAttribute(attributes=ret_attributes)
|
||||
return RegisterResult(ResultStatus(RS.SUCCESS),
|
||||
uuid=UniqueIdentifier(s_uuid),
|
||||
template_attribute=template_attribute)
|
||||
|
||||
def rekey_key_pair(self, private_key_unique_identifier,
|
||||
offset, common_template_attribute,
|
||||
private_key_template_attribute,
|
||||
public_key_template_attribute):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get(self,
|
||||
uuid=None,
|
||||
key_format_type=None,
|
||||
key_compression_type=None,
|
||||
key_wrapping_specification=None,
|
||||
credential=None):
|
||||
self.logger.debug('get() called')
|
||||
ret_value = RS.OPERATION_FAILED
|
||||
if uuid is None or not hasattr(uuid, 'value'):
|
||||
self.logger.debug('no uuid provided')
|
||||
reason = ResultReason(ResultReasonEnum.ITEM_NOT_FOUND)
|
||||
message = ResultMessage('')
|
||||
return GetResult(ResultStatus(ret_value), reason, message)
|
||||
if key_format_type is None:
|
||||
self.logger.debug('key format type is None, setting to raw')
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
if key_format_type.value != KeyFormatTypeEnum.RAW:
|
||||
self.logger.debug('key format type is not raw')
|
||||
reason = ResultReason(ResultReasonEnum.
|
||||
KEY_FORMAT_TYPE_NOT_SUPPORTED)
|
||||
message = ResultMessage('')
|
||||
return GetResult(ResultStatus(ret_value), reason, message)
|
||||
if key_compression_type is not None:
|
||||
self.logger.debug('key compression type is not None')
|
||||
reason = ResultReason(ResultReasonEnum.
|
||||
KEY_COMPRESSION_TYPE_NOT_SUPPORTED)
|
||||
message = ResultMessage('')
|
||||
return GetResult(ResultStatus(ret_value), reason, message)
|
||||
if key_wrapping_specification is not None:
|
||||
self.logger.debug('key wrapping specification is not None')
|
||||
reason = ResultReason(ResultReasonEnum.FEATURE_NOT_SUPPORTED)
|
||||
message = ResultMessage('key wrapping is not currently supported')
|
||||
return GetResult(ResultStatus(ret_value), reason, message)
|
||||
|
||||
self.logger.debug('retrieving object from repo')
|
||||
managed_object, _ = self.repo.get(uuid.value)
|
||||
|
||||
if managed_object is None:
|
||||
self.logger.debug('object not found in repo')
|
||||
reason = ResultReason(ResultReasonEnum.ITEM_NOT_FOUND)
|
||||
message = ResultMessage('')
|
||||
return GetResult(ResultStatus(ret_value), reason, message)
|
||||
|
||||
# currently only symmetric keys are supported, fix this in future
|
||||
object_type = ObjectType(OT.SYMMETRIC_KEY)
|
||||
ret_value = RS.SUCCESS
|
||||
return GetResult(ResultStatus(ret_value), object_type=object_type,
|
||||
uuid=uuid, secret=managed_object)
|
||||
|
||||
def destroy(self, uuid):
|
||||
self.logger.debug('destroy() called')
|
||||
ret_value = RS.OPERATION_FAILED
|
||||
if uuid is None or not hasattr(uuid, 'value'):
|
||||
self.logger.debug('no uuid provided')
|
||||
reason = ResultReason(ResultReasonEnum.ITEM_NOT_FOUND)
|
||||
message = ResultMessage('')
|
||||
return DestroyResult(ResultStatus(ret_value), reason, message)
|
||||
|
||||
msg = 'deleting object from repo: {0}'.format(uuid)
|
||||
self.logger.debug(msg)
|
||||
if not self.repo.delete(uuid.value):
|
||||
self.logger.debug('repo did not find and delete managed object')
|
||||
reason = ResultReason(ResultReasonEnum.ITEM_NOT_FOUND)
|
||||
message = ResultMessage('')
|
||||
return DestroyResult(ResultStatus(ret_value), reason, message)
|
||||
|
||||
ret_value = RS.SUCCESS
|
||||
return DestroyResult(ResultStatus(ret_value), uuid=uuid)
|
||||
|
||||
def locate(self, maximum_items=None, storage_status_mask=None,
|
||||
object_group_member=None, attributes=None,
|
||||
credential=None):
|
||||
self.logger.debug('locate() called')
|
||||
msg = 'locating object(s) from repo'
|
||||
self.logger.debug(msg)
|
||||
try:
|
||||
uuids = self.repo.locate(maximum_items, storage_status_mask,
|
||||
object_group_member, attributes)
|
||||
return LocateResult(ResultStatus(RS.SUCCESS), uuids=uuids)
|
||||
except NotImplementedError:
|
||||
msg = ResultMessage('Locate Operation Not Supported')
|
||||
reason = ResultReason(ResultReasonEnum.OPERATION_NOT_SUPPORTED)
|
||||
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
|
||||
found_attr = None
|
||||
for attr in attrs:
|
||||
if self._validate_field(attr, name, expected, msg):
|
||||
if seen:
|
||||
# TODO check what spec says to do on this
|
||||
msg = 'duplicate attribute: %s' % name
|
||||
self.logger.debug(msg)
|
||||
result = self._get_duplicate_attribute_result(name)
|
||||
raise InvalidFieldException(result)
|
||||
seen = True
|
||||
found_attr = attr
|
||||
if required and not seen:
|
||||
result = self._get_missing_field_result(name)
|
||||
raise InvalidFieldException(result)
|
||||
return found_attr
|
||||
|
||||
def _validate_field(self, attr, name, expected, msg):
|
||||
if attr.attribute_name.value == name:
|
||||
self.logger.debug('validating attribute %s' % name)
|
||||
if not expected or attr.attribute_value.value in expected:
|
||||
self.logger.debug('attribute validated')
|
||||
return True
|
||||
else:
|
||||
self.logger.debug('attribute not validated')
|
||||
result = self._get_invalid_field_result(msg)
|
||||
raise InvalidFieldException(result)
|
||||
else:
|
||||
return False
|
||||
|
||||
def _get_invalid_field_result(self, msg):
|
||||
status = ResultStatus(RS.OPERATION_FAILED)
|
||||
reason = ResultReason(ResultReasonEnum.INVALID_FIELD)
|
||||
message = ResultMessage(msg)
|
||||
return OperationResult(status, reason, message)
|
||||
|
||||
def _get_missing_field_result(self, name):
|
||||
msg = '%s not supplied' % name
|
||||
self.logger.debug(msg)
|
||||
status = ResultStatus(RS.OPERATION_FAILED)
|
||||
reason = ResultReason(ResultReasonEnum.ITEM_NOT_FOUND)
|
||||
message = ResultMessage(msg)
|
||||
return OperationResult(status, reason, message)
|
||||
|
||||
def _get_duplicate_attribute_result(self, name):
|
||||
msg = '%s supplied multiple times' % name
|
||||
self.logger.debug(msg)
|
||||
status = ResultStatus(RS.OPERATION_FAILED)
|
||||
reason = ResultReason(ResultReasonEnum.INDEX_OUT_OF_BOUNDS)
|
||||
message = ResultMessage(msg)
|
||||
return OperationResult(status, reason, message)
|
||||
|
||||
def _gen_symmetric_key(self, bit_length, crypto_alg):
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
key_material = KeyMaterial(os.urandom(int(bit_length/8)))
|
||||
key_value = KeyValue(key_material)
|
||||
crypto_length = CryptographicLength(bit_length)
|
||||
key_block = KeyBlock(key_format_type, None, key_value, crypto_alg,
|
||||
crypto_length, None)
|
||||
return SymmetricKey(key_block)
|
||||
|
||||
def _save(self, key, attributes):
|
||||
s_uuid = self.repo.save(key, attributes)
|
||||
self.logger.debug('creating object with uuid = %s' % s_uuid)
|
||||
attribute_type = AT.UNIQUE_IDENTIFIER
|
||||
attribute = self.attribute_factory.create_attribute(attribute_type,
|
||||
s_uuid)
|
||||
attributes.append(attribute)
|
||||
# Calling update to also store the UUID
|
||||
self.repo.update(s_uuid, key, attributes)
|
||||
return s_uuid, attribute
|
||||
|
||||
def _get_key_block_attributes(self, key_block):
|
||||
self.logger.debug('getting all key attributes from key block')
|
||||
attributes = []
|
||||
if key_block.cryptographic_algorithm is not None:
|
||||
self.logger.debug('crypto_alg set on key block')
|
||||
self.logger.debug('adding crypto algorithm attribute')
|
||||
at = AT.CRYPTOGRAPHIC_ALGORITHM
|
||||
alg = key_block.cryptographic_algorithm.value
|
||||
attributes.append(self.attribute_factory.create_attribute(at, alg))
|
||||
if key_block.cryptographic_length is not None:
|
||||
self.logger.debug('crypto_length set on key block')
|
||||
self.logger.debug('adding crypto length attribute')
|
||||
at = AT.CRYPTOGRAPHIC_LENGTH
|
||||
len = key_block.cryptographic_length.value
|
||||
attributes.append(self.attribute_factory.create_attribute(at, len))
|
||||
self.logger.debug('getting key value attributes')
|
||||
if key_block.key_wrapping_data is not None:
|
||||
self.logger.debug('no wrapping data so key value is struct')
|
||||
kv = key_block.key_value
|
||||
if isinstance(kv, KeyValue):
|
||||
kv = key_block.key_value
|
||||
if kv.attributes is not None:
|
||||
self.logger.debug('adding the key value struct attributes')
|
||||
attributes.extend(kv.attributes)
|
||||
return attributes
|
||||
|
||||
|
||||
class InvalidFieldException(Exception):
|
||||
|
||||
def __init__(self, result):
|
||||
super(InvalidFieldException, self).__init__()
|
||||
self.result = result
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
# Copyright (c) 2014 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 logging
|
||||
import os
|
||||
import socket
|
||||
import ssl
|
||||
import warnings
|
||||
|
||||
from kmip.core.config_helper import ConfigHelper
|
||||
from kmip.core.server import KMIPImpl
|
||||
|
||||
from kmip.services.server.kmip_protocol import KMIPProtocolFactory
|
||||
from kmip.services.server.processor import Processor
|
||||
|
||||
FILE_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
class KMIPServer(object):
|
||||
|
||||
def __init__(self, host=None, port=None, keyfile=None, certfile=None,
|
||||
cert_reqs=None, ssl_version=None, ca_certs=None,
|
||||
do_handshake_on_connect=None, suppress_ragged_eofs=None):
|
||||
warnings.simplefilter("always")
|
||||
warnings.warn((
|
||||
"Please use the newer KmipServer located in kmip.services.server. "
|
||||
"This version of the server will be deprecated in the future."),
|
||||
PendingDeprecationWarning
|
||||
)
|
||||
warnings.simplefilter("default")
|
||||
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
self._set_variables(host, port, keyfile, certfile, cert_reqs,
|
||||
ssl_version, ca_certs, do_handshake_on_connect,
|
||||
suppress_ragged_eofs)
|
||||
|
||||
handler = KMIPImpl()
|
||||
self._processor = Processor(handler)
|
||||
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.socket.bind((self.host, self.port))
|
||||
|
||||
def close(self):
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
self.socket.close()
|
||||
|
||||
def serve(self):
|
||||
self.socket.listen(0)
|
||||
while True:
|
||||
connection, address = self.socket.accept()
|
||||
self.logger.info("Connected by {0}".format(address))
|
||||
connection = ssl.wrap_socket(
|
||||
connection,
|
||||
keyfile=self.keyfile,
|
||||
certfile=self.certfile,
|
||||
server_side=True,
|
||||
cert_reqs=self.cert_reqs,
|
||||
ssl_version=self.ssl_version,
|
||||
ca_certs=self.ca_certs,
|
||||
do_handshake_on_connect=self.do_handshake_on_connect,
|
||||
suppress_ragged_eofs=self.suppress_ragged_eofs)
|
||||
|
||||
factory = KMIPProtocolFactory()
|
||||
protocol = factory.getProtocol(connection)
|
||||
|
||||
try:
|
||||
while True:
|
||||
self._processor.process(protocol, protocol)
|
||||
except EOFError as e:
|
||||
self.logger.warning("KMIPServer {0} {1}".format(type(e), e))
|
||||
except Exception as e:
|
||||
self.logger.error('KMIPServer {0} {1}'.format(type(e), e))
|
||||
finally:
|
||||
connection.close()
|
||||
self.logger.info('Connection closed')
|
||||
|
||||
def _set_variables(self, host, port, keyfile, certfile, cert_reqs,
|
||||
ssl_version, ca_certs, do_handshake_on_connect,
|
||||
suppress_ragged_eofs):
|
||||
conf = ConfigHelper()
|
||||
self.host = conf.get_valid_value(host, 'server',
|
||||
'host', conf.DEFAULT_HOST)
|
||||
self.port = int(conf.get_valid_value(port, 'server',
|
||||
'port', conf.DEFAULT_PORT))
|
||||
self.keyfile = conf.get_valid_value(
|
||||
keyfile, 'server', 'keyfile', conf.DEFAULT_KEYFILE)
|
||||
|
||||
self.certfile = conf.get_valid_value(
|
||||
certfile, 'server', 'certfile', conf.DEFAULT_CERTFILE)
|
||||
|
||||
self.cert_reqs = getattr(ssl, conf.get_valid_value(
|
||||
cert_reqs, 'server', 'cert_reqs', 'CERT_NONE'))
|
||||
|
||||
self.ssl_version = getattr(ssl, conf.get_valid_value(
|
||||
ssl_version, 'server', 'ssl_version', conf.DEFAULT_SSL_VERSION))
|
||||
|
||||
self.ca_certs = conf.get_valid_value(
|
||||
ca_certs, 'server', 'ca_certs', None)
|
||||
|
||||
if conf.get_valid_value(
|
||||
do_handshake_on_connect, 'server',
|
||||
'do_handshake_on_connect', 'True') == 'True':
|
||||
self.do_handshake_on_connect = True
|
||||
else:
|
||||
self.do_handshake_on_connect = False
|
||||
|
||||
if conf.get_valid_value(
|
||||
suppress_ragged_eofs, 'server',
|
||||
'suppress_ragged_eofs', 'True') == 'True':
|
||||
self.suppress_ragged_eofs = True
|
||||
else:
|
||||
self.suppress_ragged_eofs = False
|
|
@ -1,299 +0,0 @@
|
|||
# Copyright (c) 2014 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 logging
|
||||
import time
|
||||
|
||||
from kmip.core.messages.messages import RequestMessage
|
||||
from kmip.core.messages.messages import ResponseMessage
|
||||
from kmip.core.messages.messages import ResponseBatchItem
|
||||
from kmip.core.messages.messages import ResponseHeader
|
||||
|
||||
from kmip.core.messages.contents import AsynchronousIndicator
|
||||
from kmip.core.messages.contents import BatchErrorContinuationOption
|
||||
from kmip.core.messages.contents import BatchCount
|
||||
from kmip.core.messages.contents import TimeStamp
|
||||
|
||||
from kmip.core.primitives import Base
|
||||
|
||||
from kmip.core.messages.payloads.create import CreateResponsePayload
|
||||
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
|
||||
from kmip.core.enums import Tags
|
||||
from kmip.core.enums import BatchErrorContinuationOption as BECO
|
||||
|
||||
from kmip.core.utils import BytearrayStream
|
||||
|
||||
|
||||
class Processor(object):
|
||||
def __init__(self, handler):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self._handler = handler
|
||||
|
||||
def process(self, istream, ostream):
|
||||
stream = istream.read()
|
||||
|
||||
if Base.is_tag_next(Tags.REQUEST_MESSAGE, stream):
|
||||
message = RequestMessage()
|
||||
message.read(stream)
|
||||
try:
|
||||
result = self._process_request(message)
|
||||
except Exception as e:
|
||||
raise e
|
||||
tstream = BytearrayStream()
|
||||
result.write(tstream)
|
||||
ostream.write(tstream.buffer)
|
||||
elif Base.is_tag_next(Tags.RESPONSE_MESSAGE, stream):
|
||||
message = ResponseMessage()
|
||||
message.read(stream)
|
||||
self._process_response(message)
|
||||
else:
|
||||
raise ValueError('Processing error: stream contains unknown '
|
||||
'message type')
|
||||
|
||||
def _process_request(self, message):
|
||||
header = message.request_header
|
||||
|
||||
protocol_version = header.protocol_version
|
||||
# maximum_response_size = header.maximum_response_size
|
||||
asynchronous_indicator = header.asynchronous_indicator
|
||||
# authentication = header.authentication
|
||||
batch_error_cont_option = header.batch_error_cont_option
|
||||
# batch_order_option = header.batch_order_option
|
||||
# time_stamp = header.time_stamp
|
||||
request_batch_count = header.batch_count.value
|
||||
|
||||
# TODO (peter-hamilton) Log receipt of message with time stamp
|
||||
|
||||
if asynchronous_indicator is None:
|
||||
asynchronous_indicator = AsynchronousIndicator(False)
|
||||
|
||||
if batch_error_cont_option is None:
|
||||
batch_error_cont_option = BatchErrorContinuationOption(BECO.STOP)
|
||||
|
||||
request_batch_items = message.batch_items
|
||||
response_batch_items = []
|
||||
|
||||
for i in range(request_batch_count):
|
||||
request_batch_item = request_batch_items[i]
|
||||
failure_occurred = False
|
||||
|
||||
operation = request_batch_item.operation
|
||||
ubi_id = request_batch_item.unique_batch_item_id
|
||||
payload = request_batch_item.request_payload
|
||||
message_extension = request_batch_item.message_extension
|
||||
|
||||
result = self._process_operation(operation, payload)
|
||||
|
||||
result_status = result[0]
|
||||
result_reason = result[1]
|
||||
result_message = result[2]
|
||||
asyn_cv = None
|
||||
response_payload = None
|
||||
message_extension = None
|
||||
|
||||
if result_status.value is RS.SUCCESS:
|
||||
response_payload = result[3]
|
||||
elif result_status.value is RS.OPERATION_FAILED:
|
||||
failure_occurred = True
|
||||
result_reason = result[1]
|
||||
elif result_status.value is RS.OPERATION_PENDING:
|
||||
# TODO (peter-hamilton) Need to add a way to track async
|
||||
# TODO (peter-hamilton) operations.
|
||||
asyn_cv = b'\x00'
|
||||
elif result_status.value is RS.OPERATION_UNDONE:
|
||||
result_reason = result[1]
|
||||
else:
|
||||
msg = 'Unrecognized operation result status: {0}'
|
||||
raise RuntimeError(msg.format(result_status))
|
||||
|
||||
resp_bi = ResponseBatchItem(operation=operation,
|
||||
unique_batch_item_id=ubi_id,
|
||||
result_status=result_status,
|
||||
result_reason=result_reason,
|
||||
result_message=result_message,
|
||||
async_correlation_value=asyn_cv,
|
||||
response_payload=response_payload,
|
||||
message_extension=message_extension)
|
||||
response_batch_items.append(resp_bi)
|
||||
|
||||
if failure_occurred:
|
||||
if batch_error_cont_option.value is BECO.STOP:
|
||||
break
|
||||
elif batch_error_cont_option.value is BECO.UNDO:
|
||||
# TODO (peter-hamilton) Tell client to undo operations.
|
||||
# TODO (peter-hamilton) Unclear what response should be.
|
||||
break
|
||||
elif batch_error_cont_option.value is BECO.CONTINUE:
|
||||
continue
|
||||
else:
|
||||
msg = 'Unrecognized batch error continuation option: {0}'
|
||||
raise RuntimeError(msg.format(batch_error_cont_option))
|
||||
|
||||
response_batch_count = BatchCount(len(response_batch_items))
|
||||
response_time_stamp = TimeStamp(int(time.time()))
|
||||
response_header = ResponseHeader(protocol_version=protocol_version,
|
||||
time_stamp=response_time_stamp,
|
||||
batch_count=response_batch_count)
|
||||
|
||||
response_message = ResponseMessage(response_header=response_header,
|
||||
batch_items=response_batch_items)
|
||||
return response_message
|
||||
|
||||
def _process_response(self, message):
|
||||
raise NotImplementedError()
|
||||
|
||||
def _process_operation(self, operation, payload):
|
||||
op = operation.value
|
||||
|
||||
if op is Operation.CREATE:
|
||||
return self._process_create_request(payload)
|
||||
elif op is Operation.GET:
|
||||
return self._process_get_request(payload)
|
||||
elif op is Operation.DESTROY:
|
||||
return self._process_destroy_request(payload)
|
||||
elif op is Operation.REGISTER:
|
||||
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):
|
||||
object_type = payload.object_type
|
||||
template_attribute = payload.template_attribute
|
||||
result = self._handler.create(object_type, template_attribute)
|
||||
|
||||
result_status = result.result_status
|
||||
result_reason = result.result_reason
|
||||
result_message = result.result_message
|
||||
created_type = result.object_type
|
||||
uuid = result.uuid
|
||||
template_attribute = result.template_attribute
|
||||
|
||||
resp_pl = CreateResponsePayload(object_type=created_type,
|
||||
unique_identifier=uuid,
|
||||
template_attribute=template_attribute)
|
||||
|
||||
return (result_status, result_reason, result_message, resp_pl)
|
||||
|
||||
def _process_get_request(self, payload):
|
||||
uuid = None
|
||||
kft = None
|
||||
kct = None
|
||||
|
||||
unique_identifier = payload.unique_identifier
|
||||
key_format_type = payload.key_format_type
|
||||
key_compression_type = payload.key_compression_type
|
||||
key_wrapping_specification = payload.key_wrapping_specification
|
||||
|
||||
if unique_identifier is not None:
|
||||
uuid = unique_identifier
|
||||
if key_format_type is not None:
|
||||
kft = key_format_type
|
||||
if key_compression_type is not None:
|
||||
kct = key_compression_type
|
||||
|
||||
result = self._handler.get(uuid, kft, kct,
|
||||
key_wrapping_specification)
|
||||
|
||||
result_status = result.result_status
|
||||
result_reason = result.result_reason
|
||||
result_message = result.result_message
|
||||
retrieved_type = result.object_type
|
||||
uuid = result.uuid
|
||||
secret = result.secret
|
||||
|
||||
resp_pl = GetResponsePayload(object_type=retrieved_type,
|
||||
unique_identifier=uuid,
|
||||
secret=secret)
|
||||
|
||||
return (result_status, result_reason, result_message, resp_pl)
|
||||
|
||||
def _process_destroy_request(self, payload):
|
||||
uuid = payload.unique_identifier
|
||||
result = self._handler.destroy(uuid)
|
||||
|
||||
result_status = result.result_status
|
||||
result_reason = result.result_reason
|
||||
result_message = result.result_message
|
||||
uuid = result.uuid
|
||||
|
||||
payload = DestroyResponsePayload(unique_identifier=uuid)
|
||||
|
||||
return (result_status, result_reason, result_message, payload)
|
||||
|
||||
def _process_register_request(self, payload):
|
||||
object_type = payload.object_type
|
||||
template_attribute = payload.template_attribute
|
||||
secret = payload.secret
|
||||
result = self._handler.register(object_type, template_attribute,
|
||||
secret)
|
||||
|
||||
result_status = result.result_status
|
||||
result_reason = result.result_reason
|
||||
result_message = result.result_message
|
||||
uuid = result.uuid
|
||||
template_attr = result.template_attribute
|
||||
|
||||
resp_pl = RegisterResponsePayload(unique_identifier=uuid,
|
||||
template_attribute=template_attr)
|
||||
|
||||
return (result_status, result_reason, result_message, resp_pl)
|
||||
|
||||
def _process_locate_request(self, payload):
|
||||
max_items = payload.maximum_items
|
||||
storage_mask = payload.storage_status_mask
|
||||
objgrp_member = payload.object_group_member
|
||||
attributes = payload.attributes
|
||||
|
||||
result = self._handler.locate(max_items, storage_mask,
|
||||
objgrp_member, attributes)
|
||||
|
||||
result_status = result.result_status
|
||||
result_reason = result.result_reason
|
||||
result_message = result.result_message
|
||||
|
||||
uuids = result.uuids
|
||||
|
||||
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)
|
|
@ -1,14 +0,0 @@
|
|||
# Copyright (c) 2014 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.
|
|
@ -1,51 +0,0 @@
|
|||
# Copyright (c) 2014 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.
|
||||
|
||||
from kmip.services.server.repo.repo import ManagedObjectRepo
|
||||
|
||||
|
||||
class MemRepo(ManagedObjectRepo):
|
||||
|
||||
def __init__(self):
|
||||
self.repo = {}
|
||||
self.uuid = 1
|
||||
|
||||
def save(self, managed_object, attributes):
|
||||
# TODO (nate) verify the parameters
|
||||
uuid = "{0}".format(self.uuid)
|
||||
self.repo[uuid] = (managed_object, attributes)
|
||||
self.uuid += 1
|
||||
return uuid
|
||||
|
||||
def get(self, uuid):
|
||||
if uuid is None or uuid not in self.repo:
|
||||
return (None, None)
|
||||
return self.repo[uuid]
|
||||
|
||||
def update(self, uuid, managed_object, attributes):
|
||||
if uuid is None:
|
||||
return False
|
||||
self.repo[uuid] = (managed_object, attributes)
|
||||
return True
|
||||
|
||||
def delete(self, uuid):
|
||||
if uuid is None or uuid not in self.repo:
|
||||
return False
|
||||
del self.repo[uuid]
|
||||
return True
|
||||
|
||||
def locate(self, maximum_items, storage_status_mask,
|
||||
object_group_member, attributes):
|
||||
raise NotImplementedError
|
|
@ -1,73 +0,0 @@
|
|||
# Copyright (c) 2014 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.
|
||||
|
||||
|
||||
class ManagedObjectRepo(object):
|
||||
"""Stores and manages KMIP managed objects.
|
||||
|
||||
The KMIP specification details the managed objects that are stored by a
|
||||
KMIP server. This repository abstraction is an interface for KMIP servers
|
||||
to store managed objects.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def save(self, managed_object, attributes):
|
||||
"""Save a managed object
|
||||
|
||||
This saves a managed object into the repository and returns a UUID
|
||||
string that can be used to reference the object in the repository.
|
||||
:param managed_object: managed object to save from secrets.py
|
||||
:param attributes: attributes to store with the managed object
|
||||
:returns: a UUID string that can be used to retrieve the object later
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get(self, uuid):
|
||||
"""Retrieve a managed object
|
||||
|
||||
Retrieve a managed object from the repository. The UUID is used to
|
||||
identify the managed object to return. The UUID is returned from the
|
||||
save call.
|
||||
|
||||
A tuple is returned that contains the managed object and all of its
|
||||
attributes.
|
||||
:param uuid: UUID of the managed object
|
||||
:returns: (managed_object, attributes) if object exists, otherwise
|
||||
(None, None)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def update(self, uuid, managed_object, attributes):
|
||||
"""Updates a managed object
|
||||
|
||||
Updates the values for a managed_object.
|
||||
:param uuid: UUID of the managed object
|
||||
:param managed_object: managed object
|
||||
:param attributes: attributes to store with the managed object
|
||||
:returns: True if object existed and successfully updated, otherwise
|
||||
False
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def delete(self, uuid):
|
||||
"""Delete a managed object from the repository
|
||||
|
||||
Delete a managed object from the repository.
|
||||
:param uuid: UUID of the managed object
|
||||
:returns: True if successfully deleted, False if not found
|
||||
"""
|
||||
raise NotImplementedError
|
|
@ -1,96 +0,0 @@
|
|||
# Copyright (c) 2014 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 logging
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
from kmip.core.config_helper import ConfigHelper
|
||||
|
||||
from kmip.services.server.kmip_server import KMIPServer
|
||||
|
||||
FILE_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def run_server(host, port, certfile, keyfile, cert_reqs, ssl_version,
|
||||
ca_certs, do_handshake_on_connect, suppress_ragged_eofs):
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
server = KMIPServer(host=host, port=port, keyfile=keyfile,
|
||||
certfile=certfile, cert_reqs=cert_reqs,
|
||||
ssl_version=ssl_version, ca_certs=ca_certs,
|
||||
do_handshake_on_connect=do_handshake_on_connect,
|
||||
suppress_ragged_eofs=suppress_ragged_eofs)
|
||||
|
||||
logger.info('Starting the KMIP server')
|
||||
|
||||
try:
|
||||
server.serve()
|
||||
except KeyboardInterrupt:
|
||||
logger.info('KeyboardInterrupt received while serving')
|
||||
except Exception as e:
|
||||
logger.info('Exception received while serving: {0}'.format(e))
|
||||
finally:
|
||||
server.close()
|
||||
|
||||
logger.info('Shutting down KMIP server')
|
||||
|
||||
|
||||
def build_cli_parser():
|
||||
parser = optparse.OptionParser(usage="%prog [options]",
|
||||
description="Run KMIP Server")
|
||||
parser.add_option("-n", "--host", action="store", default='127.0.0.1',
|
||||
dest="host",
|
||||
help="Hostname/IP address of platform running the KMIP "
|
||||
"server (e.g., localhost, 127.0.0.1)")
|
||||
parser.add_option("-p", "--port", action="store", default=5696,
|
||||
dest="port", help="Port number for KMIP services")
|
||||
parser.add_option("-k", "--keyfile", action="store",
|
||||
default=os.path.normpath(os.path.join(
|
||||
FILE_PATH, '../utils/certs/server.key')),
|
||||
dest="keyfile")
|
||||
parser.add_option("-c", "--certfile", action="store",
|
||||
default=os.path.normpath(os.path.join(
|
||||
FILE_PATH, '../utils/certs/server.crt')),
|
||||
dest="certfile")
|
||||
parser.add_option("-r", "--cert_reqs", action="store",
|
||||
default="CERT_NONE", dest="cert_reqs")
|
||||
parser.add_option("-s", "--ssl_version", action="store",
|
||||
default='PROTOCOL_SSLv23', dest="ssl_version")
|
||||
parser.add_option("-a", "--ca_certs", action="store",
|
||||
default=ConfigHelper.NONE_VALUE, dest="ca_certs")
|
||||
parser.add_option("-d", "--do_handshake_on_connect", action="store",
|
||||
default="True", dest="do_handshake_on_connect")
|
||||
parser.add_option("-e", "--suppress_ragged_eofs", action="store",
|
||||
default="True", dest="suppress_ragged_eofs")
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = build_cli_parser()
|
||||
|
||||
opts, args = parser.parse_args(sys.argv[1:])
|
||||
|
||||
run_server(host=opts.host,
|
||||
port=opts.port,
|
||||
certfile=opts.certfile,
|
||||
keyfile=opts.keyfile,
|
||||
cert_reqs=opts.cert_reqs,
|
||||
ssl_version=opts.ssl_version,
|
||||
ca_certs=opts.ca_certs,
|
||||
do_handshake_on_connect=opts.do_handshake_on_connect,
|
||||
suppress_ragged_eofs=opts.suppress_ragged_eofs)
|
|
@ -1,542 +0,0 @@
|
|||
# Copyright (c) 2014 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.
|
||||
|
||||
from testtools import TestCase
|
||||
|
||||
from kmip.core.attributes import CryptographicAlgorithm
|
||||
from kmip.core.attributes import CryptographicLength
|
||||
from kmip.core.attributes import CryptographicUsageMask
|
||||
from kmip.core.attributes import UniqueIdentifier
|
||||
from kmip.core.attributes import ObjectType
|
||||
from kmip.core.attributes import Name
|
||||
|
||||
from kmip.core.enums import AttributeType
|
||||
from kmip.core.enums import CryptographicAlgorithm as CryptoAlgorithmEnum
|
||||
from kmip.core.enums import CryptographicUsageMask as CryptoUsageMaskEnum
|
||||
from kmip.core.enums import KeyCompressionType as KeyCompressionTypeEnum
|
||||
from kmip.core.enums import KeyFormatType as KeyFormatTypeEnum
|
||||
from kmip.core.enums import ObjectType as ObjectTypeEnum
|
||||
from kmip.core.enums import ResultReason
|
||||
from kmip.core.enums import ResultStatus
|
||||
from kmip.core.enums import NameType
|
||||
|
||||
from kmip.core.factories.attributes import AttributeFactory
|
||||
|
||||
from kmip.core.messages.contents import KeyCompressionType
|
||||
from kmip.core.misc import KeyFormatType
|
||||
|
||||
from kmip.core.objects import KeyBlock
|
||||
from kmip.core.objects import KeyMaterial
|
||||
from kmip.core.objects import KeyValue
|
||||
from kmip.core.objects import TemplateAttribute
|
||||
|
||||
from kmip.core.secrets import SymmetricKey
|
||||
from kmip.core.server import KMIPImpl
|
||||
|
||||
|
||||
class TestKMIPServer(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestKMIPServer, self).setUp()
|
||||
self.kmip = KMIPImpl()
|
||||
self.algorithm_name = CryptoAlgorithmEnum.AES
|
||||
self.key_length = 256
|
||||
self.key = bytearray(range(0, 32))
|
||||
self.usage_mask = CryptoUsageMaskEnum.ENCRYPT.value |\
|
||||
CryptoUsageMaskEnum.DECRYPT.value
|
||||
|
||||
def tearDown(self):
|
||||
super(TestKMIPServer, self).tearDown()
|
||||
|
||||
def test_create(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
attributes = self._get_attrs()
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.create(obj_type, template_attribute)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
|
||||
def test_create_no_length(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
attributes = self._get_attrs()[0:2]
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.create(obj_type, template_attribute)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
attrs = res.template_attribute.attributes
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
self.assertTrue(self._check_attr_exists(attributes[2], attrs),
|
||||
'length attribute not returned')
|
||||
|
||||
def test_create_no_alg(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
attributes = [self._get_attrs()[1]]
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.create(obj_type, template_attribute)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(
|
||||
ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
|
||||
def test_create_no_usage_mask(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
attributes = [self._get_attrs()[0]]
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.create(obj_type, template_attribute)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(
|
||||
ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
|
||||
def test_register(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
|
||||
def test_register_attrs_in_key_value(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.cryptographic_algorithm = None
|
||||
key.key_block.cryptographic_length = None
|
||||
key.key_block.key_value.attributes = self._get_attrs()
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
|
||||
def test_register_attrs_in_template(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.cryptographic_algorithm = None
|
||||
key.key_block.cryptographic_length = None
|
||||
key.key_block.key_value.attributes = []
|
||||
attributes = self._get_attrs()
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
|
||||
def test_register_no_alg(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.cryptographic_algorithm = None
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.ITEM_NOT_FOUND,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_alg_in_key_value_and_key_block(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.key_value.attributes = [self._get_alg_attr()]
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INDEX_OUT_OF_BOUNDS,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_alg_in_template_and_key_block(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
attributes = [self._get_alg_attr()]
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INDEX_OUT_OF_BOUNDS,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_alg_in_template_and_key_value(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.cryptographic_algorithm = None
|
||||
key.key_block.key_value.attributes = [self._get_alg_attr()]
|
||||
attributes = [self._get_alg_attr()]
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INDEX_OUT_OF_BOUNDS,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_invalid_alg(self):
|
||||
unsupported_algs = (CryptoAlgorithmEnum.RSA,
|
||||
CryptoAlgorithmEnum.DSA,
|
||||
CryptoAlgorithmEnum.ECDSA,
|
||||
CryptoAlgorithmEnum.HMAC_SHA1,
|
||||
CryptoAlgorithmEnum.HMAC_SHA224,
|
||||
CryptoAlgorithmEnum.HMAC_SHA256,
|
||||
CryptoAlgorithmEnum.HMAC_SHA384,
|
||||
CryptoAlgorithmEnum.HMAC_SHA512,
|
||||
CryptoAlgorithmEnum.HMAC_MD5,
|
||||
CryptoAlgorithmEnum.DH,
|
||||
CryptoAlgorithmEnum.ECDH,
|
||||
CryptoAlgorithmEnum.ECMQV,
|
||||
CryptoAlgorithmEnum.BLOWFISH,
|
||||
CryptoAlgorithmEnum.CAMELLIA,
|
||||
CryptoAlgorithmEnum.CAST5,
|
||||
CryptoAlgorithmEnum.IDEA,
|
||||
CryptoAlgorithmEnum.MARS,
|
||||
CryptoAlgorithmEnum.RC2,
|
||||
CryptoAlgorithmEnum.RC4,
|
||||
CryptoAlgorithmEnum.RC5,
|
||||
CryptoAlgorithmEnum.SKIPJACK,
|
||||
CryptoAlgorithmEnum.TWOFISH)
|
||||
for alg in unsupported_algs:
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.cryptographic_algorithm = CryptographicAlgorithm(alg)
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INVALID_FIELD,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_no_length(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.cryptographic_length = None
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.ITEM_NOT_FOUND,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_length_in_key_value_and_key_block(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.key_value.attributes = [self._get_length_attr()]
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INDEX_OUT_OF_BOUNDS,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_length_in_template_and_key_block(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
attributes = [self._get_length_attr()]
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INDEX_OUT_OF_BOUNDS,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_length_in_template_and_key_value(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.cryptographic_length = None
|
||||
key.key_block.key_value.attributes = [self._get_length_attr()]
|
||||
attributes = [self._get_length_attr()]
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INDEX_OUT_OF_BOUNDS,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_invalid_length(self):
|
||||
unsupported_lens = (-1, 0, 2048, 5, 18)
|
||||
for len in unsupported_lens:
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.cryptographic_length = CryptographicLength(len)
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INVALID_FIELD,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_no_usage_mask(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
key = self._get_symmetric_key()
|
||||
key.key_block.key_value.attributes = []
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.ITEM_NOT_FOUND,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_no_object_type(self):
|
||||
obj_type = None
|
||||
key = self._get_symmetric_key()
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.ITEM_NOT_FOUND,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_unsupported_object_type(self):
|
||||
unsupported_types = (ObjectTypeEnum.CERTIFICATE,
|
||||
ObjectTypeEnum.PUBLIC_KEY,
|
||||
ObjectTypeEnum.PRIVATE_KEY,
|
||||
ObjectTypeEnum.SPLIT_KEY,
|
||||
ObjectTypeEnum.TEMPLATE,
|
||||
ObjectTypeEnum.SECRET_DATA,
|
||||
ObjectTypeEnum.OPAQUE_DATA)
|
||||
for unsupported_type in unsupported_types:
|
||||
obj_type = ObjectType(unsupported_type)
|
||||
key = self._get_symmetric_key()
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INVALID_FIELD,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_register_object_type_mismatch(self):
|
||||
unsupported_types = (ObjectTypeEnum.CERTIFICATE,
|
||||
ObjectTypeEnum.PUBLIC_KEY,
|
||||
ObjectTypeEnum.PRIVATE_KEY,
|
||||
ObjectTypeEnum.SPLIT_KEY,
|
||||
ObjectTypeEnum.TEMPLATE,
|
||||
ObjectTypeEnum.SECRET_DATA,
|
||||
ObjectTypeEnum.OPAQUE_DATA)
|
||||
for unsupported_type in unsupported_types:
|
||||
obj_type = ObjectType(unsupported_type)
|
||||
key = self._get_symmetric_key()
|
||||
attributes = []
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.register(obj_type, template_attribute, key)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.INVALID_FIELD,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_get(self):
|
||||
uuid = self._create()
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
res = self.kmip.get(uuid, key_format_type)
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
|
||||
def test_get_no_key_format_type(self):
|
||||
uuid = self._create()
|
||||
res = self.kmip.get(uuid, None)
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
|
||||
def test_get_unknown(self):
|
||||
uuids = ('some random string', UniqueIdentifier('no key here'))
|
||||
for uuid in uuids:
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
res = self.kmip.get(uuid, key_format_type)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.ITEM_NOT_FOUND,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_get_no_uuid(self):
|
||||
self._create()
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
res = self.kmip.get(None, key_format_type)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
|
||||
def test_get_with_key_compression(self):
|
||||
uuid = self._create()
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
key_compression = KeyCompressionType(KeyCompressionTypeEnum.
|
||||
EC_PUBLIC_KEY_TYPE_UNCOMPRESSED)
|
||||
res = self.kmip.get(uuid, key_format_type, key_compression)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.KEY_COMPRESSION_TYPE_NOT_SUPPORTED,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_destroy(self):
|
||||
uuid = self._create()
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
res = self.kmip.get(uuid, key_format_type)
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
res = self.kmip.destroy(uuid)
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
res = self.kmip.destroy(uuid)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.ITEM_NOT_FOUND,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_destroy_no_uuid(self):
|
||||
res = self.kmip.destroy(None)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.ITEM_NOT_FOUND,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def test_destroy_unknown(self):
|
||||
uuids = ('some random string', UniqueIdentifier('no key here'))
|
||||
for uuid in uuids:
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
res = self.kmip.get(uuid, key_format_type)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
res = self.kmip.destroy(uuid)
|
||||
self.assertEqual(ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'result status did not return failed')
|
||||
self.assertEqual(ResultReason.ITEM_NOT_FOUND,
|
||||
res.result_reason.value,
|
||||
'result reason did not match')
|
||||
|
||||
def _create(self):
|
||||
obj_type = ObjectType(ObjectTypeEnum.SYMMETRIC_KEY)
|
||||
attributes = self._get_attrs()
|
||||
template_attribute = TemplateAttribute(attributes=attributes)
|
||||
res = self.kmip.create(obj_type, template_attribute)
|
||||
self.assertNotEqual(None, res, 'result is None')
|
||||
self.assertEqual(ResultStatus.SUCCESS, res.result_status.value,
|
||||
'result status did not return success')
|
||||
return res.uuid
|
||||
|
||||
def _get_symmetric_key(self):
|
||||
# only need usage attribute
|
||||
attrs = [self._get_attrs()[1]]
|
||||
key_format_type = KeyFormatType(KeyFormatTypeEnum.RAW)
|
||||
key_material = KeyMaterial(self.key)
|
||||
key_value = KeyValue(key_material, attrs)
|
||||
crypto_alg = CryptographicAlgorithm(self.algorithm_name)
|
||||
crypto_length = CryptographicLength(self.key_length)
|
||||
usage = CryptographicUsageMask(self.usage_mask)
|
||||
key_block = KeyBlock(key_format_type, None, key_value, crypto_alg,
|
||||
crypto_length, usage)
|
||||
return SymmetricKey(key_block)
|
||||
|
||||
def _get_attrs(self):
|
||||
attr_factory = AttributeFactory()
|
||||
algorithm = self._get_alg_attr(self.algorithm_name)
|
||||
length = self._get_length_attr(self.key_length)
|
||||
attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
|
||||
mask_flags = [CryptoUsageMaskEnum.ENCRYPT,
|
||||
CryptoUsageMaskEnum.DECRYPT]
|
||||
usage_mask = attr_factory.create_attribute(attribute_type,
|
||||
mask_flags)
|
||||
name_value = Name.NameValue(value='TESTNAME')
|
||||
name_type = Name.NameType(value=NameType.UNINTERPRETED_TEXT_STRING)
|
||||
value = Name.create(name_value, name_type)
|
||||
nameattr = attr_factory.create_attribute(AttributeType.NAME, value)
|
||||
return [algorithm, usage_mask, length, nameattr]
|
||||
|
||||
def _get_alg_attr(self, alg=None):
|
||||
if alg is None:
|
||||
alg = self.algorithm_name
|
||||
attr_factory = AttributeFactory()
|
||||
attribute_type = AttributeType.CRYPTOGRAPHIC_ALGORITHM
|
||||
return attr_factory.create_attribute(attribute_type, alg)
|
||||
|
||||
def _get_length_attr(self, length=None):
|
||||
if length is None:
|
||||
length = self.key_length
|
||||
attr_factory = AttributeFactory()
|
||||
attribute_type = AttributeType.CRYPTOGRAPHIC_LENGTH
|
||||
return attr_factory.create_attribute(attribute_type, length)
|
||||
|
||||
def _check_attr_exists(self, attr_expected, attributes):
|
||||
for attribute in attributes:
|
||||
if attribute.attribute_name.value ==\
|
||||
attr_expected.attribute_name.value:
|
||||
return attribute.attribute_value.value ==\
|
||||
attr_expected.attribute_value.value
|
||||
return False
|
||||
|
||||
def test_locate(self):
|
||||
self._create()
|
||||
|
||||
name_value = Name.NameValue(value='TESTNAME')
|
||||
name_type = Name.NameType(value=NameType.UNINTERPRETED_TEXT_STRING)
|
||||
value = Name.create(name_value, name_type)
|
||||
|
||||
attr_factory = AttributeFactory()
|
||||
nameattr = attr_factory.create_attribute(AttributeType.NAME, value)
|
||||
|
||||
attrs = [nameattr]
|
||||
res = self.kmip.locate(attributes=attrs)
|
||||
self.assertEqual(
|
||||
ResultStatus.OPERATION_FAILED,
|
||||
res.result_status.value,
|
||||
'locate result status did not return success')
|
|
@ -1,169 +0,0 @@
|
|||
# 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