Class: Parse::ACL

Inherits:
DataType show all
Defined in:
lib/parse/model/acl.rb

Overview

An ACL represents the dirty-trackable Parse Permissions object used for each record. In Parse, it is composed a hash-like object that represent User objectIds and/or a set of Role names. For each entity (ex. User/Role/Public), you can define read/write privileges on a particular record through a Permission instance.

If you want to give privileges for an action (ex. read/write), you set that particular permission it to true. If you want to deny a permission, then you set it to false. Any denied permissions will not be part of the final hash structure that is sent to parse, as omission of a permission means denial.

An ACL is represented by a JSON object with the keys being Parse::User object ids or the special key of “*”, which indicates the public access permissions. The value of each key in the hash is a Permission object which defines the boolean permission state for read and write. The example below illustrates a Parse ACL JSON object where there is a public read permission, but public write is prevented. In addition, the user with id “3KmCvT7Zsb” is allowed to both read and write this record, and the “Admins” role is also allowed write access.

{
  "*": { "read": true },
  "3KmCvT7Zsb": {  "read": true, "write": true },
  "role:Admins": { "write": true }
}

All Parse::Object subclasses have an acl property by default. With this property, you can apply and delete permissions for this particular Parse object record.

user = Parse::User.first
artist = Artist.first

artist.acl # "*": { "read": true, "write": true }

# apply public read, but no public write
artist.acl.everyone true, false

# allow user to have read and write access
artist.acl.apply user.id, true, true

# remove all permissions for this user id
artist.acl.delete user.id

# allow the 'Admins' role read and write
artist.acl.apply_role "Admins", true, true

# remove write from all attached privileges
artist.acl.no_write!

# remove all attached privileges
artist.acl.master_key_only!

artist.save

You may also set default ACLs for your subclasses by using Object.set_default_acl. These will be get applied for newly created instances. All subclasses have public read and write enabled by default.

class AdminData < Parse::Object

  # Disable public read and write
  set_default_acl :public, read: true, write: false

  # Allow Admin roles to read/write
  set_default_acl 'Admin', role: true, read: true, write: true

end

data = AdminData.new
data.acl # => ACL({"role:Admin"=>{"read"=>true, "write"=>true}})

For more information about Parse record ACLs, see the documentation on Security.

Defined Under Namespace

Classes: Permission

Constant Summary collapse

PUBLIC =

The key field value for public permissions.

"*".freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(acls = nil, owner: nil) ⇒ ACL

Create a new ACL with default Public read/write permissions and any overrides from the input hash format.

Parameters:

  • acls (Hash) (defaults to: nil)

    a Parse-compatible hash acl format.

  • owner (Parse::Object) (defaults to: nil)

    a delegate to receive notifications of acl changes. This delegate must support receiving `acl_will_change!` method.



141
142
143
144
145
# File 'lib/parse/model/acl.rb', line 141

def initialize(acls = nil, owner: nil)
  acls = acls.as_json if acls.is_a?(ACL)
  self.attributes = acls if acls.is_a?(Hash)
  @delegate = owner
end

Instance Attribute Details

#delegateObject

The instance object to be notified of changes. The delegate must support receiving a Object#acl_will_change! method.



118
# File 'lib/parse/model/acl.rb', line 118

attr_accessor :permissions, :delegate

#permissionsHash

Contains a hash structure of permissions, with keys mapping to either Public '*', a role name or an objectId for a user and values of type Permission. If you modify this attribute directly, you should call Object#acl_will_change! on the target object in order for dirty tracking to register changes.

Examples:

object.acl.permissions
# => { "*": { "read": true }, "3KmCvT7Zsb": {  "read": true, "write": true } }

Returns:

  • (Hash)

    a hash of permissions.



118
119
120
# File 'lib/parse/model/acl.rb', line 118

def permissions
  @permissions
end

Class Method Details

.everyone(read = true, write = true) ⇒ Object

Create a new ACL with default Public read/write permissions and any overrides from the input hash format.

Parameters:

  • read (Boolean) (defaults to: true)

    the read permissions for PUBLIC (default: true)

  • write (Boolean) (defaults to: true)

    the write permissions for PUBLIC (default: true)

Version:

  • 1.7.0



152
153
154
155
156
# File 'lib/parse/model/acl.rb', line 152

def self.everyone(read = true, write = true)
  acl = Parse::ACL.new
  acl.everyone(read, write)
  acl
end

.permission(read, write = nil) ⇒ ACL::Permission

Create a new ACL::Permission instance with the supplied read and write values.

Parameters:

  • read (Boolean)

    the read permission value

  • write (Boolean) (defaults to: nil)

    the write permission value.

Returns:

See Also:



163
164
165
# File 'lib/parse/model/acl.rb', line 163

def self.permission(read, write = nil)
  ACL::Permission.new(read, write)
end

.typecast(value, delegate = nil) ⇒ ACL

Used for object conversion when formatting the input/output value in Parse::Object properties

Parameters:

  • value (Hash)

    a Parse ACL hash to construct a Parse::ACL instance.

  • delegate (Object) (defaults to: nil)

    any object that would need to be notified of changes.

Returns:

See Also:



281
282
283
# File 'lib/parse/model/acl.rb', line 281

def self.typecast(value, delegate = nil)
  ACL.new(value, owner: delegate)
end

Instance Method Details

#==(other_acl) ⇒ Boolean

Determines whether two ACLs or a Parse-ACL hash is equivalent to this object.

Examples:

acl = Parse::ACL.new
# create a public read-only ACL
acl.apply :public, true, false
acl.as_json # => {'*' => { "read" => true }}

create a second instance with similar privileges
acl2 = Parse::ACL.everyone(true, false)
acl2.as_json # => {'*' => { "read" => true }}

acl == acl2 # => true
acl == {'*' => { "read" => true }} # hash ok too

acl2.apply_role 'Admin', true, true # rw for Admins
acl == acl2 # => false

Returns:

  • (Boolean)

    whether two ACLs have the same set of privileges.



184
185
186
187
# File 'lib/parse/model/acl.rb', line 184

def ==(other_acl)
  return false unless other_acl.is_a?(self.class) || other_acl.is_a?(Hash)
  as_json == other_acl.as_json
end

#all_read!Array

Grants read permission on all existing users and roles attached to this object.

Examples:

object.acl
#    { "*":          { "read" : true },
#      "3KmCvT7Zsb": { "read" : true, "write": true },
#      "role:Admins": { "write": true }
#     }
object.acl.all_read!
# Outcome:
#    { "*":          { "read" : true },
#      "3KmCvT7Zsb": { "read" : true, "write": true },
#      "role:Admins": { "read" : true, "write": true}
#     }

Returns:

  • (Array)

    list of ACL keys

Version:

  • 1.7.2



353
354
355
356
357
358
# File 'lib/parse/model/acl.rb', line 353

def all_read!
  will_change!
  permissions.keys.each do |perm|
    permissions[perm].read! true
  end
end

#all_write!Array

Grants write permission on all existing users and roles attached to this object.

Examples:

object.acl
#    { "*":          { "read" : true },
#      "3KmCvT7Zsb": { "read" : true, "write": true },
#      "role:Admins": { "write": true }
#     }
object.acl.all_write!
# Outcome:
#    { "*":          { "read" : true, "write": true },
#      "3KmCvT7Zsb": { "read" : true, "write": true },
#      "role:Admins": { "write": true }
#     }

Returns:

  • (Array)

    list of ACL keys

Version:

  • 1.7.2



375
376
377
378
379
380
# File 'lib/parse/model/acl.rb', line 375

def all_write!
  will_change!
  permissions.keys.each do |perm|
    permissions[perm].write! true
  end
end

#apply(user, read = nil, write = nil) ⇒ Hash #apply(role, read = nil, write = nil) ⇒ Hash #apply(id, read = nil, write = nil) ⇒ Hash Also known as: add

Apply a new permission with a given objectId, tag or :public.

Overloads:

  • #apply(user, read = nil, write = nil) ⇒ Hash

    Set the read and write permissions for this user on this ACL.

    Parameters:

    • user (Parse::User)

      the user object.

    • read (Boolean) (defaults to: nil)

      the read permission.

    • write (Boolean) (defaults to: nil)

      the write permission.

  • #apply(role, read = nil, write = nil) ⇒ Hash

    Set the read and write permissions for this role object on this ACL.

    Parameters:

    • role (Parse::Role)

      the role object.

    • read (Boolean) (defaults to: nil)

      the read permission.

    • write (Boolean) (defaults to: nil)

      the write permission.

  • #apply(id, read = nil, write = nil) ⇒ Hash

    Set the read and write permissions for this objectId on this ACL.

    Parameters:

    • id (String|:public)

      the objectId for a User. If :public is passed, then the PUBLIC read and write permissions will be modified.

    • read (Boolean) (defaults to: nil)

      the read permission.

    • write (Boolean) (defaults to: nil)

      the write permission.

Returns:

  • (Hash)

    the current set of permissions.

See Also:



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/parse/model/acl.rb', line 238

def apply(id, read = nil, write = nil)
  return apply_role(id, read, write) if id.is_a?(Parse::Role)
  id = id.id if id.is_a?(Parse::Pointer)
  unless id.present?
    raise ArgumentError, "Invalid argument applying ACLs: must be either objectId, role or :public"
  end
  id = PUBLIC if id.to_sym == :public
  # create a new Permissions
  permission = ACL.permission(read, write)
  # if the input is already an Permission object, then set it directly
  permission = read if read.is_a?(Parse::ACL::Permission)
  if permission.is_a?(ACL::Permission)
    if permissions[id.to_s] != permission
      will_change! # dirty track
      permissions[id.to_s] = permission
    end
  end

  permissions
end

#apply_role(role, read = nil, write = nil) ⇒ Object #apply_role(role_name, read = nil, write = nil) ⇒ Object Also known as: add_role

Apply a Role to this ACL.

Overloads:

  • #apply_role(role, read = nil, write = nil) ⇒ Object

    Parameters:

    • role (Parse::Role)

      the role object.

    • read (Boolean) (defaults to: nil)

      the read permission.

    • write (Boolean) (defaults to: nil)

      the write permission.

  • #apply_role(role_name, read = nil, write = nil) ⇒ Object

    Parameters:

    • role_name (String)

      the name of the role.

    • read (Boolean) (defaults to: nil)

      the read permission.

    • write (Boolean) (defaults to: nil)

      the write permission.



269
270
271
272
# File 'lib/parse/model/acl.rb', line 269

def apply_role(name, read = nil, write = nil)
  name = name.name if name.is_a?(Parse::Role)
  apply("role:#{name}", read, write)
end

#as_json(*args) ⇒ Hash

Returns:



310
311
312
# File 'lib/parse/model/acl.rb', line 310

def as_json(*args)
  permissions.select { |k, v| v.present? }.as_json
end

#attributesHash

Used for JSON serialization. Only if an attribute is non-nil, do we allow it in the Permissions hash, since omission means denial of priviledge. If the permission value has neither read or write, then the entire record has been denied all privileges

Returns:



290
291
292
# File 'lib/parse/model/acl.rb', line 290

def attributes
  permissions.select { |k, v| v.present? }.as_json
end

#delete(object) ⇒ Object #delete(id) ⇒ Object

Removes a permission for an objectId or user.

Overloads:

  • #delete(object) ⇒ Object

    Parameters:

    • object (Parse::User)

      the user to revoke permissions.

  • #delete(id) ⇒ Object

    Parameters:

    • id (String)

      the objectId to revoke permissions.



211
212
213
214
215
216
217
# File 'lib/parse/model/acl.rb', line 211

def delete(id)
  id = id.id if id.is_a?(Parse::Pointer)
  if id.present? && permissions.has_key?(id)
    will_change!
    permissions.delete(id)
  end
end

#everyone(read, write) ⇒ Hash Also known as: world

Set the public read and write permissions.

Parameters:

  • read (Boolean)

    the read permission state.

  • write (Boolean)

    the write permission state.

Returns:

  • (Hash)

    the current public permissions.



193
194
195
196
# File 'lib/parse/model/acl.rb', line 193

def everyone(read, write)
  apply(PUBLIC, read, write)
  permissions[PUBLIC]
end

#master_key_only!Hash Also known as: clear!

Removes all ACLs, which only allows requests using the Parse Server master key to query and modify the object.

Examples:

object.acl
#    { "*":          { "read" : true },
#      "3KmCvT7Zsb": { "read" : true, "write": true },
#      "role:Admins": { "write": true }
#     }
object.acl.master_key_only!
# Outcome:
#    { }

Returns:

  • (Hash)

    The cleared permissions hash

Version:

  • 1.7.2



332
333
334
335
# File 'lib/parse/model/acl.rb', line 332

def master_key_only!
  will_change!
  @permissions = {}
end

#no_read!Array

Denies read permission on all existing users and roles attached to this object.

Examples:

object.acl
#    { "*":          { "read" : true },
#      "3KmCvT7Zsb": { "read" : true, "write": true },
#      "role:Admins": { "write": true }
#     }
object.acl.no_read!
# Outcome:
#    { "*":          nil,
#      "3KmCvT7Zsb": { "write": true },
#      "role:Admins": { "write": true }
#     }

Returns:

  • (Array)

    list of ACL keys

Version:

  • 1.7.2



397
398
399
400
401
402
# File 'lib/parse/model/acl.rb', line 397

def no_read!
  will_change!
  permissions.keys.each do |perm|
    permissions[perm].read! false
  end
end

#no_write!Array

Denies write permission on all existing users and roles attached to this object.

Examples:

object.acl
#    { "*":          { "read" : true },
#      "3KmCvT7Zsb": { "read" : true, "write": true },
#      "role:Admins": { "write": true }
#     }
object.acl.no_write!
# Outcome:
#    { "*":          { "read" : true },
#      "3KmCvT7Zsb": { "read" : true },
#      "role:Admins": nil
#     }

Returns:

  • (Array)

    list of ACL keys

Version:

  • 1.7.2



419
420
421
422
423
424
# File 'lib/parse/model/acl.rb', line 419

def no_write!
  will_change!
  permissions.keys.each do |perm|
    permissions[perm].write! false
  end
end

#present?Boolean

Returns true if there are any permissions.

Returns:

  • (Boolean)

    true if there are any permissions.



315
316
317
# File 'lib/parse/model/acl.rb', line 315

def present?
  permissions.values.any? { |v| v.present? }
end

#will_change!Object

Calls `acl_will_change!` on the delegate when the permissions have changed. All Object subclasses implement this method.



202
203
204
# File 'lib/parse/model/acl.rb', line 202

def will_change!
  @delegate.acl_will_change! if @delegate.respond_to?(:acl_will_change!)
end