Revision b0a2d1a6 pithos/backends/simple.py
b/pithos/backends/simple.py | ||
---|---|---|
84 | 84 |
foreign key (version_id) references versions(version_id) |
85 | 85 |
on delete cascade)''' |
86 | 86 |
self.con.execute(sql) |
87 |
|
|
88 | 87 |
sql = '''create table if not exists policy ( |
89 | 88 |
name text, key text, value text, primary key (name, key))''' |
90 | 89 |
self.con.execute(sql) |
91 | 90 |
|
91 |
# Access control tables. |
|
92 | 92 |
sql = '''create table if not exists groups ( |
93 |
account text, name text, users text, primary key (account, name))'''
|
|
93 |
account text, gname text, user text)'''
|
|
94 | 94 |
self.con.execute(sql) |
95 | 95 |
sql = '''create table if not exists permissions ( |
96 |
name text, read text, write text, primary key (name))'''
|
|
96 |
name text, op text, user text)'''
|
|
97 | 97 |
self.con.execute(sql) |
98 | 98 |
sql = '''create table if not exists public ( |
99 | 99 |
name text, primary key (name))''' |
100 | 100 |
self.con.execute(sql) |
101 |
|
|
101 | 102 |
self.con.commit() |
102 | 103 |
|
103 | 104 |
params = {'blocksize': self.block_size, |
... | ... | |
167 | 168 |
logger.debug("update_account_groups: %s %s %s", account, groups, replace) |
168 | 169 |
if user != account: |
169 | 170 |
raise NotAllowedError |
170 |
for k, v in groups.iteritems(): |
|
171 |
if True in [False or ',' in x for x in v]: |
|
172 |
raise ValueError('Bad characters in groups') |
|
173 |
if replace: |
|
174 |
sql = 'delete from groups where account = ?' |
|
175 |
self.con.execute(sql, (account,)) |
|
176 |
for k, v in groups.iteritems(): |
|
177 |
if len(v) == 0: |
|
178 |
if not replace: |
|
179 |
sql = 'delete from groups where account = ? and name = ?' |
|
180 |
self.con.execute(sql, (account, k)) |
|
181 |
else: |
|
182 |
sql = 'insert or replace into groups (account, name, users) values (?, ?, ?)' |
|
183 |
self.con.execute(sql, (account, k, ','.join(v))) |
|
184 |
self.con.commit() |
|
171 |
self._check_groups(groups) |
|
172 |
self._put_groups(account, groups, replace) |
|
185 | 173 |
|
186 | 174 |
def put_account(self, user, account): |
187 | 175 |
"""Create a new account with the given name.""" |
... | ... | |
209 | 197 |
raise IndexError('Account is not empty') |
210 | 198 |
sql = 'delete from versions where name = ?' |
211 | 199 |
self.con.execute(sql, (account,)) |
212 |
sql = 'delete from groups where name = ?' |
|
213 |
self.con.execute(sql, (account,)) |
|
200 |
self._del_groups(account) |
|
214 | 201 |
self.con.commit() |
215 | 202 |
|
216 | 203 |
def list_containers(self, user, account, marker=None, limit=10000, until=None): |
... | ... | |
445 | 432 |
sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)' |
446 | 433 |
self.con.execute(sql, (dest_version_id, k, v)) |
447 | 434 |
if permissions is not None: |
448 |
sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)' |
|
449 |
self.con.execute(sql, (path, r, w)) |
|
435 |
self._put_permissions(path, r, w) |
|
450 | 436 |
self.con.commit() |
451 | 437 |
|
452 | 438 |
def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None, src_version=None): |
... | ... | |
471 | 457 |
sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)' |
472 | 458 |
self.con.execute(sql, (dest_version_id, k, v)) |
473 | 459 |
if permissions is not None: |
474 |
sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)' |
|
475 |
self.con.execute(sql, (dest_path, r, w)) |
|
460 |
self._put_permissions(dest_path, r, w) |
|
476 | 461 |
self.con.commit() |
477 | 462 |
|
478 | 463 |
def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None): |
... | ... | |
667 | 652 |
self.con.execute(sql, (dest_version_id, k, v)) |
668 | 653 |
self.con.commit() |
669 | 654 |
|
670 |
def _get_groups(self, account): |
|
671 |
sql = 'select name, users from groups where account = ?' |
|
672 |
c = self.con.execute(sql, (account,)) |
|
673 |
return dict([(x[0], x[1].split(',')) for x in c.fetchall()]) |
|
674 |
|
|
675 | 655 |
def _check_policy(self, policy): |
676 | 656 |
for k in policy.keys(): |
677 | 657 |
if policy[k] == '': |
... | ... | |
692 | 672 |
c = self.con.execute(sql, (path,)) |
693 | 673 |
return dict(c.fetchall()) |
694 | 674 |
|
675 |
def _list_objects(self, path, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], until=None): |
|
676 |
cont_prefix = path + '/' |
|
677 |
if keys and len(keys) > 0: |
|
678 |
sql = '''select distinct o.name, o.version_id from (%s) o, metadata m where o.name like ? and |
|
679 |
m.version_id = o.version_id and m.key in (%s) order by o.name''' |
|
680 |
sql = sql % (self._sql_until(until), ', '.join('?' * len(keys))) |
|
681 |
param = (cont_prefix + prefix + '%',) + tuple(keys) |
|
682 |
else: |
|
683 |
sql = 'select name, version_id from (%s) where name like ? order by name' |
|
684 |
sql = sql % self._sql_until(until) |
|
685 |
param = (cont_prefix + prefix + '%',) |
|
686 |
c = self.con.execute(sql, param) |
|
687 |
objects = [(x[0][len(cont_prefix):], x[1]) for x in c.fetchall()] |
|
688 |
if delimiter: |
|
689 |
pseudo_objects = [] |
|
690 |
for x in objects: |
|
691 |
pseudo_name = x[0] |
|
692 |
i = pseudo_name.find(delimiter, len(prefix)) |
|
693 |
if not virtual: |
|
694 |
# If the delimiter is not found, or the name ends |
|
695 |
# with the delimiter's first occurence. |
|
696 |
if i == -1 or len(pseudo_name) == i + len(delimiter): |
|
697 |
pseudo_objects.append(x) |
|
698 |
else: |
|
699 |
# If the delimiter is found, keep up to (and including) the delimiter. |
|
700 |
if i != -1: |
|
701 |
pseudo_name = pseudo_name[:i + len(delimiter)] |
|
702 |
if pseudo_name not in [y[0] for y in pseudo_objects]: |
|
703 |
if pseudo_name == x[0]: |
|
704 |
pseudo_objects.append(x) |
|
705 |
else: |
|
706 |
pseudo_objects.append((pseudo_name, None)) |
|
707 |
objects = pseudo_objects |
|
708 |
|
|
709 |
start = 0 |
|
710 |
if marker: |
|
711 |
try: |
|
712 |
start = [x[0] for x in objects].index(marker) + 1 |
|
713 |
except ValueError: |
|
714 |
pass |
|
715 |
if not limit or limit > 10000: |
|
716 |
limit = 10000 |
|
717 |
return objects[start:start + limit] |
|
718 |
|
|
719 |
def _del_version(self, version): |
|
720 |
self.mapper.map_remv(version) |
|
721 |
sql = 'delete from versions where version_id = ?' |
|
722 |
self.con.execute(sql, (version,)) |
|
723 |
|
|
724 |
# Access control functions. |
|
725 |
|
|
726 |
def _check_groups(self, groups): |
|
727 |
# Example follows. |
|
728 |
# for k, v in groups.iteritems(): |
|
729 |
# if True in [False or ',' in x for x in v]: |
|
730 |
# raise ValueError('Bad characters in groups') |
|
731 |
pass |
|
732 |
|
|
733 |
def _get_groups(self, account): |
|
734 |
sql = 'select gname, user from groups where account = ?' |
|
735 |
c = self.con.execute(sql, (account,)) |
|
736 |
groups = {} |
|
737 |
for row in c.fetchall(): |
|
738 |
if row[0] not in groups: |
|
739 |
groups[row[0]] = [] |
|
740 |
groups[row[0]].append(row[1]) |
|
741 |
return groups |
|
742 |
|
|
743 |
def _put_groups(self, account, groups, replace=False): |
|
744 |
if replace: |
|
745 |
self._del_groups(account) |
|
746 |
for k, v in groups.iteritems(): |
|
747 |
sql = 'delete from groups where account = ? and gname = ?' |
|
748 |
self.con.execute(sql, (account, k)) |
|
749 |
if v: |
|
750 |
sql = 'insert into groups (account, gname, user) values (?, ?, ?)' |
|
751 |
self.con.executemany(sql, [(account, k, x) for x in v]) |
|
752 |
self.con.commit() |
|
753 |
|
|
754 |
def _del_groups(self, account): |
|
755 |
sql = 'delete from groups where account = ?' |
|
756 |
self.con.execute(sql, (account,)) |
|
757 |
|
|
695 | 758 |
def _is_allowed(self, user, account, container, name, op='read'): |
696 | 759 |
if user == account: |
697 | 760 |
return True |
... | ... | |
702 | 765 |
|
703 | 766 |
# Expand groups. |
704 | 767 |
for x in ('read', 'write'): |
705 |
g_perms = []
|
|
768 |
g_perms = set()
|
|
706 | 769 |
for y in perms.get(x, []): |
707 |
groups = self._get_groups(account) |
|
708 |
if y in groups: #it's a group |
|
709 |
for g_name in groups[y]: |
|
710 |
g_perms.append(g_name) |
|
711 |
else: #it's a user |
|
712 |
g_perms.append(y) |
|
770 |
if ':' in y: |
|
771 |
g_account, g_name = y.split(':', 1) |
|
772 |
groups = self._get_groups(g_account) |
|
773 |
if g_name in groups: |
|
774 |
g_perms.update(groups[g_name]) |
|
775 |
else: |
|
776 |
g_perms.add(y) |
|
713 | 777 |
perms[x] = g_perms |
714 | 778 |
|
715 |
if op == 'read' and user in perms.get('read', []):
|
|
779 |
if op == 'read' and ('*' in perms['read'] or user in perms['read']):
|
|
716 | 780 |
return True |
717 |
if user in perms.get('write', []):
|
|
781 |
if '*' in perms['write'] or user in perms['write']:
|
|
718 | 782 |
return True |
719 | 783 |
return False |
720 | 784 |
|
... | ... | |
739 | 803 |
|
740 | 804 |
# Format given permissions. |
741 | 805 |
if len(permissions) == 0: |
742 |
return '', ''
|
|
806 |
return [], []
|
|
743 | 807 |
r = permissions.get('read', []) |
744 | 808 |
w = permissions.get('write', []) |
745 |
if True in [False or ',' in x for x in r]: |
|
746 |
raise ValueError('Bad characters in read permissions') |
|
747 |
if True in [False or ',' in x for x in w]: |
|
748 |
raise ValueError('Bad characters in write permissions') |
|
749 |
return ','.join(r), ','.join(w) |
|
809 |
# Examples follow. |
|
810 |
# if True in [False or ',' in x for x in r]: |
|
811 |
# raise ValueError('Bad characters in read permissions') |
|
812 |
# if True in [False or ',' in x for x in w]: |
|
813 |
# raise ValueError('Bad characters in write permissions') |
|
814 |
return r, w |
|
750 | 815 |
|
751 | 816 |
def _get_permissions(self, path): |
752 | 817 |
# Check for permissions at path or above. |
753 |
sql = 'select name, read, write from permissions where ? like name || ?'
|
|
818 |
sql = 'select name, op, user from permissions where ? like name || ?'
|
|
754 | 819 |
c = self.con.execute(sql, (path, '%')) |
755 |
row = c.fetchone() |
|
756 |
if not row: |
|
757 |
return path, {} |
|
758 |
|
|
759 |
name, r, w = row |
|
760 |
ret = {} |
|
761 |
if w != '': |
|
762 |
ret['write'] = w.split(',') |
|
763 |
if r != '': |
|
764 |
ret['read'] = r.split(',') |
|
765 |
return name, ret |
|
820 |
name = path |
|
821 |
perms = {} # Return nothing, if nothing is set. |
|
822 |
for row in c.fetchall(): |
|
823 |
name = row[0] |
|
824 |
if row[1] not in perms: |
|
825 |
perms[row[1]] = [] |
|
826 |
perms[row[1]].append(row[2]) |
|
827 |
return name, perms |
|
766 | 828 |
|
767 | 829 |
def _put_permissions(self, path, r, w): |
768 |
if r == '' and w == '': |
|
769 |
sql = 'delete from permissions where name = ?' |
|
770 |
self.con.execute(sql, (path,)) |
|
771 |
else: |
|
772 |
sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)' |
|
773 |
self.con.execute(sql, (path, r, w)) |
|
830 |
sql = 'delete from permissions where name = ?' |
|
831 |
self.con.execute(sql, (path,)) |
|
832 |
sql = 'insert into permissions (name, op, user) values (?, ?, ?)' |
|
833 |
if r: |
|
834 |
self.con.executemany(sql, [(path, 'read', x) for x in r]) |
|
835 |
if w: |
|
836 |
self.con.executemany(sql, [(path, 'write', x) for x in w]) |
|
774 | 837 |
self.con.commit() |
775 | 838 |
|
776 | 839 |
def _get_public(self, path): |
... | ... | |
795 | 858 |
sql = 'delete from public where name = ?' |
796 | 859 |
self.con.execute(sql, (path,)) |
797 | 860 |
self.con.commit() |
798 |
|
|
799 |
def _list_objects(self, path, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], until=None): |
|
800 |
cont_prefix = path + '/' |
|
801 |
if keys and len(keys) > 0: |
|
802 |
sql = '''select distinct o.name, o.version_id from (%s) o, metadata m where o.name like ? and |
|
803 |
m.version_id = o.version_id and m.key in (%s) order by o.name''' |
|
804 |
sql = sql % (self._sql_until(until), ', '.join('?' * len(keys))) |
|
805 |
param = (cont_prefix + prefix + '%',) + tuple(keys) |
|
806 |
else: |
|
807 |
sql = 'select name, version_id from (%s) where name like ? order by name' |
|
808 |
sql = sql % self._sql_until(until) |
|
809 |
param = (cont_prefix + prefix + '%',) |
|
810 |
c = self.con.execute(sql, param) |
|
811 |
objects = [(x[0][len(cont_prefix):], x[1]) for x in c.fetchall()] |
|
812 |
if delimiter: |
|
813 |
pseudo_objects = [] |
|
814 |
for x in objects: |
|
815 |
pseudo_name = x[0] |
|
816 |
i = pseudo_name.find(delimiter, len(prefix)) |
|
817 |
if not virtual: |
|
818 |
# If the delimiter is not found, or the name ends |
|
819 |
# with the delimiter's first occurence. |
|
820 |
if i == -1 or len(pseudo_name) == i + len(delimiter): |
|
821 |
pseudo_objects.append(x) |
|
822 |
else: |
|
823 |
# If the delimiter is found, keep up to (and including) the delimiter. |
|
824 |
if i != -1: |
|
825 |
pseudo_name = pseudo_name[:i + len(delimiter)] |
|
826 |
if pseudo_name not in [y[0] for y in pseudo_objects]: |
|
827 |
if pseudo_name == x[0]: |
|
828 |
pseudo_objects.append(x) |
|
829 |
else: |
|
830 |
pseudo_objects.append((pseudo_name, None)) |
|
831 |
objects = pseudo_objects |
|
832 |
|
|
833 |
start = 0 |
|
834 |
if marker: |
|
835 |
try: |
|
836 |
start = [x[0] for x in objects].index(marker) + 1 |
|
837 |
except ValueError: |
|
838 |
pass |
|
839 |
if not limit or limit > 10000: |
|
840 |
limit = 10000 |
|
841 |
return objects[start:start + limit] |
|
842 |
|
|
843 |
def _del_version(self, version): |
|
844 |
self.mapper.map_remv(version) |
|
845 |
sql = 'delete from versions where version_id = ?' |
|
846 |
self.con.execute(sql, (version,)) |
Also available in: Unified diff