Merge branch 'next'
[pithos] / snf-pithos-backend / 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         r = permissions.get('read', [])
65         w = permissions.get('write', [])
66         if not r and not w:
67             self.xfeature_destroy(path)
68             return
69         feature = self.xfeature_create(path)
70         self.feature_clear(feature, READ)
71         self.feature_clear(feature, WRITE)
72         if r:
73             self.feature_setmany(feature, READ, r)
74         if w:
75             self.feature_setmany(feature, WRITE, w)
76     
77     def access_get(self, path):
78         """Get permissions for path."""
79         
80         feature = self.xfeature_get(path)
81         if not feature:
82             return {}
83         permissions = self.feature_dict(feature)
84         if READ in permissions:
85             permissions['read'] = permissions[READ]
86             del(permissions[READ])
87         if WRITE in permissions:
88             permissions['write'] = permissions[WRITE]
89             del(permissions[WRITE])
90         return permissions
91     
92     def access_members(self, path):
93         feature = self.xfeature_get(path)
94         if not feature:
95             return []
96         permissions = self.feature_dict(feature)
97         members = set()
98         members.update(permissions.get(READ, []))
99         members.update(permissions.get(WRITE, []))
100         for m in set(members):
101             parts = m.split(':', 1)
102             if len(parts) != 2:
103                 continue
104             user, group = parts
105             members.remove(m)
106             members.update(self.group_members(user, group))
107         return members
108     
109     def access_clear(self, path):
110         """Revoke access to path (both permissions and public)."""
111         
112         self.xfeature_destroy(path)
113         self.public_unset(path)
114     
115     def access_clear_bulk(self, paths):
116         """Revoke access to path (both permissions and public)."""
117         
118         self.xfeature_destroy_bulk(paths)
119         self.public_unset_bulk(paths)
120     
121     def access_check(self, path, access, member):
122         """Return true if the member has this access to the path."""
123         
124         feature = self.xfeature_get(path)
125         if not feature:
126             return False
127         members = self.feature_get(feature, access)
128         if member in members or '*' in members:
129             return True
130         for owner, group in self.group_parents(member):
131             if owner + ':' + group in members:
132                 return True
133         return False
134     
135     def access_inherit(self, path):
136         """Return the paths influencing the access for path."""
137         
138 #         r = self.xfeature_inherit(path)
139 #         if not r:
140 #             return []
141 #         # Compute valid.
142 #         return [x[0] for x in r if x[0] in valid]
143         
144         # Only keep path components.
145         parts = path.rstrip('/').split('/')
146         valid = []
147         for i in range(1, len(parts)):
148             subp = '/'.join(parts[:i + 1])
149             valid.append(subp)
150             if subp != path:
151                 valid.append(subp + '/')
152         return [x for x in valid if self.xfeature_get(x)]
153     
154     def access_list_paths(self, member, prefix=None):
155         """Return the list of paths granted to member."""
156         
157         q = ("select distinct path from xfeatures inner join "
158              "   (select distinct feature_id, key from xfeaturevals inner join "
159              "      (select owner || ':' || name as value from groups "
160              "       where member = ? union select ? union select '*') "
161              "    using (value)) "
162              "using (feature_id)")
163         p = (member, member)
164         if prefix:
165             q += " where path like ? escape '\\'"
166             p += (self.escape_like(prefix) + '%',)
167         self.execute(q, p)
168         return [r[0] for r in self.fetchall()]
169     
170     def access_list_shared(self, prefix=''):
171         """Return the list of shared paths."""
172         
173         q = "select path from xfeatures where path like ? escape '\\'"
174         self.execute(q, (self.escape_like(prefix) + '%',))
175         return [r[0] for r in self.fetchall()]