Added support for LOCATE operation

This commit is contained in:
wyllys 2014-09-04 14:42:20 -04:00
parent 97ae864196
commit b04f5c2dc3
9 changed files with 339 additions and 3 deletions

View File

@ -559,3 +559,13 @@ class CryptographicUsageMask(Enum):
TRANSLATE_DECRYPT = 0x00020000
TRANSLATE_WRAP = 0x00040000
TRANSLATE_UNWRAP = 0x00080000
# 9.1.3.2.33
class ObjectGroupMember(Enum):
GROUP_MEMBER_FRESH = 0x00000001
GROUP_MEMBER_DEFAULT = 0x00000002
# 9.1.3.3.2
class StorageStatusMask(Enum):
ONLINE_STORAGE = 0x00000001
ARCHIVAL_STORAGE = 0x00000002

View File

@ -24,6 +24,7 @@ from kmip.core.objects import TemplateAttribute
from kmip.core.primitives import Struct
from kmip.core.primitives import Enumeration
from kmip.core.primitives import Integer
from kmip.core.utils import BytearrayStream
@ -429,11 +430,125 @@ class DestroyResponsePayload(Struct):
pass
class LocateRequestPayload(Struct):
# 9.1.3.2.33
class ObjectGroupMember(Enumeration):
ENUM_TYPE = enums.ObjectGroupMember
def __init__(self, value=None):
super(self.__class__, self).__init__(value,
Tags.OBJECT_GROUP_MEMBER)
class MaximumItems(Integer):
def __init__(self, value=None):
super(self.__class__, self).__init__(value,
Tags.MAXIMUM_ITEMS)
# 9.1.3.3.2
class StorageStatusMask(Enumeration):
ENUM_TYPE = enums.StorageStatusMask
def __init__(self, value=None):
super(self.__class__, self).__init__(value,
Tags.STORAGE_STATUS_MASK)
def __init__(self, maximum_items=None, storage_status_mask=None,
object_group_member=None, attributes=None):
super(self.__class__, self).__init__(enums.Tags.REQUEST_PAYLOAD)
self.maximum_items = maximum_items
self.storage_status_mask = storage_status_mask
self.object_group_member = object_group_member
self.attributes = attributes or []
self.validate()
def read(self, istream):
super(self.__class__, self).read(istream)
tstream = BytearrayStream(istream.read(self.length))
if self.is_tag_next(Tags.MAXIMUM_ITEMS, tstream):
self.maximum_items = LocateRequestPayload.MaximumItems()
self.maximum_items.read()
if self.is_tag_next(Tags.STORAGE_STATUS_MASK, tstream):
self.storage_status_mask = LocateRequestPayload.StorageStatusMask()
self.storage_status_mask.read()
if self.is_tag_next(Tags.OBJECT_GROUP_MEMBER, tstream):
self.object_group_member = LocateRequestPayload.ObjectGroupMember()
self.object_group_member.read(tstream)
while self.is_tag_next(Tags.TEMPLATE_ATTRIBUTE, tstream):
attr = TemplateAttribute()
attr.read(tstream)
self.attributes.append(attr)
self.validate()
def write(self, ostream):
tstream = BytearrayStream()
if self.maximum_items is not None:
self.maximum_items.write(tstream)
if self.storage_status_mask is not None:
self.storage_status_mask.write(tstream)
if self.attributes is not None:
for a in self.attributes:
a.write(tstream)
# Write the length and value of the request payload
self.length = tstream.length()
super(self.__class__, self).write(ostream)
ostream.write(tstream.buffer)
def validate(self):
self._validate()
def _validate(self):
# TODO Finish implementation.
pass
class LocateResponsePayload(Struct):
def __init__(self, unique_identifiers=[]):
super(self.__class__, self).__init__(enums.Tags.RESPONSE_PAYLOAD)
self.unique_identifiers = unique_identifiers or []
self.validate()
def read(self, istream):
super(self.__class__, self).read(istream)
tstream = BytearrayStream(istream.read(self.length))
while self.is_tag_next(Tags.UNIQUE_IDENTIFIER, tstream):
ui = attributes.UniqueIdentifier()
ui.read(tstream)
self.unique_identifiers.append(ui)
self.is_oversized(tstream)
self.validate()
def write(self, ostream):
tstream = BytearrayStream()
for ui in self.unique_identifier:
ui.write(tstream)
# Write the length and value of the request payload
self.length = tstream.length()
super(self.__class__, self).write(ostream)
ostream.write(tstream.buffer)
def validate(self):
self.__validate()
def __validate(self):
# TODO (peter-hamilton) Finish implementation.
pass
REQUEST_MAP = {enums.Operation.CREATE: CreateRequestPayload,
enums.Operation.GET: GetRequestPayload,
enums.Operation.DESTROY: DestroyRequestPayload,
enums.Operation.REGISTER: RegisterRequestPayload}
enums.Operation.REGISTER: RegisterRequestPayload,
enums.Operation.LOCATE: LocateRequestPayload}
RESPONSE_MAP = {enums.Operation.CREATE: CreateResponsePayload,
enums.Operation.GET: GetResponsePayload,
enums.Operation.REGISTER: RegisterResponsePayload,
enums.Operation.DESTROY: DestroyResponsePayload,
enums.Operation.REGISTER: RegisterResponsePayload}
enums.Operation.LOCATE: LocateResponsePayload}

View File

@ -45,3 +45,10 @@ class MemRepo(ManagedObjectRepo):
return False
del self.repo[uuid]
return True
def locate(self, maximum_items, storage_status_mask,
object_group_member, attributes):
# TODO - search objects, find one with matching attrs
if "1" in self.repo:
return [self.repo["1"]]
return None

View File

@ -47,6 +47,7 @@ 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
class KMIP(object):
@ -68,6 +69,11 @@ class KMIP(object):
def destroy(self, uuid, credential=None):
raise NotImplementedError
def locate(self, maximum_items=None, storate_status_mask=None,
object_group_member=None, attributes=None,
credential=None):
raise NotImplementedError
class KMIPImpl(KMIP):
@ -248,6 +254,17 @@ class KMIPImpl(KMIP):
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)
uuids = self.repo.locate(maximum_items, storage_status_mask,
object_group_member, attributes)
return LocateResult(ResultStatus(RS.SUCCESS),
locate_uuids=uuids)
def _validate_req_field(self, attrs, name, expected, msg, required=True):
self.logger.debug('Validating attribute %s' % name)
seen = False

78
kmip/demos/locate.py Normal file
View File

@ -0,0 +1,78 @@
# 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.core.enums import AttributeType
from kmip.core.enums import CredentialType
from kmip.core.enums import ObjectType
from kmip.core.enums import CryptographicAlgorithm
from kmip.core.enums import CryptographicUsageMask
from kmip.core.enums import NameType
from kmip.core.attributes import Name
from kmip.core.factories.attributes import AttributeFactory
from kmip.core.factories.credentials import CredentialFactory
from kmip.core.objects import TemplateAttribute, Attribute
from kmip.services.kmip_client import KMIPProxy
import logging
import os
if __name__ == '__main__':
f_log = os.path.join(os.path.dirname(__file__), '..', 'logconfig.ini')
logging.config.fileConfig(f_log)
logger = logging.getLogger(__name__)
attribute_factory = AttributeFactory()
credential_factory = CredentialFactory()
credential_type = CredentialType.USERNAME_AND_PASSWORD
credential_value = {'Username': 'Peter', 'Password': 'abc123'}
credential = credential_factory.create_credential(credential_type,
credential_value)
client = KMIPProxy()
client.open()
object_type = ObjectType.SYMMETRIC_KEY
attribute_type = AttributeType.CRYPTOGRAPHIC_ALGORITHM
algorithm = attribute_factory.create_attribute(attribute_type,
CryptographicAlgorithm.AES)
mask_flags = [CryptographicUsageMask.ENCRYPT,
CryptographicUsageMask.DECRYPT]
attribute_type = AttributeType.CRYPTOGRAPHIC_USAGE_MASK
usage_mask = attribute_factory.create_attribute(attribute_type,
mask_flags)
name = Attribute.AttributeName('Name')
name_value = Name.NameValue('FOOBAR')
name_type = Name.NameType(NameType.UNINTERPRETED_TEXT_STRING)
value = Name(name_value=name_value, name_type=name_type)
nameattr = Attribute(attribute_name=name, attribute_value=value)
attributes = [algorithm, usage_mask, nameattr]
template_attribute = TemplateAttribute(attributes=attributes)
result = client.create(object_type, template_attribute,
credential)
attrs = [nameattr]
result = client.locate(attributes=attrs, credential=credential)
client.close()
logger.debug('get() result status: {}'.format(result.result_status.enum))
logger.debug('retrieved object type: {}'.format(result.object_type.enum))
logger.debug('Located UUID: {}'.format(result.locate_uuids))

View File

@ -17,6 +17,7 @@ from kmip.services.results import CreateResult
from kmip.services.results import GetResult
from kmip.services.results import DestroyResult
from kmip.services.results import RegisterResult
from kmip.services.results import LocateResult
from kmip.core import attributes as attr
@ -93,6 +94,13 @@ class KMIPProxy(KMIP):
secret=secret,
credential=credential)
def locate(self, maximum_items=None, storage_status_mask=None,
object_group_member=None, attributes=None, credential=None):
return self._locate(maximum_items=maximum_items,
storage_status_mask=storage_status_mask,
object_group_member=object_group_member,
attributes=attributes, credential=credential)
def _create(self,
object_type=None,
template_attribute=None,
@ -263,6 +271,53 @@ class KMIPProxy(KMIP):
payload_template_attribute)
return result
def _locate(self, maximum_items=None, storage_status_mask=None,
object_group_member=None, attributes=[], credential=None):
operation = Operation(OperationEnum.LOCATE)
mxi = None
ssmask = None
objgrp = None
if maximum_items is not None:
mxi = operations.LocateRequestPayload.MaximumItems(maximum_items)
if storage_status_mask is not None:
m = storage_status_mask
ssmask = operations.LocateRequestPayload.StorageStatusMask(m)
if object_group_member is not None:
o = object_group_member
objgrp = operations.LocateRequestPayload.ObjectGroupMember(o)
payload = operations.LocateRequestPayload(maximum_items=mxi,
storage_status_mask=ssmask,
object_group_member=objgrp,
attributes=attributes)
batch_item = messages.RequestBatchItem(operation=operation,
request_payload=payload)
message = self._build_request_message(credential, [batch_item])
self._send_message(message)
message = messages.ResponseMessage()
data = self._receive_message()
message.read(data)
batch_items = message.batch_items
batch_item = batch_items[0]
payload = batch_item.response_payload
if payload is None:
locate_uuids = None
else:
locate_uuids = payload.unique_identifiers
result = LocateResult(batch_item.result_status,
batch_item.result_reason,
batch_item.result_message,
locate_uuids)
return result
def _build_request_message(self, credential, batch_items):
protocol_version = ProtocolVersion.create(1, 1)

22
kmip/services/processor.py Executable file → Normal file
View File

@ -31,6 +31,7 @@ from kmip.core.messages.operations import CreateResponsePayload
from kmip.core.messages.operations import GetResponsePayload
from kmip.core.messages.operations import DestroyResponsePayload
from kmip.core.messages.operations import RegisterResponsePayload
from kmip.core.messages.operations import LocateResponsePayload
from kmip.core.enums import Operation
from kmip.core.enums import ResultStatus as RS
@ -168,6 +169,8 @@ class Processor(object):
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)
else:
raise NotImplementedError()
@ -252,3 +255,22 @@ class Processor(object):
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.status_storage_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.locate_uuids
resp_pl = LocateResponsePayload(unique_identifiers=uuids)
return (result_status, result_reason, result_message, resp_pl)

View File

@ -125,3 +125,16 @@ class DestroyResult(OperationResult):
self.uuid = uuid
else:
self.uuid = None
class LocateResult(OperationResult):
def __init__(self,
result_status,
result_reason=None,
result_message=None,
locate_uuids=None):
super(self.__class__, self).__init__(result_status,
result_reason,
result_message)
self.locate_uuids = locate_uuids

View File

@ -20,6 +20,7 @@ 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
@ -28,6 +29,7 @@ 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.keys import RawKey
from kmip.core.messages.contents import KeyCompressionType
@ -35,6 +37,7 @@ from kmip.core.messages.contents import KeyFormatType
from kmip.core.objects import KeyBlock
from kmip.core.objects import KeyValueStruct
from kmip.core.objects import TemplateAttribute
from kmip.core.objects import Attribute
from kmip.core.secrets import SymmetricKey
from kmip.core.server import KMIPImpl
@ -474,6 +477,14 @@ class TestKMIPServer(TestCase):
crypto_length, usage)
return SymmetricKey(key_block)
def _make_nameattr(self):
name = Attribute.AttributeName('Name')
name_value = Name.NameValue('TESTNAME')
name_type = Name.NameType(NameType.UNINTERPRETED_TEXT_STRING)
value = Name(name_value=name_value, name_type=name_type)
nameattr = Attribute(attribute_name=name, attribute_value=value)
return nameattr
def _get_attrs(self):
attr_factory = AttributeFactory()
algorithm = self._get_alg_attr(self.algorithm_name)
@ -483,7 +494,8 @@ class TestKMIPServer(TestCase):
CryptoUsageMaskEnum.DECRYPT]
usage_mask = attr_factory.create_attribute(attribute_type,
mask_flags)
return [algorithm, usage_mask, length]
nameattr = self._make_nameattr()
return [algorithm, usage_mask, length, nameattr]
def _get_alg_attr(self, alg=None):
if alg is None:
@ -506,3 +518,10 @@ class TestKMIPServer(TestCase):
return attribute.attribute_value.value ==\
attr_expected.attribute_value.value
return False
def test_locate(self):
self._create()
attrs = [self._make_nameattr()]
res = self.kmip.locate(attributes=attrs)
self.assertEqual(ResultStatus.SUCCESS, res.result_status.enum,
'locate result status did not return success')