File: grantee.rb

package info (click to toggle)
ruby-aws 2.10.2-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster, forky, sid, trixie
  • size: 748 kB
  • sloc: ruby: 7,748; makefile: 16
file content (238 lines) | stat: -rw-r--r-- 8,074 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
module Aws

  # There are 2 ways to set permissions for a bucket or key (called a +thing+ below):
  #
  # 1 . Use +perms+ param to set 'Canned Access Policies' when calling the <tt>bucket.create</tt>,
  # <tt>bucket.put</tt> and <tt>key.put</tt> methods.
  # The +perms+ param can take these values: 'private', 'public-read', 'public-read-write' and
  # 'authenticated-read'.
  # (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html).
  #
  #  bucket = s3.bucket('bucket_for_kd_test_13', true, 'public-read')
  #  key.put('Woohoo!','public-read-write' )
  #
  # 2 . Use Grantee instances (the permission is a +String+ or an +Array+ of: 'READ', 'WRITE',
  # 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'):
  #
  #  bucket  = s3.bucket('my_awesome_bucket', true)
  #  grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c', FULL_CONTROL, :apply)
  #  grantee2 = Aws::S3::Grantee.new(bucket, 'xy3v3...5fhp', [READ, WRITE], :apply)
  #
  # There is only one way to get and to remove permission (via Grantee instances):
  #
  #  grantees = bucket.grantees # a list of Grantees that have any access for this bucket
  #  grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c')
  #  grantee1.perms #=> returns a list of perms for this grantee to that bucket
  #    ...
  #  grantee1.drop             # remove all perms for this grantee
  #  grantee2.revoke('WRITE')  # revoke write access only
  #
  class S3::Grantee
    # A bucket or a key the grantee has an access to.
    attr_reader :thing
    # Grantee Amazon id.
    attr_reader :id
    # Grantee display name.
    attr_reader :name
    # Array of permissions.
    attr_accessor :perms

    # Retrieve Owner information and a list of Grantee instances that have
    # a access to this thing (bucket or key).
    #
    #  bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
    #   ...
    #  Aws::S3::Grantee.owner_and_grantees(bucket) #=> [owner, grantees]
    #
    def self.owner_and_grantees(thing)
      if thing.is_a?(S3::Bucket)
        bucket, key = thing, ''
      else
        bucket, key = thing.bucket, thing
      end
      hash     = bucket.s3.interface.get_acl_parse(bucket.to_s, key.to_s)
      owner    = S3::Owner.new(hash[:owner][:id], hash[:owner][:display_name])

      grantees = []
      hash[:grantees].each do |id, params|
        grantees << new(thing, id, params[:permissions], nil, params[:display_name])
      end
      [owner, grantees]
    end

    # Retrieves a list of Grantees instances that have an access to this thing(bucket or key).
    #
    #  bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
    #   ...
    #  Aws::S3::Grantee.grantees(bucket) #=> grantees
    #
    def self.grantees(thing)
      owner_and_grantees(thing)[1]
    end

    def self.put_acl(thing, owner, grantees) #:nodoc:
      if thing.is_a?(S3::Bucket)
        bucket, key = thing, ''
      else
        bucket, key = thing.bucket, thing
      end
      body = "<AccessControlPolicy>" +
          "<Owner>" +
          "<ID>#{owner.id}</ID>" +
          "<DisplayName>#{owner.name}</DisplayName>" +
          "</Owner>" +
          "<AccessControlList>" +
          grantees.map { |grantee| grantee.to_xml }.join +
          "</AccessControlList>" +
          "</AccessControlPolicy>"
      bucket.s3.interface.put_acl(bucket.to_s, key.to_s, body)
    end

    # Create a new Grantee instance.
    # Grantee +id+ must exist on S3. If +action+ == :refresh, then retrieve
    # permissions from S3 and update @perms. If +action+ == :apply, then apply
    # perms to +thing+ at S3. If +action+ == :apply_and_refresh then it performs.
    # both the actions. This is used for the new grantees that had no perms to
    # this thing before. The default action is :refresh.
    #
    #  bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
    #  grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c', FULL_CONTROL)
    #    ...
    #  grantee2 = Aws::S3::Grantee.new(bucket, 'abcde...asdf', [FULL_CONTROL, READ], :apply)
    #  grantee3 = Aws::S3::Grantee.new(bucket, 'aaaaa...aaaa', 'READ', :apply_and_refresh)
    #
    def initialize(thing, id, perms=[], action=:refresh, name=nil)
      @thing = thing
      @id    = id
      @name  = name
      @perms = perms.to_a
      case action
        when :apply then
          apply
        when :refresh then
          refresh
        when :apply_and_refresh then
          apply; refresh
      end
    end

    # Return +true+ if the grantee has any permissions to the thing.
    def exists?
      self.class.grantees(@thing).each do |grantee|
        return true if @id == grantee.id
      end
      false
    end

    # Return Grantee type (+String+): "Group" or "CanonicalUser".
    def type
      @id[/^http:/] ? "Group" : "CanonicalUser"
    end

    # Return a name or an id.
    def to_s
      @name || @id
    end

    # Add permissions for grantee.
    # Permissions: 'READ', 'WRITE', 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'.
    # See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingPermissions.html .
    # Returns +true+.
    #
    #  grantee.grant('FULL_CONTROL')                  #=> true
    #  grantee.grant('FULL_CONTROL','WRITE','READ')   #=> true
    #  grantee.grant(['WRITE_ACP','READ','READ_ACP']) #=> true
    #
    def grant(*permissions)
      permissions.flatten!
      old_perms = @perms.dup
      @perms    += permissions
      @perms.uniq!
      return true if @perms == old_perms
      apply
    end

    # Revoke permissions for grantee.
    # Permissions: 'READ', 'WRITE', 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'
    # See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingPermissions.html .
    # Default value is 'FULL_CONTROL'.
    # Returns +true+.
    #
    #  grantee.revoke('READ')                   #=> true
    #  grantee.revoke('FULL_CONTROL','WRITE')   #=> true
    #  grantee.revoke(['READ_ACP','WRITE_ACP']) #=> true
    #
    def revoke(*permissions)
      permissions.flatten!
      old_perms = @perms.dup
      @perms    -= permissions
      @perms.uniq!
      return true if @perms == old_perms
      apply
    end

    # Revoke all permissions for this grantee.
    # Returns +true+.
    #
    #  grantee.drop #=> true
    #
    def drop
      @perms = []
      apply
    end

    # Refresh grantee perms for its +thing+.
    # Returns +true+ if the grantee has perms for this +thing+ or
    # +false+ otherwise, and updates @perms value as a side-effect.
    #
    #  grantee.grant('FULL_CONTROL') #=> true
    #  grantee.refresh               #=> true
    #  grantee.drop                  #=> true
    #  grantee.refresh               #=> false
    #
    def refresh
      @perms = []
      self.class.grantees(@thing).each do |grantee|
        if @id == grantee.id
          @name  = grantee.name
          @perms = grantee.perms
          return true
        end
      end
      false
    end

    # Apply current grantee @perms to +thing+. This method is called internally by the +grant+
    # and +revoke+ methods. In normal use this method should not
    # be called directly.
    #
    #  grantee.perms = ['FULL_CONTROL']
    #  grantee.apply #=> true
    #
    def apply
      @perms.uniq!
      owner, grantees = self.class.owner_and_grantees(@thing)
      # walk through all the grantees and replace the data for the current one and ...
      grantees.map! { |grantee| grantee.id == @id ? self : grantee }
      # ... if this grantee is not known - add this bad boy to a list
      grantees << self unless grantees.include?(self)
      # set permissions
      self.class.put_acl(@thing, owner, grantees)
    end

    def to_xml # :nodoc:
      id_str = @id[/^http/] ? "<URI>#{@id}</URI>" : "<ID>#{@id}</ID>"
      grants = ''
      @perms.each do |perm|
        grants << "<Grant>" +
            "<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
            "xsi:type=\"#{type}\">#{id_str}</Grantee>" +
            "<Permission>#{perm}</Permission>" +
            "</Grant>"
      end
      grants
    end

  end

end