Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / lib / sqlite / permissions.py @ 3759eddb

History | View | Annotate | Download (9.1 kB)

1 2e662088 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 2715ade4 Sofia Papagiannaki
#
3 a9b3f29d Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 a9b3f29d Antony Chazapis
# without modification, are permitted provided that the following
5 a9b3f29d Antony Chazapis
# conditions are met:
6 2715ade4 Sofia Papagiannaki
#
7 a9b3f29d Antony Chazapis
#   1. Redistributions of source code must retain the above
8 a9b3f29d Antony Chazapis
#      copyright notice, this list of conditions and the following
9 a9b3f29d Antony Chazapis
#      disclaimer.
10 2715ade4 Sofia Papagiannaki
#
11 a9b3f29d Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 a9b3f29d Antony Chazapis
#      copyright notice, this list of conditions and the following
13 a9b3f29d Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 a9b3f29d Antony Chazapis
#      provided with the distribution.
15 2715ade4 Sofia Papagiannaki
#
16 a9b3f29d Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 a9b3f29d Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 a9b3f29d Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 a9b3f29d Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 a9b3f29d Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 a9b3f29d Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 a9b3f29d Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 a9b3f29d Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 a9b3f29d Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 a9b3f29d Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 a9b3f29d Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 a9b3f29d Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 2715ade4 Sofia Papagiannaki
#
29 a9b3f29d Antony Chazapis
# The views and conclusions contained in the software and
30 a9b3f29d Antony Chazapis
# documentation are those of the authors and should not be
31 a9b3f29d Antony Chazapis
# interpreted as representing official policies, either expressed
32 a9b3f29d Antony Chazapis
# or implied, of GRNET S.A.
33 a9b3f29d Antony Chazapis
34 a9b3f29d Antony Chazapis
from xfeatures import XFeatures
35 a9b3f29d Antony Chazapis
from groups import Groups
36 a9b3f29d Antony Chazapis
from public import Public
37 a63f36a2 Sofia Papagiannaki
from node import Node
38 d3c34119 Sofia Papagiannaki
from collections import defaultdict
39 a9b3f29d Antony Chazapis
40 a9b3f29d Antony Chazapis
41 6f4bce7b Antony Chazapis
READ = 0
42 6f4bce7b Antony Chazapis
WRITE = 1
43 6f4bce7b Antony Chazapis
44 6f4bce7b Antony Chazapis
45 a63f36a2 Sofia Papagiannaki
class Permissions(XFeatures, Groups, Public, Node):
46 2715ade4 Sofia Papagiannaki
47 a9b3f29d Antony Chazapis
    def __init__(self, **params):
48 a9b3f29d Antony Chazapis
        XFeatures.__init__(self, **params)
49 a9b3f29d Antony Chazapis
        Groups.__init__(self, **params)
50 a9b3f29d Antony Chazapis
        Public.__init__(self, **params)
51 a63f36a2 Sofia Papagiannaki
        Node.__init__(self, **params)
52 2715ade4 Sofia Papagiannaki
53 6f4bce7b Antony Chazapis
    def access_grant(self, path, access, members=()):
54 0f9d752c Antony Chazapis
        """Grant members with access to path.
55 0f9d752c Antony Chazapis
           Members can also be '*' (all),
56 0f9d752c Antony Chazapis
           or some group specified as 'owner:group'."""
57 2715ade4 Sofia Papagiannaki
58 0f9d752c Antony Chazapis
        if not members:
59 0f9d752c Antony Chazapis
            return
60 6f4bce7b Antony Chazapis
        feature = self.xfeature_create(path)
61 6f4bce7b Antony Chazapis
        self.feature_setmany(feature, access, members)
62 2715ade4 Sofia Papagiannaki
63 0f9d752c Antony Chazapis
    def access_set(self, path, permissions):
64 0f9d752c Antony Chazapis
        """Set permissions for path. The permissions dict
65 0f9d752c Antony Chazapis
           maps 'read', 'write' keys to member lists."""
66 2715ade4 Sofia Papagiannaki
67 5e068361 Antony Chazapis
        r = permissions.get('read', [])
68 5e068361 Antony Chazapis
        w = permissions.get('write', [])
69 5e068361 Antony Chazapis
        if not r and not w:
70 5e068361 Antony Chazapis
            self.xfeature_destroy(path)
71 5e068361 Antony Chazapis
            return
72 5e068361 Antony Chazapis
        feature = self.xfeature_create(path)
73 345dcf39 Antony Chazapis
        self.feature_clear(feature, READ)
74 345dcf39 Antony Chazapis
        self.feature_clear(feature, WRITE)
75 5e068361 Antony Chazapis
        if r:
76 5e068361 Antony Chazapis
            self.feature_setmany(feature, READ, r)
77 5e068361 Antony Chazapis
        if w:
78 5e068361 Antony Chazapis
            self.feature_setmany(feature, WRITE, w)
79 2715ade4 Sofia Papagiannaki
80 d3c34119 Sofia Papagiannaki
    def access_get_for_bulk(self, perms):
81 d3c34119 Sofia Papagiannaki
        """Get permissions for paths."""
82 d3c34119 Sofia Papagiannaki
83 d3c34119 Sofia Papagiannaki
        allowed = None
84 d3c34119 Sofia Papagiannaki
        d = defaultdict(list)
85 d3c34119 Sofia Papagiannaki
        for value, feature_id, key in perms:
86 d3c34119 Sofia Papagiannaki
            d[key].append(value)
87 d3c34119 Sofia Papagiannaki
        permissions = d
88 d3c34119 Sofia Papagiannaki
        if READ in permissions:
89 d3c34119 Sofia Papagiannaki
            allowed = 0
90 d3c34119 Sofia Papagiannaki
            permissions['read'] = permissions[READ]
91 d3c34119 Sofia Papagiannaki
            del(permissions[READ])
92 d3c34119 Sofia Papagiannaki
        if WRITE in permissions:
93 d3c34119 Sofia Papagiannaki
            allowed = 1
94 d3c34119 Sofia Papagiannaki
            permissions['write'] = permissions[WRITE]
95 d3c34119 Sofia Papagiannaki
            del(permissions[WRITE])
96 d3c34119 Sofia Papagiannaki
        return (permissions, allowed)
97 d3c34119 Sofia Papagiannaki
98 92da0e5a Antony Chazapis
    def access_get(self, path):
99 cf341da4 Antony Chazapis
        """Get permissions for path."""
100 2715ade4 Sofia Papagiannaki
101 92da0e5a Antony Chazapis
        feature = self.xfeature_get(path)
102 92da0e5a Antony Chazapis
        if not feature:
103 71dbc012 Antony Chazapis
            return {}
104 92da0e5a Antony Chazapis
        permissions = self.feature_dict(feature)
105 92da0e5a Antony Chazapis
        if READ in permissions:
106 92da0e5a Antony Chazapis
            permissions['read'] = permissions[READ]
107 92da0e5a Antony Chazapis
            del(permissions[READ])
108 92da0e5a Antony Chazapis
        if WRITE in permissions:
109 92da0e5a Antony Chazapis
            permissions['write'] = permissions[WRITE]
110 92da0e5a Antony Chazapis
            del(permissions[WRITE])
111 92da0e5a Antony Chazapis
        return permissions
112 2715ade4 Sofia Papagiannaki
113 a74ba506 Sofia Papagiannaki
    def access_members(self, path):
114 a74ba506 Sofia Papagiannaki
        feature = self.xfeature_get(path)
115 a74ba506 Sofia Papagiannaki
        if not feature:
116 a74ba506 Sofia Papagiannaki
            return []
117 a74ba506 Sofia Papagiannaki
        permissions = self.feature_dict(feature)
118 a74ba506 Sofia Papagiannaki
        members = set()
119 a74ba506 Sofia Papagiannaki
        members.update(permissions.get(READ, []))
120 a74ba506 Sofia Papagiannaki
        members.update(permissions.get(WRITE, []))
121 a74ba506 Sofia Papagiannaki
        for m in set(members):
122 a74ba506 Sofia Papagiannaki
            parts = m.split(':', 1)
123 a74ba506 Sofia Papagiannaki
            if len(parts) != 2:
124 a74ba506 Sofia Papagiannaki
                continue
125 a74ba506 Sofia Papagiannaki
            user, group = parts
126 a74ba506 Sofia Papagiannaki
            members.remove(m)
127 a74ba506 Sofia Papagiannaki
            members.update(self.group_members(user, group))
128 a74ba506 Sofia Papagiannaki
        return members
129 2715ade4 Sofia Papagiannaki
130 0f9d752c Antony Chazapis
    def access_clear(self, path):
131 0f9d752c Antony Chazapis
        """Revoke access to path (both permissions and public)."""
132 2715ade4 Sofia Papagiannaki
133 6f4bce7b Antony Chazapis
        self.xfeature_destroy(path)
134 0f9d752c Antony Chazapis
        self.public_unset(path)
135 2715ade4 Sofia Papagiannaki
136 4d15c94e Sofia Papagiannaki
    def access_clear_bulk(self, paths):
137 4d15c94e Sofia Papagiannaki
        """Revoke access to path (both permissions and public)."""
138 2715ade4 Sofia Papagiannaki
139 4d15c94e Sofia Papagiannaki
        self.xfeature_destroy_bulk(paths)
140 4d15c94e Sofia Papagiannaki
        self.public_unset_bulk(paths)
141 2715ade4 Sofia Papagiannaki
142 6f4bce7b Antony Chazapis
    def access_check(self, path, access, member):
143 a9b3f29d Antony Chazapis
        """Return true if the member has this access to the path."""
144 2715ade4 Sofia Papagiannaki
145 43763394 Antony Chazapis
        feature = self.xfeature_get(path)
146 43763394 Antony Chazapis
        if not feature:
147 6f4bce7b Antony Chazapis
            return False
148 6f4bce7b Antony Chazapis
        members = self.feature_get(feature, access)
149 6f4bce7b Antony Chazapis
        if member in members or '*' in members:
150 6f4bce7b Antony Chazapis
            return True
151 62f915a1 Antony Chazapis
        for owner, group in self.group_parents(member):
152 6f4bce7b Antony Chazapis
            if owner + ':' + group in members:
153 6f4bce7b Antony Chazapis
                return True
154 676edf89 Antony Chazapis
        return False
155 2715ade4 Sofia Papagiannaki
156 d3c34119 Sofia Papagiannaki
    def access_check_bulk(self, paths, member):
157 d3c34119 Sofia Papagiannaki
        rows = None
158 d3c34119 Sofia Papagiannaki
        q = ("select x.path, xvals.value, xvals.feature_id, xvals.key "
159 d3c34119 Sofia Papagiannaki
             "from xfeaturevals xvals join xfeatures x "
160 d3c34119 Sofia Papagiannaki
             "on xvals.feature_id = x.feature_id "
161 d3c34119 Sofia Papagiannaki
             "where x.path in (%s)") % ','.join('?' for _ in paths)
162 d3c34119 Sofia Papagiannaki
        self.execute(q, paths)
163 d3c34119 Sofia Papagiannaki
        rows = self.fetchall()
164 d3c34119 Sofia Papagiannaki
        if rows:
165 d3c34119 Sofia Papagiannaki
            access_check_paths = {}
166 d3c34119 Sofia Papagiannaki
            for path, value, feature_id, key in rows:
167 d3c34119 Sofia Papagiannaki
                try:
168 d3c34119 Sofia Papagiannaki
                    access_check_paths[path].append((value, feature_id, key))
169 d3c34119 Sofia Papagiannaki
                except KeyError:
170 d3c34119 Sofia Papagiannaki
                    access_check_paths[path] = [(value, feature_id, key)]
171 d3c34119 Sofia Papagiannaki
            return access_check_paths
172 d3c34119 Sofia Papagiannaki
        return None
173 d3c34119 Sofia Papagiannaki
174 6f4bce7b Antony Chazapis
    def access_inherit(self, path):
175 43763394 Antony Chazapis
        """Return the paths influencing the access for path."""
176 2715ade4 Sofia Papagiannaki
177 d83c93c9 Antony Chazapis
#         r = self.xfeature_inherit(path)
178 d83c93c9 Antony Chazapis
#         if not r:
179 d83c93c9 Antony Chazapis
#             return []
180 d83c93c9 Antony Chazapis
#         # Compute valid.
181 d83c93c9 Antony Chazapis
#         return [x[0] for x in r if x[0] in valid]
182 2715ade4 Sofia Papagiannaki
183 43763394 Antony Chazapis
        # Only keep path components.
184 43763394 Antony Chazapis
        parts = path.rstrip('/').split('/')
185 43763394 Antony Chazapis
        valid = []
186 43763394 Antony Chazapis
        for i in range(1, len(parts)):
187 43763394 Antony Chazapis
            subp = '/'.join(parts[:i + 1])
188 43763394 Antony Chazapis
            valid.append(subp)
189 d83c93c9 Antony Chazapis
            if subp != path:
190 d83c93c9 Antony Chazapis
                valid.append(subp + '/')
191 d83c93c9 Antony Chazapis
        return [x for x in valid if self.xfeature_get(x)]
192 2715ade4 Sofia Papagiannaki
193 d3c34119 Sofia Papagiannaki
    def access_inherit_bulk(self, paths):
194 d3c34119 Sofia Papagiannaki
        """Return the paths influencing the access for paths."""
195 d3c34119 Sofia Papagiannaki
196 d3c34119 Sofia Papagiannaki
        # Only keep path components.
197 d3c34119 Sofia Papagiannaki
        valid = []
198 d3c34119 Sofia Papagiannaki
        for path in paths:
199 d3c34119 Sofia Papagiannaki
            parts = path.rstrip('/').split('/')
200 d3c34119 Sofia Papagiannaki
            for i in range(1, len(parts)):
201 d3c34119 Sofia Papagiannaki
                subp = '/'.join(parts[:i + 1])
202 d3c34119 Sofia Papagiannaki
                valid.append(subp)
203 d3c34119 Sofia Papagiannaki
                if subp != path:
204 d3c34119 Sofia Papagiannaki
                    valid.append(subp + '/')
205 d3c34119 Sofia Papagiannaki
        valid = self.xfeature_get_bulk(valid)
206 d3c34119 Sofia Papagiannaki
        return [x[1] for x in valid]
207 d3c34119 Sofia Papagiannaki
208 a63f36a2 Sofia Papagiannaki
    def access_list_paths(self, member, prefix=None, include_owned=False,
209 a63f36a2 Sofia Papagiannaki
                          include_containers=True):
210 a63f36a2 Sofia Papagiannaki
        """Return the list of paths granted to member.
211 a63f36a2 Sofia Papagiannaki

212 a63f36a2 Sofia Papagiannaki
        Keyword arguments:
213 a63f36a2 Sofia Papagiannaki
        prefix -- return only paths starting with prefix (default None)
214 a63f36a2 Sofia Papagiannaki
        include_owned -- return also paths owned by member (default False)
215 a63f36a2 Sofia Papagiannaki
        include_containers -- return also container paths owned by member
216 a63f36a2 Sofia Papagiannaki
                              (default True)
217 a63f36a2 Sofia Papagiannaki

218 a63f36a2 Sofia Papagiannaki
        """
219 2715ade4 Sofia Papagiannaki
220 6f4bce7b Antony Chazapis
        q = ("select distinct path from xfeatures inner join "
221 29148653 Sofia Papagiannaki
             "  (select distinct feature_id, key from xfeaturevals inner join "
222 29148653 Sofia Papagiannaki
             "     (select owner || ':' || name as value from groups "
223 29148653 Sofia Papagiannaki
             "      where member = ? union select ? union select '*') "
224 29148653 Sofia Papagiannaki
             "   using (value)) "
225 6f4bce7b Antony Chazapis
             "using (feature_id)")
226 6f4bce7b Antony Chazapis
        p = (member, member)
227 6f4bce7b Antony Chazapis
        if prefix:
228 d3c34119 Sofia Papagiannaki
            q += " where "
229 d3c34119 Sofia Papagiannaki
            paths = self.access_inherit(prefix) or [prefix]
230 d3c34119 Sofia Papagiannaki
            q += ' or '.join("path like ? escape '\\'" for _ in paths)
231 d3c34119 Sofia Papagiannaki
            p += tuple(self.escape_like(path) + '%' for path in paths)
232 6f4bce7b Antony Chazapis
        self.execute(q, p)
233 a63f36a2 Sofia Papagiannaki
234 a63f36a2 Sofia Papagiannaki
        l = [r[0] for r in self.fetchall()]
235 a63f36a2 Sofia Papagiannaki
        if include_owned:
236 a63f36a2 Sofia Papagiannaki
            node = self.node_lookup(member)
237 a63f36a2 Sofia Papagiannaki
            select_containers = "select node from nodes where parent = ? "
238 a63f36a2 Sofia Papagiannaki
            q = ("select path from nodes where parent in (%s) " %
239 a63f36a2 Sofia Papagiannaki
                 select_containers)
240 a63f36a2 Sofia Papagiannaki
            args = [node]
241 a63f36a2 Sofia Papagiannaki
            if include_containers:
242 a63f36a2 Sofia Papagiannaki
                q += ("or node in (%s)" % select_containers)
243 a63f36a2 Sofia Papagiannaki
                args += [node]
244 a63f36a2 Sofia Papagiannaki
            self.execute(q, args)
245 a63f36a2 Sofia Papagiannaki
            l += [r[0] for r in self.fetchall() if r[0] not in l]
246 a63f36a2 Sofia Papagiannaki
        return l
247 2715ade4 Sofia Papagiannaki
248 6f4bce7b Antony Chazapis
    def access_list_shared(self, prefix=''):
249 6f4bce7b Antony Chazapis
        """Return the list of shared paths."""
250 2715ade4 Sofia Papagiannaki
251 d3c34119 Sofia Papagiannaki
        q = "select path from xfeatures where "
252 d3c34119 Sofia Papagiannaki
        paths = self.access_inherit(prefix) or [prefix]
253 d3c34119 Sofia Papagiannaki
        q += ' or '.join("path like ? escape '\\'" for _ in paths)
254 d3c34119 Sofia Papagiannaki
        p = tuple(self.escape_like(path) + '%' for path in paths)
255 6e0f3e65 Sofia Papagiannaki
        self.execute(q, p)
256 6f4bce7b Antony Chazapis
        return [r[0] for r in self.fetchall()]