diff options
author | Simo Sorce <simo@redhat.com> | 2015-10-07 13:50:15 -0400 |
---|---|---|
committer | Simo Sorce <simo@redhat.com> | 2015-10-19 12:17:07 -0400 |
commit | ed3dd0d4c63b424bd5e6d7ba79779caf42f3de7b (patch) | |
tree | 98fa4c62969c38f79e9c552ebe3f4c98e2c4167d | |
parent | b2d829bbcaf0a676b86238fced9cdc2b1ef9c074 (diff) | |
download | custodia-ed3dd0d4c63b424bd5e6d7ba79779caf42f3de7b.tar.gz custodia-ed3dd0d4c63b424bd5e6d7ba79779caf42f3de7b.tar.xz custodia-ed3dd0d4c63b424bd5e6d7ba79779caf42f3de7b.zip |
Remove filter option for directory listings
This commit removes the option to pas a filter parameter.
It also changes the way database plugins are expected to return
results, results are now expected to be relative to the path
requested.
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Christian Heimes <cheimes@redhat.com>
-rw-r--r-- | API.md | 4 | ||||
-rw-r--r-- | custodia/secrets.py | 53 | ||||
-rw-r--r-- | custodia/store/sqlite.py | 56 |
3 files changed, 42 insertions, 71 deletions
@@ -160,9 +160,7 @@ Listing containers A GET operation on a path that ends in a '/' translates into a listing for a container. -A 'filter' query argument may be provided to filter on key/container -names within the container being listed. -GET /secrets/container/?filter=red +GET /secrets/container/ Implementations may assume a default container if none is excplicitly provided: GET /secrets/ may return only keys under /<user-default>/* diff --git a/custodia/secrets.py b/custodia/secrets.py index 558bc39..3f01afb 100644 --- a/custodia/secrets.py +++ b/custodia/secrets.py @@ -79,25 +79,22 @@ class Secrets(HTTPConsumer): def _parent_exists(self, default, trail): # check that the containers exist - basename = self._db_container_key(trail[0], '') + basename = self._db_container_key(trail[0], trail[:-1] + ['']) try: keylist = self.root.store.list(basename) except CSStoreError: raise HTTPError(500) + if keylist is not None: + return True + # create default namespace if it is the only missing piece - if keylist is None and len(trail) == 2 and default == trail[0]: + if len(trail) == 2 and default == trail[0]: container = self._db_container_key(default, '') self.root.store.set(container, '') return True - # 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 + return False def GET(self, request, response): trail = request.get('trail', []) @@ -132,20 +129,11 @@ class Secrets(HTTPConsumer): def _list(self, trail, request, response): default = request.get('default_namespace', None) basename = self._db_container_key(default, trail) - userfilter = request.get('query', dict()).get('filter', '') try: - keylist = self.root.store.list(basename + userfilter) + keylist = self.root.store.list(basename) if keylist is None: raise HTTPError(404) - # 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/'):] - output.append(name) - response['output'] = json.dumps(output) + response['output'] = json.dumps(keylist) except CSStoreError: raise HTTPError(500) @@ -171,10 +159,7 @@ class Secrets(HTTPConsumer): keylist = self.root.store.list(basename) if keylist is None: raise HTTPError(404) - if basename not in keylist: - # uh ? - raise HTTPError(409) - if len(keylist) != 1: + if len(keylist) != 0: raise HTTPError(409) ret = self.root.store.cut(basename) except CSStoreError: @@ -354,16 +339,7 @@ class SecretsTests(unittest.TestCase): rep = {} self.GET(req, rep) self.assertEqual(json.loads(rep['output']), - json.loads('["test/key1"]')) - - def test_3_LISTKeys_2(self): - req = {'remote_user': 'test', - 'query': {'filter': 'key'}, - 'trail': ['test', '']} - rep = {} - self.GET(req, rep) - self.assertEqual(json.loads(rep['output']), - json.loads('["test/key1"]')) + json.loads('["key1"]')) def test_4_PUTKey_errors_400_1(self): req = {'headers': {'Content-Type': 'text/plain'}, @@ -470,15 +446,6 @@ class SecretsTests(unittest.TestCase): self.GET(req, rep) self.assertEqual(err.exception.code, 404) - def test_6_LISTkeys_errors_404_2(self): - req = {'remote_user': 'test', - 'query': {'filter': 'foo'}, - 'trail': ['test', '']} - rep = {} - with self.assertRaises(HTTPError) as err: - self.GET(req, rep) - self.assertEqual(err.exception.code, 404) - def test_7_DELETEKey(self): req = {'remote_user': 'test', 'trail': ['test', 'key1']} diff --git a/custodia/store/sqlite.py b/custodia/store/sqlite.py index 44d139f..482787a 100644 --- a/custodia/store/sqlite.py +++ b/custodia/store/sqlite.py @@ -74,23 +74,36 @@ class SqliteStore(CSStore): log_error("Error storing key %s: [%r]" % (key, repr(err))) raise CSStoreError('Error occurred while trying to store key') - def list(self, keyfilter='/'): + def list(self, keyfilter=''): + path = keyfilter.rstrip('/') + child_prefix = path if path == '' else path + '/' search = "SELECT key FROM %s WHERE key LIKE ?" % self.table - key = "%s%%" % (keyfilter,) + key = "%s%%" % (path,) try: conn = sqlite3.connect(self.dburi) r = conn.execute(search, (key,)) rows = r.fetchall() except sqlite3.Error as err: - log_error("Error listing (filter: %s): [%r]" % (key, repr(err))) + log_error("Error listing %s: [%r]" % (keyfilter, repr(err))) raise CSStoreError('Error occurred while trying to list keys') if len(rows) > 0: + parent_exists = False value = list() for row in rows: - value.append(row[0]) - return sorted(value) - else: - return None + if row[0] == path or row[0] == child_prefix: + parent_exists = True + continue + if not row[0].startswith(child_prefix): + continue + value.append(row[0][len(child_prefix):].lstrip('/')) + + if value: + return sorted(value) + elif parent_exists: + return [] + elif keyfilter == '': + return [] + return None def cut(self, key): query = "DELETE from %s WHERE key=?" % self.table @@ -124,7 +137,7 @@ class SqliteStoreTests(unittest.TestCase): value = self.store.get('test') self.assertEqual(value, None) - def test_1_list_empty(self): + def test_1_list_none(self): value = self.store.list('test') self.assertEqual(value, None) @@ -134,13 +147,10 @@ class SqliteStoreTests(unittest.TestCase): self.assertEqual(value, 'value') def test_3_list_key(self): - value = self.store.list('key') + value = self.store.list() self.assertEqual(value, ['key']) value = self.store.list('k') - self.assertEqual(value, ['key']) - - value = self.store.list('none') self.assertEqual(value, None) def test_4_multiple_keys(self): @@ -153,27 +163,23 @@ class SqliteStoreTests(unittest.TestCase): value = self.store.list() self.assertEqual(value, - sorted(['/sub1/key1', '/sub1/key2', - '/sub1/key3', '/sub2/key1', - '/sub2/key2', '/oth3/key1'])) + sorted(['key', + 'sub1/key1', 'sub1/key2', + 'sub1/key3', 'sub2/key1', + 'sub2/key2', 'oth3/key1'])) value = self.store.list('/sub') - self.assertEqual(value, - sorted(['/sub1/key1', '/sub1/key2', - '/sub1/key3', '/sub2/key1', - '/sub2/key2'])) + self.assertEqual(value, None) value = self.store.list('/sub2') - self.assertEqual(value, sorted(['/sub2/key1', '/sub2/key2'])) - - value = self.store.list('/o') - self.assertEqual(value, ['/oth3/key1']) + self.assertEqual(value, sorted(['key1', 'key2'])) + self.store.set('/x', '') value = self.store.list('/x') - self.assertEqual(value, None) + self.assertEqual(value, []) value = self.store.list('/sub1/key1/') - self.assertEqual(value, None) + self.assertEqual(value, []) value = self.store.get('/sub1') self.assertEqual(value, None) |