From 575efc8bd229cfa5ef7d73c4b53c1e27f6f267d5 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 8 Apr 2015 09:00:37 -0400 Subject: Return only key/containers names on LIST operation --- API.md | 2 -- custodia/secrets.py | 67 +++++++++++++++++++++--------------------------- custodia/store/sqlite.py | 36 ++++++++++++-------------- 3 files changed, 45 insertions(+), 60 deletions(-) diff --git a/API.md b/API.md index e250e9f..a2f7cba 100644 --- a/API.md +++ b/API.md @@ -108,8 +108,6 @@ provided: GET /secrets/ may return only keys under //* Returns: - 200 in case of success and a dictionary containing a list of all keys in the container and all subcontainers. - The dictionary key is the key or container name, the value is the empty - string for containers. - 401 if authentication is necessary - 403 if access to the key is forbidden - 404 if no key was found diff --git a/custodia/secrets.py b/custodia/secrets.py index 9e57a49..397754b 100644 --- a/custodia/secrets.py +++ b/custodia/secrets.py @@ -75,26 +75,25 @@ class Secrets(HTTPConsumer): def _parent_exists(self, default, trail): # check that the containers exist - exists = True - l = len(trail) - n = 0 - for n in range(1, l): - probe = self._db_key(trail[:n] + ['']) - try: - check = self.root.store.get(probe) - if check is None: - exists = False - break - except CSStoreError: - raise HTTPError(500) - - # create if default namespace needs creating - if not exists and l == 2 and n == 1 and default == trail[0]: + basename = self._db_container_key(trail[0], '') + try: + keylist = self.root.store.list(basename) + except CSStoreError: + raise HTTPError(500) + + # create default namespace if it is the only missing piece + if keylist is None and len(trail) == 2 and default == trail[0]: container = self._db_container_key(default, '') self.root.store.set(container, '') - exists = True + return True - return exists + # check if any parent is missing + for n in range(1, len(trail)): + c = self._db_key(trail[:n] + ['']) + if c not in keylist: + return False + + return True def GET(self, request, response): trail = request.get('trail', []) @@ -131,21 +130,17 @@ class Secrets(HTTPConsumer): basename = self._db_container_key(default, trail) userfilter = request.get('query', dict()).get('filter', '') try: - keydict = self.root.store.list(basename + userfilter) - if keydict is None: + keylist = self.root.store.list(basename + userfilter) + if keylist is None: raise HTTPError(404) - output = dict() - for k in keydict: - # remove the base container itself + # remove the base container itself + output = list() + for k in keylist: if k == basename: continue # strip away the internal prefix for storing keys name = k[len('keys/'):] - # return empty value for containers - if name.endswith('/'): - output[name] = '' - else: - output[name] = json.loads(keydict[k]) + output.append(name) response['output'] = json.dumps(output) except CSStoreError: raise HTTPError(500) @@ -169,16 +164,14 @@ class Secrets(HTTPConsumer): def _destroy(self, trail, request, response): basename = self._db_container_key(None, trail) try: - keydict = self.root.store.list(basename) - if keydict is None: + keylist = self.root.store.list(basename) + if keylist is None: raise HTTPError(404) - keys = list(keydict.keys()) - if len(keys) != 1: - raise HTTPError(409) - if keys[0] != basename: + if basename not in keylist: # uh ? raise HTTPError(409) - print((basename, keys)) + if len(keylist) != 1: + raise HTTPError(409) ret = self.root.store.cut(basename) except CSStoreError: raise HTTPError(500) @@ -314,8 +307,7 @@ class SecretsTests(unittest.TestCase): rep = {} self.GET(req, rep) self.assertEqual(json.loads(rep['output']), - json.loads('{"test/key1":' - '{"type":"simple","value":"1234"}}')) + json.loads('["test/key1"]')) def test_3_LISTKeys_2(self): req = {'remote_user': 'test', @@ -324,8 +316,7 @@ class SecretsTests(unittest.TestCase): rep = {} self.GET(req, rep) self.assertEqual(json.loads(rep['output']), - json.loads('{"test/key1":' - '{"type":"simple","value":"1234"}}')) + json.loads('["test/key1"]')) def test_4_PUTKey_errors_400_1(self): req = {'headers': {'Content-Type': 'text/plain'}, diff --git a/custodia/store/sqlite.py b/custodia/store/sqlite.py index 5308674..e96848f 100644 --- a/custodia/store/sqlite.py +++ b/custodia/store/sqlite.py @@ -72,7 +72,7 @@ class SqliteStore(CSStore): raise CSStoreError('Error occurred while trying to store key') def list(self, keyfilter='/'): - search = "SELECT * FROM %s WHERE key LIKE ?" % self.table + search = "SELECT key FROM %s WHERE key LIKE ?" % self.table key = "%s%%" % (keyfilter,) try: conn = sqlite3.connect(self.dburi) @@ -82,10 +82,10 @@ class SqliteStore(CSStore): log_error("Error listing (filter: %s): [%r]" % (key, repr(err))) raise CSStoreError('Error occurred while trying to list keys') if len(rows) > 0: - value = dict() + value = list() for row in rows: - value[row[0]] = row[1] - return value + value.append(row[0]) + return sorted(value) else: return None @@ -135,10 +135,10 @@ class SqliteStoreTests(unittest.TestCase): def test_3_list_key(self): value = self.store.list('key') - self.assertEqual(value, {'key': 'value'}) + self.assertEqual(value, ['key']) value = self.store.list('k') - self.assertEqual(value, {'key': 'value'}) + self.assertEqual(value, ['key']) value = self.store.list('none') self.assertEqual(value, None) @@ -152,26 +152,22 @@ class SqliteStoreTests(unittest.TestCase): self.store.set('/oth3/key1', 'value31') value = self.store.list() - self.assertEqual(value, {'/sub1/key1': 'value11', - '/sub1/key2': 'value12', - '/sub1/key3': 'value13', - '/sub2/key1': 'value21', - '/sub2/key2': 'value22', - '/oth3/key1': 'value31'}) + self.assertEqual(value, + sorted(['/sub1/key1', '/sub1/key2', + '/sub1/key3', '/sub2/key1', + '/sub2/key2', '/oth3/key1'])) value = self.store.list('/sub') - self.assertEqual(value, {'/sub1/key1': 'value11', - '/sub1/key2': 'value12', - '/sub1/key3': 'value13', - '/sub2/key1': 'value21', - '/sub2/key2': 'value22'}) + self.assertEqual(value, + sorted(['/sub1/key1', '/sub1/key2', + '/sub1/key3', '/sub2/key1', + '/sub2/key2'])) value = self.store.list('/sub2') - self.assertEqual(value, {'/sub2/key1': 'value21', - '/sub2/key2': 'value22'}) + self.assertEqual(value, sorted(['/sub2/key1', '/sub2/key2'])) value = self.store.list('/o') - self.assertEqual(value, {'/oth3/key1': 'value31'}) + self.assertEqual(value, ['/oth3/key1']) value = self.store.list('/x') self.assertEqual(value, None) -- cgit