Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (7.7 kB)

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 sqlalchemy.sql import select, literal, or_
35
from sqlalchemy.sql.expression import join, union
36

    
37
from xfeatures import XFeatures
38
from groups import Groups
39
from public import Public
40
from node import Node
41

    
42
from dbworker import ESCAPE_CHAR
43

    
44

    
45
READ = 0
46
WRITE = 1
47

    
48

    
49
class Permissions(XFeatures, Groups, Public, Node):
50

    
51
    def __init__(self, **params):
52
        XFeatures.__init__(self, **params)
53
        Groups.__init__(self, **params)
54
        Public.__init__(self, **params)
55
        Node.__init__(self, **params)
56

    
57
    def access_grant(self, path, access, members=()):
58
        """Grant members with access to path.
59
           Members can also be '*' (all),
60
           or some group specified as 'owner:group'."""
61

    
62
        if not members:
63
            return
64
        feature = self.xfeature_create(path)
65
        self.feature_setmany(feature, access, members)
66

    
67
    def access_set(self, path, permissions):
68
        """Set permissions for path. The permissions dict
69
           maps 'read', 'write' keys to member lists."""
70

    
71
        r = permissions.get('read', [])
72
        w = permissions.get('write', [])
73
        if not r and not w:
74
            self.xfeature_destroy(path)
75
            return
76
        feature = self.xfeature_create(path)
77
        self.feature_clear(feature, READ)
78
        self.feature_clear(feature, WRITE)
79
        if r:
80
            self.feature_setmany(feature, READ, r)
81
        if w:
82
            self.feature_setmany(feature, WRITE, w)
83

    
84
    def access_get(self, path):
85
        """Get permissions for path."""
86

    
87
        feature = self.xfeature_get(path)
88
        if not feature:
89
            return {}
90
        permissions = self.feature_dict(feature)
91
        if READ in permissions:
92
            permissions['read'] = permissions[READ]
93
            del(permissions[READ])
94
        if WRITE in permissions:
95
            permissions['write'] = permissions[WRITE]
96
            del(permissions[WRITE])
97
        return permissions
98

    
99
    def access_members(self, path):
100
        feature = self.xfeature_get(path)
101
        if not feature:
102
            return []
103
        permissions = self.feature_dict(feature)
104
        members = set()
105
        members.update(permissions.get(READ, []))
106
        members.update(permissions.get(WRITE, []))
107
        for m in set(members):
108
            parts = m.split(':', 1)
109
            if len(parts) != 2:
110
                continue
111
            user, group = parts
112
            members.remove(m)
113
            members.update(self.group_members(user, group))
114
        return list(members)
115

    
116
    def access_clear(self, path):
117
        """Revoke access to path (both permissions and public)."""
118

    
119
        self.xfeature_destroy(path)
120
        self.public_unset(path)
121

    
122
    def access_clear_bulk(self, paths):
123
        """Revoke access to path (both permissions and public)."""
124

    
125
        self.xfeature_destroy_bulk(paths)
126
        self.public_unset_bulk(paths)
127

    
128
    def access_check(self, path, access, member):
129
        """Return true if the member has this access to the path."""
130

    
131
        feature = self.xfeature_get(path)
132
        if not feature:
133
            return False
134
        members = self.feature_get(feature, access)
135
        if member in members or '*' in members:
136
            return True
137
        for owner, group in self.group_parents(member):
138
            if owner + ':' + group in members:
139
                return True
140
        return False
141

    
142
    def access_inherit(self, path):
143
        """Return the paths influencing the access for path."""
144

    
145
#         r = self.xfeature_inherit(path)
146
#         if not r:
147
#             return []
148
#         # Compute valid.
149
#         return [x[0] for x in r if x[0] in valid]
150

    
151
        # Only keep path components.
152
        parts = path.rstrip('/').split('/')
153
        valid = []
154
        for i in range(1, len(parts)):
155
            subp = '/'.join(parts[:i + 1])
156
            valid.append(subp)
157
            if subp != path:
158
                valid.append(subp + '/')
159
        return [x for x in valid if self.xfeature_get(x)]
160

    
161
    def access_list_paths(self, member, prefix=None, include_owned=False,
162
                          include_containers=True):
163
        """Return the list of paths granted to member.
164

165
        Keyword arguments:
166
        prefix -- return only paths starting with prefix (default None)
167
        include_owned -- return also paths owned by member (default False)
168
        include_containers -- return also container paths owned by member
169
                              (default True)
170

171
        """
172

    
173
        xfeatures_xfeaturevals = self.xfeatures.join(self.xfeaturevals)
174

    
175
        selectable = (self.groups.c.owner + ':' + self.groups.c.name)
176
        member_groups = select([selectable.label('value')],
177
                               self.groups.c.member == member)
178

    
179
        members = select([literal(member).label('value')])
180
        any = select([literal('*').label('value')])
181

    
182
        u = union(member_groups, members, any).alias()
183
        inner_join = join(xfeatures_xfeaturevals, u,
184
                          self.xfeaturevals.c.value == u.c.value)
185
        s = select([self.xfeatures.c.path], from_obj=[inner_join]).distinct()
186
        if prefix:
187
            s = s.where(self.xfeatures.c.path.like(
188
                self.escape_like(prefix) + '%', escape=ESCAPE_CHAR
189
            ))
190
        r = self.conn.execute(s)
191
        l = [row[0] for row in r.fetchall()]
192
        r.close()
193

    
194
        if include_owned:
195
            container_nodes = select(
196
                [self.nodes.c.node],
197
                self.nodes.c.parent == self.node_lookup(member))
198
            condition = self.nodes.c.parent.in_(container_nodes)
199
            if include_containers:
200
                condition = or_(condition,
201
                                self.nodes.c.node.in_(container_nodes))
202
            s = select([self.nodes.c.path], condition)
203
            r = self.conn.execute(s)
204
            l += [row[0] for row in r.fetchall() if row[0] not in l]
205
            r.close()
206
        return l
207

    
208
    def access_list_shared(self, prefix=''):
209
        """Return the list of shared paths."""
210

    
211
        s = select([self.xfeatures.c.path],
212
                   self.xfeatures.c.path.like(self.escape_like(prefix) + '%',
213
                                              escape=ESCAPE_CHAR
214
                   )
215
        ).order_by(self.xfeatures.c.path.asc())
216
        r = self.conn.execute(s)
217
        l = [row[0] for row in r.fetchall()]
218
        r.close()
219
        return l