Class: Conjur::Role

Inherits:
RestClient::Resource
  • Object
show all
Includes:
Exists, PathBased
Defined in:
lib/conjur/role.rb

Overview

A Conjur Role represents an actor that can be granted or denied permissionto do various things to Conjur Resources. Roles are hierarchical: if role a is a member of role b, a is permitted to do everything b is permitted to do. This relationship is transitive, so if a is a member of b, b is a member of c, and c is a member of d, a has all of d's permissions.

This class represents a Role with a particular identifier. The actual Conjur role may or may not exist!

Instance Method Summary collapse

Methods included from PathBased

#account, #kind

Methods included from Exists

#exists?

Instance Method Details

#all(options = {}) ⇒ Array<Conjur::Role> Also known as: memberships

Find all roles of which this role is a member. This relationship is recursively expanded, so if a is a member of b, and b is a member of c, a.all will include c.

Permissions

You must be a member of the role to call this method (note that the admin user is a member of every role).

You can restrict the roles returned to one or more role ids. This feature is mainly useful for checking whether this role is a member of any of a set of roles.

Examples:

Show all roles of which "conjur:group:pubkeys-1.0/key-managers" is a member

# Add alice to the group, so we see something interesting
key_managers = api.group('pubkeys-1.0/key-managers')
key_managers.add_member api.user('alice')

# Show the memberships, mapped to the member ids.
key_managers.role.all.map(&:roleid)
# => ["conjur:group:pubkeys-1.0/admin", "conjur:user:alice"]

See if role "conjur:user:alice" is a member of either "conjur:groups:developers" or "conjur:group:ops"

is_member = not api.role('conjur:user:alice').all(filter: ['conjur:group:developers', 'conjur:group:ops']).empty?

Parameters:

  • options (Hash) (defaults to: {})

    options for the request

Options Hash (options):

  • :filter (String, #roleid, Array<String, #roleid>)

    only return roles in this list

Returns:

  • (Array<Conjur::Role>)

    Roles of which this role is a member



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/conjur/role.rb', line 100

def all(options = {})
  query_string = "?all"
  
  if filter = options.delete(:filter)
    filter = [filter] unless filter.is_a?(Array)
    filter.map!{ |obj| cast(obj, :roleid) }
    (query_string << "&" << filter.to_query("filter")) unless filter.empty?
  end
  JSON.parse(self[query_string].get(options)).collect do |id|
    Role.new(Conjur::Authz::API.host, self.options)[Conjur::API.parse_role_id(id).join('/')]
  end
end

#grant_to(member, options = {})

This method returns an undefined value.

Grant this role to another one. The role given by the member argument will become a member of this role, and have all of its permissions.

Permissions

You must have admin permissions on this role.

Examples:

Allow 'alice' to do everything that 'bob' can do (perhaps better!).

bob = api.role 'cook:bob'
alice = api.role 'cook:alice'

# bob is allowed to 'fry' a resource called 'food:bacon'
bob.permitted? "food:bacon", "fry" # => true

# alice isn't
alice.permitted? "food:bacon", "fry" # => false

# grant the role 'cook:bob'  to alice, so that she can participate in our culture's
# bizarre bacon obsession!
bob.grant_to alice

# Now she can fry some bacon!
alice.permitted? 'food:bacon', 'fry' # => true

Make alice a member of job:cook, and let her grant that role to others

# Create an api logged in as 'alice'.  We assume that `api` is an admin.
alice_api = Conjur::API.new_from_key 'alice', 'alice-password'

# First do it without the `admin_option`
api.role('job:cook').grant_to alice_api.current_role

# Alice can't grant the role to bob
alice_api.role('job:cook').grant_to 'user:bob' # => raises RestClient::Forbidden

# Make alice an admin of the role
api.role('job:cook').grant_to alice_api.current_role, admin_option: true

# Now she can grant the role to bob
alice_api.role('job:cook').grant_to 'user:bob' # Works!

Take away a member's admin privilege

# alice_api is an api logged in as user "alice", who has admin rights on the role 'job:cooks'.
# Notice that she can grant the role to 'eve'
alice_api.role('job:cook').grant_to 'eve'

# We don't want her to do this any more
admin_api.role('job:cook').grant_to 'user:alice', admin_option: false

# She's still a member
alice_api.member_of?('job:cook') # => true

# But she can't grant the role to 'bob'
alice_api.role('job:cook').grant_to 'user:bob' # raises RestClient:Forbidden

Parameters:

  • member (String, #roleid)

    the role that will become a member of this role

  • options (Hash) (defaults to: {})

    options for the grant

Options Hash (options):

  • :admin_option (Boolean)

    when given, the admin flag on the role grant will be set to this value.

Raises:

  • (RestClient::Forbidden)

    if you don't have permission to perform the operation



203
204
205
206
207
208
209
210
211
212
# File 'lib/conjur/role.rb', line 203

def grant_to(member, options={})
  member = cast(member, :roleid)
  log do |logger|
    logger << "Granting role #{identifier} to #{member}"
    unless options.blank?
      logger << " with options #{options.to_json}"
    end
  end
  self["?members&member=#{query_escape member}"].put(options)
end

#identifierString Also known as: id

The unqualified identifier for this role.

Examples:

api.role('conjur:foo:bar').identifier # => "bar"

Returns:

  • (String)

    the unqualified identifier



43
44
45
# File 'lib/conjur/role.rb', line 43

def identifier
  match_path(3..-1)
end

#member_of?(other_role) ⇒ Boolean

Check to see if this role is a member of another role. Membership is transitive.

Permissions

You must be logged in as a member of this role in order to call this method. Note that if you pass a role of which you aren't a member to this method, it will return false rather than raising an exception.

Examples:

Permissions

alice_api = Conjur::API.new_from_key "alice", "alice-password"
admin_api = Conjur::API.new_from_key "admin", "admin-password"

# admin_view is the role as seen by the admin user
admin_view = admin_api.role('conjur:group:pubkeys-1.0/key-managers')
admin_view.member_of? alice_api.current_role # => false
alice_api.current_role.member_of? admin_view # => false

# alice_view is the role as seen by alice (who isn't a member of the key-managers group)
alice_view = alice_api.role('conjur:group:pubkeys-1.0/key-managers')
alice_view.member_of? alice_api.current_role # raises RestClient::Forbidden
alice_api.current_role.member_of? alice_view # false

Parameters:

  • other_role (String, #roleid)

    the role or role id of which we might be a member

Returns:

  • (Boolean)

    whether this role is a member of other_role

Raises:

  • (RestClient::Forbidden)

    if you don't have permission to perform this operation



139
140
141
142
# File 'lib/conjur/role.rb', line 139

def member_of?(other_role)
  other_role = cast(other_role, :roleid)
  not all(filter: other_role).empty?
end

#membersArray<Conjur::RoleGrant>

Fetch the members of this role. The results are not recursively expanded (in contrast to #memberships).

Permissions

You must be a member of the role to call this method.

Parameters:

  • options (Hash)

    unused and included only for backwards compatibility

Returns:

Raises:

  • (RestClient::Forbidden)

    if you don't have permission to perform this operation



312
313
314
315
316
# File 'lib/conjur/role.rb', line 312

def members
  JSON.parse(self["?members"].get(options)).collect do |json|
    RoleGrant.parse_from_json(json, self.options)
  end
end

#permitted?(resource, privilege, options = {}) ⇒ Boolean

Check to see if this role is allowed to perform privilege on resource.

Permissions

Any authenticated role may call this method. However, instead of raising a 404 if a resource or role doesn't exist, it will return false. This is to prevent bad guys from finding out which roles and resources exist.

web_layer.role.permitted? mysql_uri, 'execute' # => true

Examples:

bacon = api.create_resource 'food:bacon'
eggs  = api.create_resoure 'food:eggs'
bob = api.create_role 'cook:bob'

# Bob can't do anything initially
bob.permitted? bacon, 'fry' # => false
bob.permitted? eggs, 'poach' # => false

# Let him poach eggs
eggs.permit 'poach', bob

# Now it's permitted
bob.permitted? eggs, 'poach' # => true

Somethign a bit more realistic

# Say we have a service layer that needs access to a database connection string.
# The layer is called 'web', and the connection string is stored in a variable 'mysql-uri'
web_layer = api.layer 'web'
mysql_uri = api.variable 'mysql-uri'

# The web layer can't see the value of the variable right now:
web_layer.role.permitted? mysql_uri, 'execute' # => false

# Let's permit that
mysql_uri.permit 'execute', web_layer

# Now it's allowed to fetch the connection string

Parameters:

  • resource (#resourceid, String)

    the resource to check the permission against

  • privilege (String)

    the privilege to check

Returns:

  • (Boolean)

    true if this role has the privilege on the resource



294
295
296
297
298
299
300
301
# File 'lib/conjur/role.rb', line 294

def permitted?(resource, privilege, options = {})
  resource = cast(resource, :resourceid)
  # NOTE: in previous versions there was 'kind' passed separately. Now it is part of id
  self["?check&resource_id=#{query_escape resource}&privilege=#{query_escape privilege}"].get(options)
  true
rescue RestClient::ResourceNotFound
  false
end

#revoke_from(member, options = {})

This method returns an undefined value.

Remove (revoke) a member from this role. This operation is the inverse of #grant_to

Permissions

You must have admin permissions on this role

Examples:

Bob has been fired from his job as a cook.

# currently, he's a member, and therefore is allowed to 'fry' the 'bacon' resource
bob = api.role('user:bob')
bob.member_of? 'job:cook' # true
bob.permitted? 'food:bacon', 'fry' # true

# Revoke 'job:cook'
api.role('job:cook').revoke_from 'user:bob'

# Now he's not a member, and he can't fry bacon any more
bob.member_of? 'job:cook' # false
bob.permitted? 'food:bacon', 'fry' # false

# Note that if alice had her bacon frying permissions through her membership in the role 'user:bob',
# she'll lose them too:
api.role('user:alice').member_of? 'user:bob' # true
api.role('user:alice').permitted? 'food:bacon', 'fry' # => false

Parameters:

  • member (String, #roleid)

    the member to revoke this role from

  • options (Hash) (defaults to: {})

    included for backwards compatibility. Don't use it.

Raises:

  • (RestClient::Forbidden)

    If you don't have permission to perform this operation



243
244
245
246
247
248
249
250
251
252
# File 'lib/conjur/role.rb', line 243

def revoke_from(member, options = {})
  member = cast(member, :roleid)
  log do |logger|
    logger << "Revoking role #{identifier} from #{member}"
    unless options.empty?
      logger << " with options #{options.to_json}"
    end
  end
  self["?members&member=#{query_escape member}"].delete(options)
end

#roleidString Also known as: role_id

The qualified identifier for this role.

Examples:

api.user('bob').role_id # => "conjur:user:bob"

Returns:

  • (String)

    the qualified identifier



55
56
57
# File 'lib/conjur/role.rb', line 55

def roleid
  [ , kind, identifier ].join(':')
end