Revision 6f4bce7b pithos/backends/modular.py

b/pithos/backends/modular.py
39 39
import binascii
40 40

  
41 41
from base import NotAllowedError, BaseBackend
42
from lib.permissions import Permissions
42
from lib.permissions import Permissions, READ, WRITE
43 43
from lib.hashfiler import Mapper, Blocker
44 44

  
45 45

  
......
460 460
        if user != account:
461 461
            raise NotAllowedError
462 462
        path = self._get_objectinfo(account, container, name)[0]
463
        r, w = self._check_permissions(path, permissions)
464
        self._put_permissions(path, r, w)
463
        self._check_permissions(path, permissions)
464
        self._put_permissions(path, permissions)
465 465
    
466 466
    @backend_method
467 467
    def get_object_public(self, user, account, container, name):
......
509 509
        path = self._get_containerinfo(account, container)[0]
510 510
        path = '/'.join((path, name))
511 511
        if permissions is not None:
512
            r, w = self._check_permissions(path, permissions)
512
            self._check_permissions(path, permissions)
513 513
        src_version_id, dest_version_id = self._copy_version(user, path, path, not replace_meta, False)
514 514
        sql = 'update versions set size = ? where version_id = ?'
515 515
        self.con.execute(sql, (size, dest_version_id))
......
518 518
            sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)'
519 519
            self.con.execute(sql, (dest_version_id, k, v))
520 520
        if permissions is not None:
521
            self._put_permissions(path, r, w)
521
            self._put_permissions(path, permissions)
522 522
    
523 523
    @backend_method
524 524
    def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None, src_version=None):
......
537 537
        dest_path = self._get_containerinfo(account, dest_container)[0]
538 538
        dest_path = '/'.join((dest_path, dest_name))
539 539
        if permissions is not None:
540
            r, w = self._check_permissions(dest_path, permissions)
540
            self._check_permissions(dest_path, permissions)
541 541
        src_version_id, dest_version_id = self._copy_version(user, src_path, dest_path, not replace_meta, True, src_version)
542 542
        for k, v in dest_meta.iteritems():
543 543
            sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)'
544 544
            self.con.execute(sql, (dest_version_id, k, v))
545 545
        if permissions is not None:
546
            self._put_permissions(dest_path, r, w)
546
            self._put_permissions(dest_path, permissions)
547 547
    
548 548
    @backend_method
549 549
    def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions=None):
......
836 836
        pass
837 837
    
838 838
    def _get_groups(self, account):
839
        groups = {}
840
        for row in self.permissions.group_list(account):
841
            if group not in groups:
842
                groups[group] = []
843
            groups[group].append(member)
844
        return groups
839
        return self.permissions.group_dict(account)
845 840
    
846 841
    def _put_groups(self, account, groups, replace=False):
847 842
        if replace:
......
855 850
    def _del_groups(self, account):
856 851
        self.permissions.group_destroy(account)
857 852
    
858
    # ---------------- UP TO HERE ----------------
859
    
860 853
    def _check_permissions(self, path, permissions):
861 854
        # Check for existing permissions.
862
        sql = '''select name from permissions
863
                    where name != ? and (name like ? or ? like name || ?)'''
864
        c = self.con.execute(sql, (path, path + '%', path, '%'))
865
        row = c.fetchone()
866
        if row:
855
        paths = self.permissions.access_list(path)
856
        if paths:
867 857
            ae = AttributeError()
868
            ae.data = row[0]
858
            ae.data = paths
869 859
            raise ae
870 860
        
871
        # Format given permissions.
872
        if len(permissions) == 0:
873
            return [], []
874
        r = permissions.get('read', [])
875
        w = permissions.get('write', [])
876 861
        # Examples follow.
877 862
        # if True in [False or ',' in x for x in r]:
878 863
        #     raise ValueError('Bad characters in read permissions')
879 864
        # if True in [False or ',' in x for x in w]:
880 865
        #     raise ValueError('Bad characters in write permissions')
881
        return r, w
866
        pass
882 867
    
883 868
    def _get_permissions(self, path):
884
        # Check for permissions at path or above.
885
        sql = 'select name, op, user from permissions where ? like name || ?'
886
        c = self.con.execute(sql, (path, '%'))
887
        name = path
888
        perms = {} # Return nothing, if nothing is set.
889
        for row in c.fetchall():
890
            name = row[0]
891
            if row[1] not in perms:
892
                perms[row[1]] = []
893
            perms[row[1]].append(row[2])
894
        return name, perms
895
    
896
    def _put_permissions(self, path, r, w):
897
        sql = 'delete from permissions where name = ?'
898
        self.con.execute(sql, (path,))
899
        sql = 'insert into permissions (name, op, user) values (?, ?, ?)'
869
        self.permissions.access_inherit(path)
870
    
871
    def _put_permissions(self, path, permissions):
872
        self.permissions.access_revoke_all(path)
873
        r = permissions.get('read', [])
900 874
        if r:
901
            self.con.executemany(sql, [(path, 'read', x) for x in r])
875
            self.permissions.access_grant(path, READ, r)
876
        w = permissions.get('write', [])
902 877
        if w:
903
            self.con.executemany(sql, [(path, 'write', x) for x in w])
878
            self.permissions.access_grant(path, WRITE, w)
904 879
    
905 880
    def _get_public(self, path):
906
        sql = 'select name from public where name = ?'
907
        c = self.con.execute(sql, (path,))
908
        row = c.fetchone()
909
        if not row:
910
            return False
911
        return True
881
        return self.permissions.public_check(path)
912 882
    
913 883
    def _put_public(self, path, public):
914 884
        if not public:
915
            sql = 'delete from public where name = ?'
885
            self.permissions.public_unset(path)
916 886
        else:
917
            sql = 'insert or replace into public (name) values (?)'
918
        self.con.execute(sql, (path,))
887
            self.permissions.public_set(path)
919 888
    
920 889
    def _del_sharing(self, path):
921
        sql = 'delete from permissions where name = ?'
922
        self.con.execute(sql, (path,))
923
        sql = 'delete from public where name = ?'
924
        self.con.execute(sql, (path,))
890
        self.permissions.access_revoke_all(path)
891
        self.permissions.public_unset(path)
925 892
    
926
    def _is_allowed(self, user, account, container, name, op='read'):
893
    def _can_read(self, user, account, container, name):
927 894
        if user == account:
928 895
            return True
929 896
        path = '/'.join((account, container, name))
930
        if op == 'read' and self._get_public(path):
931
            return True
932
        perm_path, perms = self._get_permissions(path)
933
        
934
        # Expand groups.
935
        for x in ('read', 'write'):
936
            g_perms = set()
937
            for y in perms.get(x, []):
938
                if ':' in y:
939
                    g_account, g_name = y.split(':', 1)
940
                    groups = self._get_groups(g_account)
941
                    if g_name in groups:
942
                        g_perms.update(groups[g_name])
943
                else:
944
                    g_perms.add(y)
945
            perms[x] = g_perms
946
        
947
        if op == 'read' and ('*' in perms['read'] or user in perms['read']):
948
            return True
949
        if '*' in perms['write'] or user in perms['write']:
950
            return True
951
        return False
952
    
953
    def _can_read(self, user, account, container, name):
954
        if not self._is_allowed(user, account, container, name, 'read'):
897
        if not self.permissions.access_check(path, READ, user) and not self.permissions.access_check(path, WRITE, user):
955 898
            raise NotAllowedError
956 899
    
957 900
    def _can_write(self, user, account, container, name):
958
        if not self._is_allowed(user, account, container, name, 'write'):
901
        if user == account:
902
            return True
903
        path = '/'.join((account, container, name))
904
        if not self.permissions.access_check(path, WRITE, user):
959 905
            raise NotAllowedError
960 906
    
961 907
    def _allowed_paths(self, user, prefix=None):
962
        sql = '''select distinct name from permissions where (user = ?
963
                    or user in (select account || ':' || gname from groups where user = ?))'''
964
        param = (user, user)
965 908
        if prefix:
966
            sql += ' and name like ?'
967
            param += (prefix + '/%',)
968
        c = self.con.execute(sql, param)
969
        return [x[0] for x in c.fetchall()]
909
            prefix += '/'
910
        return self.permissions.access_list_paths(user, prefix)
970 911
    
971 912
    def _allowed_accounts(self, user):
972 913
        allow = set()
......
981 922
        return sorted(allow)
982 923
    
983 924
    def _shared_paths(self, prefix):
984
        sql = 'select distinct name from permissions where name like ?'
985
        c = self.con.execute(sql, (prefix + '/%',))
986
        return [x[0] for x in c.fetchall()]
925
        prefix += '/'
926
        return self.permissions.access_list_shared(prefix)

Also available in: Unified diff