summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2015-10-07 13:50:15 -0400
committerSimo Sorce <simo@redhat.com>2015-10-19 12:17:07 -0400
commited3dd0d4c63b424bd5e6d7ba79779caf42f3de7b (patch)
tree98fa4c62969c38f79e9c552ebe3f4c98e2c4167d
parentb2d829bbcaf0a676b86238fced9cdc2b1ef9c074 (diff)
downloadcustodia-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.md4
-rw-r--r--custodia/secrets.py53
-rw-r--r--custodia/store/sqlite.py56
3 files changed, 42 insertions, 71 deletions
diff --git a/API.md b/API.md
index eb78581..ead0344 100644
--- a/API.md
+++ b/API.md
@@ -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)