mirror of
https://github.com/OpenKMIP/PyKMIP.git
synced 2025-07-23 14:04:33 +02:00
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
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# 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):
|
class KMIP(object):
|
||||||
|
|
||||||
@ -89,334 +51,3 @@ class KMIP(object):
|
|||||||
|
|
||||||
def discover_versions(self, protocol_versions=None):
|
def discover_versions(self, protocol_versions=None):
|
||||||
raise NotImplementedError()
|
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…
x
Reference in New Issue
Block a user