5fd85088f8be48aa85a5e09afc2c91c882ef40db
[pithos] / pithos / backends / lib / sqlite / permissions.py
1 # Copyright 2011-2012 GRNET S.A. All rights reserved.
2
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
5 # conditions are met:
6
7 #   1. Redistributions of source code must retain the above
8 #      copyright notice, this list of conditions and the following
9 #      disclaimer.
10
11 #   2. Redistributions in binary form must reproduce the above
12 #      copyright notice, this list of conditions and the following
13 #      disclaimer in the documentation and/or other materials
14 #      provided with the distribution.
15
16 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
28
29 # The views and conclusions contained in the software and
30 # documentation are those of the authors and should not be
31 # interpreted as representing official policies, either expressed
32 # or implied, of GRNET S.A.
33
34 from xfeatures import XFeatures
35 from groups import Groups
36 from public import Public
37
38
39 READ = 0
40 WRITE = 1
41
42
43 class Permissions(XFeatures, Groups, Public):
44     
45     def __init__(self, **params):
46         XFeatures.__init__(self, **params)
47         Groups.__init__(self, **params)
48         Public.__init__(self, **params)
49     
50     def access_grant(self, path, access, members=()):
51         """Grant members with access to path.
52            Members can also be '*' (all),
53            or some group specified as 'owner:group'."""
54         
55         if not members:
56             return
57         feature = self.xfeature_create(path)
58         self.feature_setmany(feature, access, members)
59     
60     def access_set(self, path, permissions):
61         """Set permissions for path. The permissions dict
62            maps 'read', 'write' keys to member lists."""
63         
64         self.xfeature_destroy(path)
65         self.access_grant(path, READ, permissions.get('read', []))
66         self.access_grant(path, WRITE, permissions.get('write', []))
67     
68     def access_clear(self, path):
69         """Revoke access to path (both permissions and public)."""
70         
71         self.xfeature_destroy(path)
72         self.public_unset(path)
73     
74     def access_check(self, path, access, member):
75         """Return true if the member has this access to the path."""
76         
77         if access == READ and self.public_get(path) is not None:
78             return True
79         
80         feature = self.xfeature_get(path)
81         if not feature:
82             return False
83         members = self.feature_get(feature, access)
84         if member in members or '*' in members:
85             return True
86         for owner, group in self.group_parents(member):
87             if owner + ':' + group in members:
88                 return True
89         return False
90     
91     def access_inherit(self, path):
92         """Return the paths influencing the access for path."""
93         
94         r = self.xfeature_inherit(path)
95         if not r:
96             return []
97         
98         def get_permissions(feature):
99             permissions = self.feature_dict(feature)
100             if READ in permissions:
101                 permissions['read'] = permissions[READ]
102                 del(permissions[READ])
103             if WRITE in permissions:
104                 permissions['write'] = permissions[WRITE]
105                 del(permissions[WRITE])
106             return permissions
107         
108         # Only keep path components.
109         parts = path.rstrip('/').split('/')
110         valid = []
111         for i in range(1, len(parts)):
112             subp = '/'.join(parts[:i + 1])
113             valid.append(subp)
114             valid.append(subp + '/')
115         return [(x[0], get_permissions(x[1])) for x in r if x[0] in valid]
116     
117     def access_list_paths(self, member, prefix=None):
118         """Return the list of paths granted to member."""
119         
120         q = ("select distinct path from xfeatures inner join "
121              "   (select distinct feature_id, key from xfeaturevals inner join "
122              "      (select owner || ':' || name as value from groups "
123              "       where member = ? union select ? union select '*') "
124              "    using (value)) "
125              "using (feature_id)")
126         p = (member, member)
127         if prefix:
128             q += " where path like ? escape '\\'"
129             p += (self.escape_like(prefix) + '%',)
130         self.execute(q, p)
131         return [r[0] for r in self.fetchall()]
132     
133     def access_list_shared(self, prefix=''):
134         """Return the list of shared paths."""
135         
136         q = "select path from xfeatures where path like ? escape '\\'"
137         self.execute(q, (self.escape_like(prefix) + '%',))
138         return [r[0] for r in self.fetchall()]