Send sharing notifications.
[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         if r:
71             self.feature_clear(feature, READ)
72             self.feature_setmany(feature, READ, r)
73         if w:
74             self.feature_clear(feature, WRITE)
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_check(self, path, access, member):
116         """Return true if the member has this access to the path."""
117         
118         feature = self.xfeature_get(path)
119         if not feature:
120             return False
121         members = self.feature_get(feature, access)
122         if member in members or '*' in members:
123             return True
124         for owner, group in self.group_parents(member):
125             if owner + ':' + group in members:
126                 return True
127         return False
128     
129     def access_inherit(self, path):
130         """Return the paths influencing the access for path."""
131         
132 #         r = self.xfeature_inherit(path)
133 #         if not r:
134 #             return []
135 #         # Compute valid.
136 #         return [x[0] for x in r if x[0] in valid]
137         
138         # Only keep path components.
139         parts = path.rstrip('/').split('/')
140         valid = []
141         for i in range(1, len(parts)):
142             subp = '/'.join(parts[:i + 1])
143             valid.append(subp)
144             if subp != path:
145                 valid.append(subp + '/')
146         return [x for x in valid if self.xfeature_get(x)]
147     
148     def access_list_paths(self, member, prefix=None):
149         """Return the list of paths granted to member."""
150         
151         q = ("select distinct path from xfeatures inner join "
152              "   (select distinct feature_id, key from xfeaturevals inner join "
153              "      (select owner || ':' || name as value from groups "
154              "       where member = ? union select ? union select '*') "
155              "    using (value)) "
156              "using (feature_id)")
157         p = (member, member)
158         if prefix:
159             q += " where path like ? escape '\\'"
160             p += (self.escape_like(prefix) + '%',)
161         self.execute(q, p)
162         return [r[0] for r in self.fetchall()]
163     
164     def access_list_shared(self, prefix=''):
165         """Return the list of shared paths."""
166         
167         q = "select path from xfeatures where path like ? escape '\\'"
168         self.execute(q, (self.escape_like(prefix) + '%',))
169         return [r[0] for r in self.fetchall()]