From e0f916bb159d6a17967acf4d513635ec589ab48e Mon Sep 17 00:00:00 2001 From: Antony Chazapis Date: Mon, 4 Jul 2011 15:01:29 +0300 Subject: [PATCH] New public objects implementation. Fixes #595 --- pithos/api/functions.py | 32 +++++++++++++++++++++++++++++++- pithos/api/util.py | 14 +++++++++++++- pithos/backends/simple.py | 33 ++++++++++++++++++++++++++++++--- pithos/public/functions.py | 10 ++++------ 4 files changed, 78 insertions(+), 11 deletions(-) diff --git a/pithos/api/functions.py b/pithos/api/functions.py index 4652c18..461c33e 100644 --- a/pithos/api/functions.py +++ b/pithos/api/functions.py @@ -45,7 +45,7 @@ from pithos.api.faults import (Fault, NotModified, BadRequest, Unauthorized, Ite LengthRequired, PreconditionFailed, RangeNotSatisfiable, UnprocessableEntity) from pithos.api.util import (format_header_key, printable_header_dict, get_account_headers, put_account_headers, get_container_headers, put_container_headers, get_object_headers, put_object_headers, - update_manifest_meta, update_sharing_meta, validate_modification_preconditions, + update_manifest_meta, update_sharing_meta, update_public_meta, validate_modification_preconditions, validate_matching_preconditions, split_container_object_string, copy_or_move_object, get_int_parameter, get_content_length, get_content_range, raw_input_socket, socket_read_iterator, object_data_response, put_object_block, hashmap_hash, api_method) @@ -412,13 +412,16 @@ def object_list(request, v_account, v_container): meta = backend.get_object_meta(request.user, v_account, v_container, x[0], x[1]) if until is None: permissions = backend.get_object_permissions(request.user, v_account, v_container, x[0]) + public = backend.get_object_public(request.user, v_account, v_container, x[0]) else: permissions = None + public = None except NotAllowedError: raise Unauthorized('Access denied') except NameError: pass update_sharing_meta(permissions, v_account, v_container, x[0], meta) + update_public_meta(public, meta) object_meta.append(printable_header_dict(meta)) if request.serialization == 'xml': data = render_to_string('objects.xml', {'container': v_container, 'objects': object_meta}) @@ -441,8 +444,10 @@ def object_meta(request, v_account, v_container, v_object): meta = backend.get_object_meta(request.user, v_account, v_container, v_object, version) if version is None: permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) + public = backend.get_object_public(request.user, v_account, v_container, v_object) else: permissions = None + public = None except NotAllowedError: raise Unauthorized('Access denied') except NameError: @@ -452,6 +457,7 @@ def object_meta(request, v_account, v_container, v_object): update_manifest_meta(request, v_account, meta) update_sharing_meta(permissions, v_account, v_container, v_object, meta) + update_public_meta(public, meta) response = HttpResponse(status=200) put_object_headers(response, meta) @@ -494,8 +500,10 @@ def object_read(request, v_account, v_container, v_object): meta = backend.get_object_meta(request.user, v_account, v_container, v_object, version) if version is None: permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) + public = backend.update_object_public(request.user, v_account, v_container, v_object) else: permissions = None + public = None except NotAllowedError: raise Unauthorized('Access denied') except NameError: @@ -505,6 +513,7 @@ def object_read(request, v_account, v_container, v_object): update_manifest_meta(request, v_account, meta) update_sharing_meta(permissions, v_account, v_container, v_object, meta) + update_public_meta(public, meta) # Evaluate conditions. validate_modification_preconditions(request, meta) @@ -656,6 +665,13 @@ def object_write(request, v_account, v_container, v_object): raise BadRequest('Invalid sharing header') except AttributeError: raise Conflict('Sharing already set above or below this path in the hierarchy') + if public is not None: + try: + backend.update_object_public(request.user, v_account, v_container, v_object, public) + except NotAllowedError: + raise Unauthorized('Access denied') + except NameError: + raise ItemNotFound('Object does not exist') response = HttpResponse(content=payload, status=code) response['ETag'] = meta['hash'] @@ -740,6 +756,13 @@ def object_update(request, v_account, v_container, v_object): raise BadRequest('Invalid sharing header') except AttributeError: raise Conflict('Sharing already set above or below this path in the hierarchy') + if public is not None: + try: + backend.update_object_public(request.user, v_account, v_container, v_object, public) + except NotAllowedError: + raise Unauthorized('Access denied') + except NameError: + raise ItemNotFound('Object does not exist') try: backend.update_object_meta(request.user, v_account, v_container, v_object, meta, replace) except NotAllowedError: @@ -806,6 +829,13 @@ def object_update(request, v_account, v_container, v_object): raise BadRequest('Invalid sharing header') except AttributeError: raise Conflict('Sharing already set above or below this path in the hierarchy') + if public is not None: + try: + backend.update_object_public(request.user, v_account, v_container, v_object, public) + except NotAllowedError: + raise Unauthorized('Access denied') + except NameError: + raise ItemNotFound('Object does not exist') response = HttpResponse(status=204) response['ETag'] = meta['hash'] diff --git a/pithos/api/util.py b/pithos/api/util.py index 53676ce..342242e 100644 --- a/pithos/api/util.py +++ b/pithos/api/util.py @@ -148,7 +148,7 @@ def put_object_headers(response, meta, restricted=False): response['X-Object-Version-Timestamp'] = http_date(int(meta['version_timestamp'])) for k in [x for x in meta.keys() if x.startswith('X-Object-Meta-')]: response[k.encode('utf-8')] = meta[k].encode('utf-8') - for k in ('Content-Encoding', 'Content-Disposition', 'X-Object-Manifest', 'X-Object-Sharing', 'X-Object-Shared-By'): + for k in ('Content-Encoding', 'Content-Disposition', 'X-Object-Manifest', 'X-Object-Sharing', 'X-Object-Shared-By', 'X-Object-Public'): if k in meta: response[k] = meta[k] else: @@ -194,6 +194,11 @@ def update_sharing_meta(permissions, v_account, v_container, v_object, meta): if '/'.join((v_account, v_container, v_object)) != perm_path: meta['X-Object-Shared-By'] = perm_path +def update_public_meta(public, meta): + if not public: + return + meta['X-Object-Public'] = public + def validate_modification_preconditions(request, meta): """Check that the modified timestamp conforms with the preconditions set.""" @@ -255,6 +260,13 @@ def copy_or_move_object(request, v_account, src_container, src_name, dest_contai raise BadRequest('Invalid sharing header') except AttributeError: raise Conflict('Sharing already set above or below this path in the hierarchy') + if public is not None: + try: + backend.update_object_public(request.user, v_account, v_container, v_object, public) + except NotAllowedError: + raise Unauthorized('Access denied') + except NameError: + raise ItemNotFound('Object does not exist') def get_int_parameter(request, name): p = request.GET.get(name) diff --git a/pithos/backends/simple.py b/pithos/backends/simple.py index f93d5b6..137e8ab 100644 --- a/pithos/backends/simple.py +++ b/pithos/backends/simple.py @@ -85,11 +85,14 @@ class SimpleBackend(BaseBackend): sql = '''create table if not exists groups ( account text, name text, users text, primary key (account, name))''' self.con.execute(sql) + sql = '''create table if not exists policy ( + name text, key text, value text, primary key (name, key))''' + self.con.execute(sql) sql = '''create table if not exists permissions ( name text, read text, write text, primary key (name))''' self.con.execute(sql) - sql = '''create table if not exists policy ( - name text, key text, value text, primary key (name, key))''' + sql = '''create table if not exists public ( + name text, primary key (name))''' self.con.execute(sql) self.con.commit() @@ -351,13 +354,19 @@ class SimpleBackend(BaseBackend): """Return the public URL of the object if applicable.""" logger.debug("get_object_public: %s %s %s", account, container, name) + self._can_read(user, account, container, name) + path = self._get_objectinfo(account, container, name)[0] + if self._get_public(path): + return '/public/' + path return None def update_object_public(self, user, account, container, name, public): """Update the public status of the object.""" logger.debug("update_object_public: %s %s %s %s", account, container, name, public) - return + self._can_write(user, account, container, name) + path = self._get_objectinfo(account, container, name)[0] + self._put_public(path, public) def get_object_hashmap(self, user, account, container, name, version=None): """Return the object's size and a list with partial hashes.""" @@ -649,6 +658,8 @@ class SimpleBackend(BaseBackend): if user == account: return True path = os.path.join(account, container, name) + if op == 'read' and self._get_public(path): + return True perm_path, perms = self._get_permissions(path) # Expand groups. @@ -723,6 +734,22 @@ class SimpleBackend(BaseBackend): self.con.execute(sql, (path, r, w)) self.con.commit() + def _get_public(self, path): + sql = 'select name from public where name = ?' + c = self.con.execute(sql, (path,)) + row = c.fetchone() + if not row: + return False + return True + + def _put_public(self, path, public): + if not public: + sql = 'delete from public where name = ?' + else: + sql = 'insert or replace into public (name) values (?)' + self.con.execute(sql, (path,)) + self.con.commit() + def _list_objects(self, path, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], until=None): cont_prefix = path + '/' if keys and len(keys) > 0: diff --git a/pithos/public/functions.py b/pithos/public/functions.py index ecbc3b8..6eb2c04 100644 --- a/pithos/public/functions.py +++ b/pithos/public/functions.py @@ -65,12 +65,11 @@ def object_meta(request, v_account, v_container, v_object): try: meta = backend.get_object_meta(request.user, v_account, v_container, v_object) - permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) + public = backend.get_object_public(request.user, v_account, v_container, v_object) except: raise ItemNotFound('Object does not exist') - # TODO: Fix public indicator. - if 'public' not in permissions: + if not public: raise ItemNotFound('Object does not exist') update_manifest_meta(request, v_account, meta) @@ -91,12 +90,11 @@ def object_read(request, v_account, v_container, v_object): try: meta = backend.get_object_meta(request.user, v_account, v_container, v_object) - permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) + public = backend.get_object_public(request.user, v_account, v_container, v_object) except: raise ItemNotFound('Object does not exist') - # TODO: Fix public indicator. - if 'public' not in permissions: + if not public: raise ItemNotFound('Object does not exist') update_manifest_meta(request, v_account, meta) -- 1.7.10.4