Skip to content

Commit

Permalink
Add support for the CurrentAttribute structure
Browse files Browse the repository at this point in the history
This change adds support for the CurrentAttribute structure added
in KMIP 2.0. The CurrentAttribute structure is a basic container
structure that contains a single attribute instance for use by
attribute operations. A new unit test suite has been added to cover
the new additions.

Partially implements #547
  • Loading branch information
PeterHamilton committed Nov 1, 2019
1 parent cd1079a commit 616e683
Show file tree
Hide file tree
Showing 2 changed files with 580 additions and 0 deletions.
181 changes: 181 additions & 0 deletions kmip/core/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,187 @@ def __ne__(self, other):
return NotImplemented


class CurrentAttribute(primitives.Struct):
"""
A structure containing a single attribute.
This is intended for use with KMIP 2.0+.
Attributes:
attribute: An attribute instance.
"""

def __init__(self, attribute=None):
"""
Construct a CurrentAttribute structure.
Args:
attribute (struct): An attribute structure of varying type.
Defaults to None. Required for read/write.
"""
super(CurrentAttribute, self).__init__(
tag=enums.Tags.CURRENT_ATTRIBUTE
)

self._factory = AttributeValueFactory()

self._attribute = None

self.attribute = attribute

@property
def attribute(self):
if self._attribute:
return self._attribute
return None

@attribute.setter
def attribute(self, value):
if value is None:
self._attribute = None
elif isinstance(value, primitives.Base):
if enums.is_attribute(value.tag):
self._attribute = value
else:
raise TypeError(
"The attribute must be a supported attribute type."
)
else:
raise TypeError(
"The attribute must be a Base object, not a {}.".format(
type(value)
)
)

def read(self, input_buffer, kmip_version=enums.KMIPVersion.KMIP_2_0):
"""
Read the data stream and decode the CurrentAttribute structure into
its parts.
Args:
input_buffer (stream): A data stream containing encoded object
data, supporting a read method.
kmip_version (enum): A KMIPVersion enumeration defining the KMIP
version with which the object will be decoded. Optional,
defaults to KMIP 2.0.
Raises:
AttributeNotSupported: Raised when an invalid value is decoded as
the attribute from the encoding.
InvalidKmipEncoding: Raised if the attribute is missing from the
encoding.
VersionNotSupported: Raised when a KMIP version is provided that
does not support the CurrentAttribute structure.
"""
if kmip_version < enums.KMIPVersion.KMIP_2_0:
raise exceptions.VersionNotSupported(
"KMIP {} does not support the CurrentAttribute object.".format(
kmip_version.value
)
)

super(CurrentAttribute, self).read(
input_buffer,
kmip_version=kmip_version
)
local_buffer = BytearrayStream(input_buffer.read(self.length))

if len(local_buffer) < 3:
raise exceptions.InvalidKmipEncoding(
"The CurrentAttribute encoding is missing the attribute field."
)
tag = struct.unpack('!I', b'\x00' + local_buffer.peek(3))[0]
if enums.is_enum_value(enums.Tags, tag):
tag = enums.Tags(tag)
if enums.is_attribute(tag, kmip_version=kmip_version):
value = self._factory.create_attribute_value_by_enum(tag, None)
value.read(local_buffer, kmip_version=kmip_version)
self._attribute = value
else:
raise exceptions.AttributeNotSupported(
"Attribute {} is not supported by KMIP {}.".format(
tag.name,
kmip_version.value
)
)
else:
raise exceptions.InvalidKmipEncoding(
"The CurrentAttribute encoding is missing the attribute field."
)

self.is_oversized(local_buffer)

def write(self, output_buffer, kmip_version=enums.KMIPVersion.KMIP_2_0):
"""
Write the CurrentAttribute structure encoding to the data stream.
Args:
output_buffer (stream): A data stream in which to encode
CurrentAttribute structure data, supporting a write method.
kmip_version (enum): A KMIPVersion enumeration defining the KMIP
version with which the object will be encoded. Optional,
defaults to KMIP 2.0.
Raises:
AttributeNotSupported: Raised if an unsupported attribute is
found while encoding.
InvalidField: Raised when the attribute is unspecified at write
time.
VersionNotSupported: Raised when a KMIP version is provided that
does not support the CurrentAttribute object.
"""
if kmip_version < enums.KMIPVersion.KMIP_2_0:
raise exceptions.VersionNotSupported(
"KMIP {} does not support the CurrentAttribute object.".format(
kmip_version.value
)
)

local_buffer = BytearrayStream()

if self._attribute:
tag = self._attribute.tag
if not enums.is_attribute(tag, kmip_version=kmip_version):
raise exceptions.AttributeNotSupported(
"Attribute {} is not supported by KMIP {}.".format(
tag.name,
kmip_version.value
)
)
self._attribute.write(local_buffer, kmip_version=kmip_version)
else:
raise exceptions.InvalidField(
"The CurrentAttribute object is missing the attribute field."
)

self.length = local_buffer.length()
super(CurrentAttribute, self).write(
output_buffer,
kmip_version=kmip_version
)
output_buffer.write(local_buffer.buffer)

def __repr__(self):
return "CurrentAttribute(attribute={})".format(repr(self.attribute))

def __str__(self):
value = '"attribute": {}'.format(repr(self.attribute))
return '{' + value + '}'

def __eq__(self, other):
if not isinstance(other, CurrentAttribute):
return NotImplemented
elif self.attribute != other.attribute:
return False
return True

def __ne__(self, other):
if isinstance(other, CurrentAttribute):
return not (self == other)
else:
return NotImplemented


class AttributeReference(primitives.Struct):
"""
A structure containing reference information for an attribute.
Expand Down
Loading

0 comments on commit 616e683

Please sign in to comment.