Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / backends / lib / sqlalchemy / permissions.py @ dc7159be

History | View | Annotate | Download (10.1 kB)

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

225 a63f36a2 Sofia Papagiannaki
        Keyword arguments:
226 a63f36a2 Sofia Papagiannaki
        prefix -- return only paths starting with prefix (default None)
227 a63f36a2 Sofia Papagiannaki
        include_owned -- return also paths owned by member (default False)
228 a63f36a2 Sofia Papagiannaki
        include_containers -- return also container paths owned by member
229 a63f36a2 Sofia Papagiannaki
                              (default True)
230 a63f36a2 Sofia Papagiannaki

231 a63f36a2 Sofia Papagiannaki
        """
232 2715ade4 Sofia Papagiannaki
233 2715ade4 Sofia Papagiannaki
        xfeatures_xfeaturevals = self.xfeatures.join(self.xfeaturevals)
234 2715ade4 Sofia Papagiannaki
235 4f917833 Sofia Papagiannaki
        selectable = (self.groups.c.owner + ':' + self.groups.c.name)
236 4f917833 Sofia Papagiannaki
        member_groups = select([selectable.label('value')],
237 2715ade4 Sofia Papagiannaki
                               self.groups.c.member == member)
238 2715ade4 Sofia Papagiannaki
239 4f917833 Sofia Papagiannaki
        members = select([literal(member).label('value')])
240 f992aa60 Sofia Papagiannaki
        any = select([literal('*').label('value')])
241 2715ade4 Sofia Papagiannaki
242 fe232f24 Sofia Papagiannaki
        u = union(member_groups, members, any).alias()
243 4f1bc0a6 Sofia Papagiannaki
        inner_join = join(xfeatures_xfeaturevals, u,
244 2715ade4 Sofia Papagiannaki
                          self.xfeaturevals.c.value == u.c.value)
245 4f917833 Sofia Papagiannaki
        s = select([self.xfeatures.c.path], from_obj=[inner_join]).distinct()
246 4f917833 Sofia Papagiannaki
        if prefix:
247 6e0f3e65 Sofia Papagiannaki
            like = lambda p: self.xfeatures.c.path.like(
248 6e0f3e65 Sofia Papagiannaki
                self.escape_like(p) + '%', escape=ESCAPE_CHAR)
249 6e0f3e65 Sofia Papagiannaki
            s = s.where(or_(*map(like,
250 6e0f3e65 Sofia Papagiannaki
                                 self.access_inherit(prefix) or [prefix])))
251 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
252 4f917833 Sofia Papagiannaki
        l = [row[0] for row in r.fetchall()]
253 4f917833 Sofia Papagiannaki
        r.close()
254 a63f36a2 Sofia Papagiannaki
255 a63f36a2 Sofia Papagiannaki
        if include_owned:
256 a63f36a2 Sofia Papagiannaki
            container_nodes = select(
257 a63f36a2 Sofia Papagiannaki
                [self.nodes.c.node],
258 a63f36a2 Sofia Papagiannaki
                self.nodes.c.parent == self.node_lookup(member))
259 a63f36a2 Sofia Papagiannaki
            condition = self.nodes.c.parent.in_(container_nodes)
260 a63f36a2 Sofia Papagiannaki
            if include_containers:
261 a63f36a2 Sofia Papagiannaki
                condition = or_(condition,
262 a63f36a2 Sofia Papagiannaki
                                self.nodes.c.node.in_(container_nodes))
263 a63f36a2 Sofia Papagiannaki
            s = select([self.nodes.c.path], condition)
264 a63f36a2 Sofia Papagiannaki
            r = self.conn.execute(s)
265 a63f36a2 Sofia Papagiannaki
            l += [row[0] for row in r.fetchall() if row[0] not in l]
266 a63f36a2 Sofia Papagiannaki
            r.close()
267 4f917833 Sofia Papagiannaki
        return l
268 2715ade4 Sofia Papagiannaki
269 4f917833 Sofia Papagiannaki
    def access_list_shared(self, prefix=''):
270 4f917833 Sofia Papagiannaki
        """Return the list of shared paths."""
271 2715ade4 Sofia Papagiannaki
272 6e0f3e65 Sofia Papagiannaki
        s = select([self.xfeatures.c.path])
273 6e0f3e65 Sofia Papagiannaki
        like = lambda p: self.xfeatures.c.path.like(
274 6e0f3e65 Sofia Papagiannaki
            self.escape_like(p) + '%', escape=ESCAPE_CHAR)
275 6e0f3e65 Sofia Papagiannaki
        s = s.where(or_(*map(like, self.access_inherit(prefix) or [prefix])))
276 6e0f3e65 Sofia Papagiannaki
        s = s.order_by(self.xfeatures.c.path.asc())
277 4f917833 Sofia Papagiannaki
        r = self.conn.execute(s)
278 4f917833 Sofia Papagiannaki
        l = [row[0] for row in r.fetchall()]
279 4f917833 Sofia Papagiannaki
        r.close()
280 937dc831 Antony Chazapis
        return l