Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion kmip/demos/pie/locate.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
opts, args = parser.parse_args(sys.argv[1:])

config = opts.config
offset_items = opts.offset_items
maximum_items = opts.maximum_items
name = opts.name
initial_dates = opts.initial_dates
state = opts.state
Expand All @@ -43,6 +45,13 @@

attribute_factory = AttributeFactory()

if offset_items and (offset_items < 0):
logger.error("Invalid offset items value provided.")
sys.exit(-1)
if maximum_items and (maximum_items < 0):
logger.error("Invalid maximum items value provided.")
sys.exit(-1)

# Build attributes if any are specified
attributes = []
if name:
Expand Down Expand Up @@ -159,7 +168,11 @@
config_file=opts.config_file
) as client:
try:
uuids = client.locate(attributes=attributes)
uuids = client.locate(
attributes=attributes,
offset_items=offset_items,
maximum_items=maximum_items
)
logger.info("Located uuids: {0}".format(uuids))
except Exception as e:
logger.error(e)
16 changes: 15 additions & 1 deletion kmip/demos/units/locate.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
username = opts.username
password = opts.password
config = opts.config
offset_items = opts.offset_items
maximum_items = opts.maximum_items
name = opts.name
initial_dates = opts.initial_dates
state = opts.state
Expand Down Expand Up @@ -62,6 +64,13 @@
credential_value
)

if offset_items and (offset_items < 0):
logger.error("Invalid offset items value provided.")
sys.exit(-1)
if maximum_items and (maximum_items < 0):
logger.error("Invalid maximum items value provided.")
sys.exit(-1)

# Build the client and connect to the server
client = kmip_client.KMIPProxy(config=config, config_file=opts.config_file)
client.open()
Expand Down Expand Up @@ -180,7 +189,12 @@
)
)

result = client.locate(attributes=attributes, credential=credential)
result = client.locate(
attributes=attributes,
offset_items=offset_items,
maximum_items=maximum_items,
credential=credential
)
client.close()

# Display operation results
Expand Down
16 changes: 16 additions & 0 deletions kmip/demos/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,22 @@ def build_cli_parser(operation=None):
help="List of attribute names to retrieve, defaults to all "
"attributes")
elif operation is Operation.LOCATE:
parser.add_option(
"--offset-items",
action="store",
type="int",
default=None,
dest="offset_items",
help="The number of matching secrets to skip."
)
parser.add_option(
"--maximum-items",
action="store",
type="int",
default=None,
dest="maximum_items",
help="The maximum number of matching secrets to return."
)
parser.add_option(
"-n",
"--name",
Expand Down
15 changes: 12 additions & 3 deletions kmip/pie/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,14 +661,16 @@ def derive_key(self,

@is_connected
def locate(self, maximum_items=None, storage_status_mask=None,
object_group_member=None, attributes=None):
object_group_member=None, attributes=None, offset_items=None):
"""
Search for managed objects, depending on the attributes specified in
the request.

Args:
maximum_items (integer): Maximum number of object identifiers the
server MAY return.
offset_items (integer): Number of object identifiers the server
should skip before returning results.
storage_status_mask (integer): A bit mask that indicates whether
on-line or archived objects are to be searched.
object_group_member (ObjectGroupMember): An enumeration that
Expand All @@ -688,6 +690,9 @@ def locate(self, maximum_items=None, storage_status_mask=None,
if maximum_items is not None:
if not isinstance(maximum_items, six.integer_types):
raise TypeError("maximum_items must be an integer")
if offset_items is not None:
if not isinstance(offset_items, six.integer_types):
raise TypeError("offset items must be an integer")
if storage_status_mask is not None:
if not isinstance(storage_status_mask, six.integer_types):
raise TypeError("storage_status_mask must be an integer")
Expand All @@ -705,8 +710,12 @@ def locate(self, maximum_items=None, storage_status_mask=None,

# Search for managed objects and handle the results
result = self.proxy.locate(
maximum_items, storage_status_mask,
object_group_member, attributes)
maximum_items=maximum_items,
offset_items=offset_items,
storage_status_mask=storage_status_mask,
object_group_member=object_group_member,
attributes=attributes
)

status = result.result_status.value
if status == enums.ResultStatus.SUCCESS:
Expand Down
10 changes: 7 additions & 3 deletions kmip/services/kmip_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,11 +694,13 @@ def rekey_key_pair(self, batch=False, private_key_uuid=None, offset=None,
return results[0]

def locate(self, maximum_items=None, storage_status_mask=None,
object_group_member=None, attributes=None, credential=None):
object_group_member=None, attributes=None, credential=None,
offset_items=None):
return self._locate(maximum_items=maximum_items,
storage_status_mask=storage_status_mask,
object_group_member=object_group_member,
attributes=attributes, credential=credential)
attributes=attributes, credential=credential,
offset_items=offset_items)

def query(self, batch=False, query_functions=None, credential=None):
"""
Expand Down Expand Up @@ -1476,12 +1478,14 @@ def _register(self,
return result

def _locate(self, maximum_items=None, storage_status_mask=None,
object_group_member=None, attributes=None, credential=None):
object_group_member=None, attributes=None, credential=None,
offset_items=None):

operation = Operation(OperationEnum.LOCATE)

payload = payloads.LocateRequestPayload(
maximum_items=maximum_items,
offset_items=offset_items,
storage_status_mask=storage_status_mask,
object_group_member=object_group_member,
attributes=attributes
Expand Down
16 changes: 16 additions & 0 deletions kmip/services/server/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -1780,6 +1780,22 @@ def _process_locate(self, payload):
reverse=True
)

# Skip the requested offset items and keep the requested maximum items
if payload.offset_items is not None:
if payload.maximum_items is not None:
managed_objects = managed_objects[
payload.offset_items:(
payload.offset_items + payload.maximum_items
)
]
else:
managed_objects = managed_objects[payload.offset_items:]
else:
if payload.maximum_items is not None:
managed_objects = managed_objects[:payload.maximum_items]
else:
pass

unique_identifiers = [
str(x.unique_identifier) for x in managed_objects
]
Expand Down
16 changes: 16 additions & 0 deletions kmip/tests/integration/services/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,22 @@ def test_symmetric_key_create_getattributes_locate_destroy(self):
)
self.assertEqual(0, len(result.uuids))

# Test locating keys using offset and maximum item constraints.
result = self.client.locate(offset_items=1)

self.assertEqual(1, len(result.uuids))
self.assertIn(uid_a, result.uuids)

result = self.client.locate(maximum_items=1)

self.assertEqual(1, len(result.uuids))
self.assertIn(uid_b, result.uuids)

result = self.client.locate(offset_items=1, maximum_items=1)

self.assertEqual(1, len(result.uuids))
self.assertIn(uid_a, result.uuids)

# Clean up keys
result = self.client.destroy(uid_a)
self.assertEqual(ResultStatus.SUCCESS, result.result_status.value)
Expand Down
16 changes: 16 additions & 0 deletions kmip/tests/integration/services/test_proxykmipclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,22 @@ def test_create_getattributes_locate_destroy(self):
)
self.assertEqual(0, len(result))

# Test locating keys using offset and maximum item constraints.
result = self.client.locate(offset_items=1)

self.assertEqual(1, len(result))
self.assertIn(a_id, result)

result = self.client.locate(maximum_items=1)

self.assertEqual(1, len(result))
self.assertIn(b_id, result)

result = self.client.locate(offset_items=1, maximum_items=1)

self.assertEqual(1, len(result))
self.assertIn(a_id, result)

# Clean up the keys
self.client.destroy(a_id)
self.client.destroy(b_id)
98 changes: 98 additions & 0 deletions kmip/tests/unit/services/server/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -4474,6 +4474,104 @@ def test_locate(self):
self.assertIn(id_a, response_payload.unique_identifiers)
self.assertIn(id_b, response_payload.unique_identifiers)

def test_locate_with_offset_and_maximum_items(self):
"""
Test locate operation with specified offset and maximum item limits.
"""
e = engine.KmipEngine()
e._data_store = self.engine
e._data_store_session_factory = self.session_factory
e._data_session = e._data_store_session_factory()
e._is_allowed_by_operation_policy = mock.Mock(return_value=True)
e._logger = mock.MagicMock()

key = (
b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
)
obj_a = pie_objects.SymmetricKey(
enums.CryptographicAlgorithm.AES,
128,
key,
name='name1'
)
obj_a.initial_date = int(time.time())
time.sleep(2)
obj_b = pie_objects.SymmetricKey(
enums.CryptographicAlgorithm.DES,
128,
key,
name='name2'
)
obj_b.initial_date = int(time.time())
time.sleep(2)
obj_c = pie_objects.SymmetricKey(
enums.CryptographicAlgorithm.AES,
128,
key,
name='name3'
)
obj_c.initial_date = int(time.time())

e._data_session.add(obj_a)
e._data_session.add(obj_b)
e._data_session.add(obj_c)
e._data_session.commit()
e._data_session = e._data_store_session_factory()

id_a = str(obj_a.unique_identifier)
id_b = str(obj_b.unique_identifier)
id_c = str(obj_c.unique_identifier)

# Locate all objects.
payload = payloads.LocateRequestPayload()
e._logger.reset_mock()
response_payload = e._process_locate(payload)
e._data_session.commit()
e._data_session = e._data_store_session_factory()

e._logger.info.assert_any_call("Processing operation: Locate")

self.assertEqual(
[id_c, id_b, id_a],
response_payload.unique_identifiers
)

# Locate by skipping the first object and only returning one object.
payload = payloads.LocateRequestPayload(
offset_items=1,
maximum_items=1
)
e._logger.reset_mock()
response_payload = e._process_locate(payload)
e._data_session.commit()
e._data_session = e._data_store_session_factory()

e._logger.info.assert_any_call("Processing operation: Locate")

self.assertEqual([id_b], response_payload.unique_identifiers)

# Locate by skipping the first two objects.
payload = payloads.LocateRequestPayload(offset_items=2)
e._logger.reset_mock()
response_payload = e._process_locate(payload)
e._data_session.commit()
e._data_session = e._data_store_session_factory()

e._logger.info.assert_any_call("Processing operation: Locate")

self.assertEqual([id_a], response_payload.unique_identifiers)

# Locate by only returning two objects.
payload = payloads.LocateRequestPayload(maximum_items=2)
e._logger.reset_mock()
response_payload = e._process_locate(payload)
e._data_session.commit()
e._data_session = e._data_store_session_factory()

e._logger.info.assert_any_call("Processing operation: Locate")

self.assertEqual([id_c, id_b], response_payload.unique_identifiers)

def test_locate_with_name(self):
"""
Test locate operation when 'Name' attribute is given.
Expand Down