~ubuntu-branches/ubuntu/trusty/python-boto/trusty

« back to all changes in this revision

Viewing changes to boto/gs/acl.py

  • Committer: Package Import Robot
  • Author(s): Eric Evans
  • Date: 2011-11-13 11:58:40 UTC
  • mfrom: (14.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20111113115840-ckzyt3h17uh8s41y
Tags: 2.0-2
Promote new upstream to unstable (Closes: #638931).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2010 Google Inc.
 
2
#
 
3
# Permission is hereby granted, free of charge, to any person obtaining a
 
4
# copy of this software and associated documentation files (the
 
5
# "Software"), to deal in the Software without restriction, including
 
6
# without limitation the rights to use, copy, modify, merge, publish, dis-
 
7
# tribute, sublicense, and/or sell copies of the Software, and to permit
 
8
# persons to whom the Software is furnished to do so, subject to the fol-
 
9
# lowing conditions:
 
10
#
 
11
# The above copyright notice and this permission notice shall be included
 
12
# in all copies or substantial portions of the Software.
 
13
#
 
14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
15
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 
16
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 
17
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 
18
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
19
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 
20
# IN THE SOFTWARE.
 
21
 
 
22
from boto.gs.user import User
 
23
from boto.exception import InvalidAclError
 
24
 
 
25
ACCESS_CONTROL_LIST = 'AccessControlList'
 
26
ALL_AUTHENTICATED_USERS = 'AllAuthenticatedUsers'
 
27
ALL_USERS = 'AllUsers'
 
28
DOMAIN = 'Domain'
 
29
EMAIL_ADDRESS = 'EmailAddress'
 
30
ENTRY = 'Entry'
 
31
ENTRIES = 'Entries'
 
32
GROUP_BY_DOMAIN = 'GroupByDomain'
 
33
GROUP_BY_EMAIL = 'GroupByEmail'
 
34
GROUP_BY_ID = 'GroupById'
 
35
ID = 'ID'
 
36
NAME = 'Name'
 
37
OWNER = 'Owner'
 
38
PERMISSION = 'Permission'
 
39
SCOPE = 'Scope'
 
40
TYPE = 'type'
 
41
USER_BY_EMAIL = 'UserByEmail'
 
42
USER_BY_ID = 'UserById'
 
43
 
 
44
 
 
45
CannedACLStrings = ['private', 'public-read', 'project-private',
 
46
                    'public-read-write', 'authenticated-read',
 
47
                    'bucket-owner-read', 'bucket-owner-full-control']
 
48
 
 
49
SupportedPermissions = ['READ', 'WRITE', 'FULL_CONTROL']
 
50
 
 
51
class ACL:
 
52
 
 
53
    def __init__(self, parent=None):
 
54
        self.parent = parent
 
55
        self.entries = []
 
56
 
 
57
    @property
 
58
    def acl(self):
 
59
        return self
 
60
 
 
61
    def __repr__(self):
 
62
        # Owner is optional in GS ACLs.
 
63
        if hasattr(self, 'owner'):
 
64
            entries_repr = ['']
 
65
        else:
 
66
            entries_repr = ['Owner:%s' % self.owner.__repr__()]
 
67
        acl_entries = self.entries
 
68
        if acl_entries:
 
69
            for e in acl_entries.entry_list:
 
70
                entries_repr.append(e.__repr__())
 
71
        return '<%s>' % ', '.join(entries_repr)
 
72
 
 
73
    # Method with same signature as boto.s3.acl.ACL.add_email_grant(), to allow
 
74
    # polymorphic treatment at application layer.
 
75
    def add_email_grant(self, permission, email_address):
 
76
        entry = Entry(type=USER_BY_EMAIL, email_address=email_address,
 
77
                      permission=permission)
 
78
        self.entries.entry_list.append(entry)
 
79
 
 
80
    # Method with same signature as boto.s3.acl.ACL.add_user_grant(), to allow
 
81
    # polymorphic treatment at application layer.
 
82
    def add_user_grant(self, permission, user_id):
 
83
        entry = Entry(permission=permission, type=USER_BY_ID, id=user_id)
 
84
        self.entries.entry_list.append(entry)
 
85
 
 
86
    def add_group_email_grant(self, permission, email_address):
 
87
        entry = Entry(type=GROUP_BY_EMAIL, email_address=email_address,
 
88
                      permission=permission)
 
89
        self.entries.entry_list.append(entry)
 
90
 
 
91
    def add_group_grant(self, permission, group_id):
 
92
        entry = Entry(type=GROUP_BY_ID, id=group_id, permission=permission)
 
93
        self.entries.entry_list.append(entry)
 
94
 
 
95
    def startElement(self, name, attrs, connection):
 
96
        if name == OWNER:
 
97
            self.owner = User(self)
 
98
            return self.owner
 
99
        elif name == ENTRIES:
 
100
            self.entries = Entries(self)
 
101
            return self.entries
 
102
        else:
 
103
            return None
 
104
 
 
105
    def endElement(self, name, value, connection):
 
106
        if name == OWNER:
 
107
            pass
 
108
        elif name == ENTRIES:
 
109
            pass
 
110
        else:
 
111
            setattr(self, name, value)
 
112
 
 
113
    def to_xml(self):
 
114
        s = '<%s>' % ACCESS_CONTROL_LIST
 
115
        # Owner is optional in GS ACLs.
 
116
        if hasattr(self, 'owner'):
 
117
            s += self.owner.to_xml()
 
118
        acl_entries = self.entries
 
119
        if acl_entries:
 
120
            s += acl_entries.to_xml()
 
121
        s += '</%s>' % ACCESS_CONTROL_LIST
 
122
        return s
 
123
 
 
124
 
 
125
class Entries:
 
126
 
 
127
    def __init__(self, parent=None):
 
128
        self.parent = parent
 
129
        # Entries is the class that represents the same-named XML
 
130
        # element. entry_list is the list within this class that holds the data.
 
131
        self.entry_list = []
 
132
 
 
133
    def __repr__(self):
 
134
        entries_repr = []
 
135
        for e in self.entry_list:
 
136
            entries_repr.append(e.__repr__())
 
137
        return '<Entries: %s>' % ', '.join(entries_repr)
 
138
 
 
139
    def startElement(self, name, attrs, connection):
 
140
        if name == ENTRY:
 
141
            entry = Entry(self)
 
142
            self.entry_list.append(entry)
 
143
            return entry
 
144
        else:
 
145
            return None
 
146
 
 
147
    def endElement(self, name, value, connection):
 
148
        if name == ENTRY:
 
149
            pass
 
150
        else:
 
151
            setattr(self, name, value)
 
152
 
 
153
    def to_xml(self):
 
154
        s = '<%s>' % ENTRIES
 
155
        for entry in self.entry_list:
 
156
            s += entry.to_xml()
 
157
        s += '</%s>' % ENTRIES
 
158
        return s
 
159
        
 
160
 
 
161
# Class that represents a single (Scope, Permission) entry in an ACL.
 
162
class Entry:
 
163
 
 
164
    def __init__(self, scope=None, type=None, id=None, name=None,
 
165
                 email_address=None, domain=None, permission=None):
 
166
        if not scope:
 
167
            scope = Scope(self, type, id, name, email_address, domain)
 
168
        self.scope = scope
 
169
        self.permission = permission
 
170
 
 
171
    def __repr__(self):
 
172
        return '<%s: %s>' % (self.scope.__repr__(), self.permission.__repr__())
 
173
 
 
174
    def startElement(self, name, attrs, connection):
 
175
        if name == SCOPE:
 
176
            if not TYPE in attrs:
 
177
                raise InvalidAclError('Missing "%s" in "%s" part of ACL' %
 
178
                                      (TYPE, SCOPE))
 
179
            self.scope = Scope(self, attrs[TYPE])
 
180
            return self.scope
 
181
        elif name == PERMISSION:
 
182
            pass
 
183
        else:
 
184
            return None
 
185
 
 
186
    def endElement(self, name, value, connection):
 
187
        if name == SCOPE:
 
188
            pass
 
189
        elif name == PERMISSION:
 
190
            value = value.strip()
 
191
            if not value in SupportedPermissions:
 
192
                raise InvalidAclError('Invalid Permission "%s"' % value)
 
193
            self.permission = value
 
194
        else:
 
195
            setattr(self, name, value)
 
196
 
 
197
    def to_xml(self):
 
198
        s = '<%s>' % ENTRY
 
199
        s += self.scope.to_xml()
 
200
        s += '<%s>%s</%s>' % (PERMISSION, self.permission, PERMISSION)
 
201
        s += '</%s>' % ENTRY
 
202
        return s
 
203
 
 
204
class Scope:
 
205
 
 
206
    # Map from Scope type to list of allowed sub-elems.
 
207
    ALLOWED_SCOPE_TYPE_SUB_ELEMS = {
 
208
        ALL_AUTHENTICATED_USERS : [],
 
209
        ALL_USERS : [],
 
210
        GROUP_BY_DOMAIN : [DOMAIN],
 
211
        GROUP_BY_EMAIL : [EMAIL_ADDRESS, NAME],
 
212
        GROUP_BY_ID : [ID, NAME],
 
213
        USER_BY_EMAIL : [EMAIL_ADDRESS, NAME],
 
214
        USER_BY_ID : [ID, NAME]
 
215
    }
 
216
 
 
217
    def __init__(self, parent, type=None, id=None, name=None,
 
218
                 email_address=None, domain=None):
 
219
        self.parent = parent
 
220
        self.type = type
 
221
        self.name = name
 
222
        self.id = id
 
223
        self.domain = domain
 
224
        self.email_address = email_address
 
225
        if not self.ALLOWED_SCOPE_TYPE_SUB_ELEMS.has_key(self.type):
 
226
            raise InvalidAclError('Invalid %s %s "%s" ' %
 
227
                                  (SCOPE, TYPE, self.type))
 
228
 
 
229
    def __repr__(self):
 
230
        named_entity = None
 
231
        if self.id:
 
232
            named_entity = self.id
 
233
        elif self.email_address:
 
234
            named_entity = self.email_address
 
235
        elif self.domain:
 
236
            named_entity = self.domain
 
237
        if named_entity:
 
238
            return '<%s: %s>' % (self.type, named_entity)
 
239
        else:
 
240
            return '<%s>' % self.type
 
241
 
 
242
    def startElement(self, name, attrs, connection):
 
243
        if not name in self.ALLOWED_SCOPE_TYPE_SUB_ELEMS[self.type]:
 
244
            raise InvalidAclError('Element "%s" not allowed in %s %s "%s" ' %
 
245
                                   (name, SCOPE, TYPE, self.type))
 
246
        return None
 
247
 
 
248
    def endElement(self, name, value, connection):
 
249
        value = value.strip()
 
250
        if name == DOMAIN:
 
251
            self.domain = value
 
252
        elif name == EMAIL_ADDRESS:
 
253
            self.email_address = value
 
254
        elif name == ID:
 
255
            self.id = value
 
256
        elif name == NAME:
 
257
            self.name = value
 
258
        else:
 
259
            setattr(self, name, value)
 
260
 
 
261
    def to_xml(self):
 
262
        s = '<%s type="%s">' % (SCOPE, self.type)
 
263
        if self.type == ALL_AUTHENTICATED_USERS or self.type == ALL_USERS:
 
264
            pass
 
265
        elif self.type == GROUP_BY_DOMAIN:
 
266
            s += '<%s>%s</%s>' % (DOMAIN, self.domain, DOMAIN)
 
267
        elif self.type == GROUP_BY_EMAIL or self.type == USER_BY_EMAIL:
 
268
            s += '<%s>%s</%s>' % (EMAIL_ADDRESS, self.email_address,
 
269
                                  EMAIL_ADDRESS)
 
270
            if self.name:
 
271
              s += '<%s>%s</%s>' % (NAME, self.name, NAME)
 
272
        elif self.type == GROUP_BY_ID or self.type == USER_BY_ID:
 
273
            s += '<%s>%s</%s>' % (ID, self.id, ID)
 
274
            if self.name:
 
275
              s += '<%s>%s</%s>' % (NAME, self.name, NAME)
 
276
        else:
 
277
            raise InvalidAclError('Invalid scope type "%s" ', self.type)
 
278
 
 
279
        s += '</%s>' % SCOPE
 
280
        return s