conjur-api 4.14.0 → 4.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +4 -0
- data/lib/conjur-api/version.rb +1 -1
- data/lib/conjur/acts_as_asset.rb +44 -3
- data/lib/conjur/acts_as_resource.rb +53 -4
- data/lib/conjur/acts_as_user.rb +17 -7
- data/lib/conjur/annotations.rb +49 -3
- data/lib/conjur/api.rb +30 -3
- data/lib/conjur/api/deputies.rb +25 -1
- data/lib/conjur/api/resources.rb +109 -5
- data/lib/conjur/api/roles.rb +103 -11
- data/lib/conjur/api/secrets.rb +16 -1
- data/lib/conjur/api/users.rb +65 -1
- data/lib/conjur/api/variables.rb +65 -1
- data/lib/conjur/audit-api.rb +3 -0
- data/lib/conjur/authn-api.rb +4 -0
- data/lib/conjur/authz-api.rb +4 -0
- data/lib/conjur/base.rb +31 -30
- data/lib/conjur/build_from_response.rb +11 -0
- data/lib/conjur/cast.rb +5 -1
- data/lib/conjur/core-api.rb +22 -2
- data/lib/conjur/deputy.rb +19 -2
- data/lib/conjur/env.rb +18 -3
- data/lib/conjur/escape.rb +65 -4
- data/lib/conjur/event_source.rb +15 -2
- data/lib/conjur/graph.rb +103 -12
- data/lib/conjur/has_id.rb +13 -1
- data/lib/conjur/has_identifier.rb +9 -6
- data/lib/conjur/has_owner.rb +21 -7
- data/lib/conjur/host.rb +8 -0
- data/lib/conjur/layer-api.rb +4 -0
- data/lib/conjur/layer.rb +50 -3
- data/lib/conjur/log.rb +22 -2
- data/lib/conjur/log_source.rb +27 -0
- data/lib/conjur/path_based.rb +47 -2
- data/lib/conjur/pubkeys-api.rb +12 -0
- data/lib/conjur/role.rb +220 -9
- data/lib/conjur/role_grant.rb +50 -2
- data/lib/conjur/secret.rb +9 -1
- data/lib/conjur/standard_methods.rb +31 -3
- data/lib/conjur/user.rb +55 -3
- data/spec/lib/role_spec.rb +1 -2
- metadata +2 -2
data/lib/conjur/has_id.rb
CHANGED
@@ -19,11 +19,23 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
+
|
23
|
+
# Included in classes for assets that derive their id from their urls.
|
22
24
|
module HasId
|
25
|
+
# @api private
|
26
|
+
# This method is provided to support basic JSON serialization for all objects with `id`s.
|
27
|
+
#
|
28
|
+
# @param [Hash] options provided for backwards compatibility, do not use.
|
29
|
+
# @return [Hash] the JSON hash.
|
23
30
|
def to_json(options = {})
|
24
31
|
{ id: id }
|
25
32
|
end
|
26
|
-
|
33
|
+
|
34
|
+
|
35
|
+
# Get this assets id. This is the *unqualified* Conjur id for the asset,
|
36
|
+
# and is derived from the asset's url.
|
37
|
+
#
|
38
|
+
# @return [String] the asset's id
|
27
39
|
def id
|
28
40
|
URI.unescape self.url.split('/')[-1]
|
29
41
|
end
|
@@ -19,13 +19,16 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
+
# Included in Conjur assets that have an identifier attribute.
|
22
23
|
module HasIdentifier
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
include HasAttributes
|
25
|
+
|
26
|
+
# Get the identifier attribute. This is a *fully qualified* Conjur id.
|
27
|
+
#
|
28
|
+
# ### Permissions
|
29
|
+
# You must have the "`read`" permission on the underlying resource to call this method.
|
30
|
+
#
|
31
|
+
# @return [String] the asset's fully qualified id
|
29
32
|
def identifier
|
30
33
|
attributes['identifier']
|
31
34
|
end
|
data/lib/conjur/has_owner.rb
CHANGED
@@ -19,17 +19,31 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
+
# Included in assets that have an *owner*.
|
22
23
|
module HasOwner
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
include HasAttributes
|
25
|
+
|
26
|
+
# Return the `userid` attribute. This is the id of the Conjur role that
|
27
|
+
# created this asset.
|
28
|
+
#
|
29
|
+
# ### Permissions
|
30
|
+
# You must have the "`read`" permission on the underlying resource to call this method.
|
31
|
+
#
|
32
|
+
# @return [String] the userid
|
29
33
|
def userid
|
30
34
|
attributes['userid']
|
31
35
|
end
|
32
|
-
|
36
|
+
|
37
|
+
|
38
|
+
# Return the owner of this resource or asset.
|
39
|
+
#
|
40
|
+
# The owner of a resource or an asset with an underlying resource is allowed to do anything to the resource,
|
41
|
+
# including granting permissions to other roles.
|
42
|
+
#
|
43
|
+
# ### Permissions
|
44
|
+
# You must have the "`read`" permission on the underlying resource to call this method.
|
45
|
+
#
|
46
|
+
# @return [String] the fully qualified role id of the asset's owner.
|
33
47
|
def ownerid
|
34
48
|
attributes['ownerid']
|
35
49
|
end
|
data/lib/conjur/host.rb
CHANGED
@@ -19,7 +19,15 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
+
# This class represents a {http://developer.conjur.net/reference/services/directory/host
|
23
|
+
# Conjur Host} asset. You should not create {Conjur::Host} instances directly, but use {Conjur::API}
|
24
|
+
# methods such as {Conjur::API#create_host} and {Conjur::API#host}.
|
22
25
|
class Host < Deputy
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
# @deprecated
|
29
|
+
#
|
30
|
+
# This method was used before conjurize came along. It's no longer in use.
|
23
31
|
def enrollment_url
|
24
32
|
log do |logger|
|
25
33
|
logger << "Fetching enrollment_url for #{id}"
|
data/lib/conjur/layer-api.rb
CHANGED
data/lib/conjur/layer.rb
CHANGED
@@ -1,8 +1,37 @@
|
|
1
1
|
module Conjur
|
2
|
+
|
3
|
+
# A {http://developer.conjur.net/reference/services/directory/layer Conjur Layer}
|
4
|
+
# represents a collection of
|
5
|
+
# {http://developer.conjur.net/reference/services/directory/host Conjur Hosts} with the
|
6
|
+
# ssame permissions on other Conjur resources.
|
7
|
+
#
|
8
|
+
# @example Allow hosts in the layer `dev/database` to access a `dev/database_uri` secret
|
9
|
+
# # Create the layer and add a couple of EC2 hosts
|
10
|
+
# layer = api.create_layer 'dev/database'
|
11
|
+
# hosts = ['ec2-iac5ed', 'ec2-iadc31'].map{ |hostid| api.create_host id: hostid }
|
12
|
+
# hosts.each{ |host| layer.add_host host }
|
13
|
+
#
|
14
|
+
# # A Variable representing the database uri secret
|
15
|
+
# database_uri = api.variable 'dev/database_uri'
|
16
|
+
#
|
17
|
+
# # Currently none of the hosts can access it:
|
18
|
+
# hosts.any?{ |host| host.role.permitted? database_uri, 'execute' } # => false
|
19
|
+
#
|
20
|
+
# # Grant permission on the layer
|
21
|
+
# database_uri.resource.permit 'execute', layer
|
22
|
+
#
|
23
|
+
# # Now all hosts in the layer have the execute permission on the secret through the layer
|
24
|
+
# hosts.all?{ |host| host.role.permitted? database_uri, 'execute' } # => true
|
25
|
+
#
|
2
26
|
class Layer < RestClient::Resource
|
3
27
|
include ActsAsAsset
|
4
28
|
include ActsAsRole
|
5
|
-
|
29
|
+
|
30
|
+
# Add a host to this layer. The host's role will become a member of the layer's role, and have
|
31
|
+
# all privileges of the layer.
|
32
|
+
#
|
33
|
+
# @param [String, Conjur::Host] hostid A *qualified* Conjur id for the host, or a {Conjur::Host} instance.
|
34
|
+
# @return [void]
|
6
35
|
def add_host(hostid)
|
7
36
|
hostid = cast(hostid, :roleid)
|
8
37
|
log do |logger|
|
@@ -12,7 +41,12 @@ module Conjur
|
|
12
41
|
RestClient::Resource.new(self['hosts'].url, options).post(hostid: hostid)
|
13
42
|
end
|
14
43
|
end
|
15
|
-
|
44
|
+
|
45
|
+
# Remove a host from this layer. The host will lose all privileges it had through this
|
46
|
+
# layer.
|
47
|
+
#
|
48
|
+
# @param [String, Conjur::Host] hostid A *qualified* Conjur id for the host, or a {Conjur::Host} instance.
|
49
|
+
# @return [void]
|
16
50
|
def remove_host(hostid)
|
17
51
|
hostid = cast(hostid, :roleid)
|
18
52
|
log do |logger|
|
@@ -23,11 +57,24 @@ module Conjur
|
|
23
57
|
end
|
24
58
|
end
|
25
59
|
|
26
|
-
# Lists the roles that have been granted access to the
|
60
|
+
# Lists the roles that have been granted access to the host's owned roles.
|
61
|
+
#
|
62
|
+
# `role_name` can be either `admin_host` or `use_host`. This method corresponds
|
63
|
+
# to {Conjur::ActsAsAsset#add_member} in that members added with that method
|
64
|
+
# will be returned by this method.
|
65
|
+
#
|
66
|
+
# @param [String] role_name Either `use_host` or `admin_host`
|
67
|
+
# @return [Conjur::RoleGrant] the grants associated with this host (the return type
|
68
|
+
# is identical to that of {Conjur::Role#members}).
|
69
|
+
# @see Conjur::ActsAsAsset#add_member
|
27
70
|
def hosts_members(role_name)
|
28
71
|
owned_role(role_name).members
|
29
72
|
end
|
30
73
|
|
74
|
+
|
75
|
+
# Return all hosts in the layer.
|
76
|
+
#
|
77
|
+
# @return [Array<Conjur::Host>] the hosts in the layer.
|
31
78
|
def hosts
|
32
79
|
self.attributes['hosts'].collect do |id|
|
33
80
|
Conjur::Host.new(Conjur::API.core_asset_host, options)["hosts/#{fully_escape id}"]
|
data/lib/conjur/log.rb
CHANGED
@@ -21,11 +21,26 @@
|
|
21
21
|
require 'logger'
|
22
22
|
|
23
23
|
module Conjur
|
24
|
-
#
|
24
|
+
# Assign a Logger for use by Conjur API methods. This method accepts
|
25
|
+
# several argument forms:
|
26
|
+
# * The strings 'stdout' and 'stderr' cause log messages to be sent to the corresponding stream.
|
27
|
+
# * Other stings are treated as paths and will cause log messages to be sent to those files.
|
28
|
+
# * A `Logger` instance will be used as is.
|
29
|
+
#
|
30
|
+
# Note that the logger specified by the `CONJURAPI_LOG` environment variable will override
|
31
|
+
# the value set here.
|
32
|
+
#
|
33
|
+
# @param [String, Logger,nil] log the new logger to use
|
34
|
+
# @return [void]
|
25
35
|
def self.log= log
|
26
36
|
@@log = create_log log
|
27
37
|
end
|
28
38
|
|
39
|
+
# @api private
|
40
|
+
# Create a log from a String or Logger param
|
41
|
+
#
|
42
|
+
# @param [String, Logger, nil] param the value to create the logger from
|
43
|
+
# @return Logger
|
29
44
|
def self.create_log param
|
30
45
|
if param
|
31
46
|
if param.is_a? String
|
@@ -46,7 +61,12 @@ module Conjur
|
|
46
61
|
|
47
62
|
@@log = nil
|
48
63
|
|
49
|
-
|
64
|
+
# @api private
|
65
|
+
# @note this method may return nil if no log has been set, so you **must** check the value
|
66
|
+
# before attempting to use the logger.
|
67
|
+
#
|
68
|
+
# You should consider using {Conjur::LogSource} instead.
|
69
|
+
def self.log
|
50
70
|
@@env_log || @@log
|
51
71
|
end
|
52
72
|
end
|
data/lib/conjur/log_source.rb
CHANGED
@@ -19,7 +19,34 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
+
# This module provides logging support for actions taken by the Conjur API.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# class Example
|
26
|
+
# include LogSource
|
27
|
+
#
|
28
|
+
# def something_interesting param
|
29
|
+
# log{|l| l << "doing something interesting with #{param}"}
|
30
|
+
#
|
31
|
+
# # Do something interesting...
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# end
|
35
|
+
# # ...
|
36
|
+
#
|
37
|
+
# Example.new.something_interesting 'foo'
|
38
|
+
# # will log:
|
39
|
+
# # [admin] doing something interesting with foo
|
40
|
+
#
|
22
41
|
module LogSource
|
42
|
+
# Yield a logger to the block. You should use the `<<` method to write to the
|
43
|
+
# logger so that you don't send newlines or formatting. The block will only be called
|
44
|
+
# if {Conjur.log} is not nil.
|
45
|
+
#
|
46
|
+
# The log format is `"[<username>]<messages logged in block>\n"`.
|
47
|
+
#
|
48
|
+
# @yieldparam [#<<] logger a logger to write messages
|
49
|
+
# @return [void]
|
23
50
|
def log(&block)
|
24
51
|
if Conjur.log
|
25
52
|
Conjur.log << "["
|
data/lib/conjur/path_based.rb
CHANGED
@@ -19,21 +19,66 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
+
# This module provides methods for determining Conjur id components from an asset's
|
23
|
+
# REST URL.
|
22
24
|
module PathBased
|
25
|
+
# Return the Conjur {http://developer.conjur.net/reference/services/authorization#Organization.Account
|
26
|
+
# organizational account} for this role or resource. The `account`
|
27
|
+
# is the first token in a fully qualified Conjur id, like `"account:kind:identifier"`
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# role = api.role 'foo:bar:baz'
|
31
|
+
# role.account # => 'foo'
|
32
|
+
#
|
33
|
+
# @return [String] the Conjur organizational account
|
23
34
|
def account
|
24
35
|
match_path(0..0)
|
25
36
|
end
|
26
37
|
|
38
|
+
# Return the *kind* for this role or resource. The kind partitions the space of roles and resources, generally
|
39
|
+
# according to their purpose (for example, roles representing users have kind `'user'`). The `kind` of a role or
|
40
|
+
# resource is the second token of a fully qualified Conjur id, like `"account:kind:identifier"`.
|
41
|
+
#
|
42
|
+
# @example Get the kind of a role
|
43
|
+
# role = api.host('postgres-1').role
|
44
|
+
# role.kind # => 'host'
|
45
|
+
#
|
46
|
+
# @example Get the kind of a resource
|
47
|
+
# res = api.host('postgres-1').resource
|
48
|
+
# res.kind # => 'host'
|
49
|
+
#
|
50
|
+
# @return [String] the kind of the role or resource
|
27
51
|
def kind
|
28
52
|
match_path(2..2)
|
29
53
|
end
|
30
54
|
|
31
55
|
protected
|
32
|
-
|
56
|
+
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
# Returns the path parts in the given range.
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# self.url # => "https://10.0.3.100/api/authz/foo/roles/bar/baz"
|
63
|
+
# self.match_path 0..2 # => "foo/roles/bar"
|
64
|
+
# self.match_path 2..-1 # => "bar/baz"
|
65
|
+
#
|
66
|
+
# @param [Range] range the range of parts
|
67
|
+
# @return [String] the parts joined by `'/'`
|
33
68
|
def match_path(range)
|
34
69
|
tokens[range].map{|t| URI.unescape(t)}.join('/')
|
35
70
|
end
|
36
|
-
|
71
|
+
|
72
|
+
# @api private
|
73
|
+
#
|
74
|
+
# Returns the components of this asset's path starting with the first component
|
75
|
+
# that isn't part of the authz service url.
|
76
|
+
#
|
77
|
+
# @example
|
78
|
+
# self.url # => "https://10.0.3.100/api/authz/foo/roles/bar/baz"
|
79
|
+
# self.tokens # => ["foo", "roles", "bar", "baz"]
|
80
|
+
#
|
81
|
+
# @return [Array<String>] the path components
|
37
82
|
def tokens
|
38
83
|
self.url[RestClient::Resource.new(Conjur::Authz::API.host)[''].url.length..-1].split('/')
|
39
84
|
end
|
data/lib/conjur/pubkeys-api.rb
CHANGED
@@ -22,6 +22,14 @@ require 'conjur/api'
|
|
22
22
|
require 'conjur/configuration'
|
23
23
|
|
24
24
|
class Conjur::Configuration
|
25
|
+
# @!attribute pubkeys_url
|
26
|
+
# The url for the {http://developer.conjur.net/reference/services/pubkyes Conjur public keys service}.
|
27
|
+
#
|
28
|
+
# @note You should not generally set this value. Instead, Conjur will derive it from the
|
29
|
+
# {Conjur::Configuration#account} and {Conjur::Configuration#appliance_url}
|
30
|
+
# properties.
|
31
|
+
#
|
32
|
+
# @return [String] the pubkeys service url
|
25
33
|
add_option :pubkeys_url do
|
26
34
|
account_service_url 'pubkeys', 400
|
27
35
|
end
|
@@ -29,6 +37,10 @@ end
|
|
29
37
|
|
30
38
|
class Conjur::API
|
31
39
|
class << self
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
# Url to the pubkeys service.
|
43
|
+
# @return [String] the url
|
32
44
|
def pubkeys_asset_host
|
33
45
|
Conjur.configuration.pubkeys_url
|
34
46
|
end
|
data/lib/conjur/role.rb
CHANGED
@@ -21,20 +21,47 @@
|
|
21
21
|
require 'conjur/role_grant'
|
22
22
|
|
23
23
|
module Conjur
|
24
|
+
# A {http://developer.conjur.net/reference/services/authorization/role Conjur Role} represents an actor that
|
25
|
+
# can be granted or denied permissionto do various things to
|
26
|
+
# {http://developer.conjur.net/reference/services/authorization/resource Conjur Resources}. Roles are hierarchical:
|
27
|
+
# if role a is a **member of** role b, a is permitted to do everything b is permitted
|
28
|
+
# to do. This relationship is transitive, so if a is a member of b, b is a member of c,
|
29
|
+
# and c is a member of d, a has all of d's permissions.
|
30
|
+
#
|
31
|
+
# This class represents a Role with a particular identifier. The actual Conjur role *may or may not
|
32
|
+
# exist!*
|
24
33
|
class Role < RestClient::Resource
|
25
34
|
include Exists
|
26
35
|
include PathBased
|
27
36
|
|
37
|
+
# The *unqualified* identifier for this role.
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# api.role('conjur:foo:bar').identifier # => "bar"
|
41
|
+
#
|
42
|
+
# @return [String] the unqualified identifier
|
28
43
|
def identifier
|
29
44
|
match_path(3..-1)
|
30
45
|
end
|
31
46
|
|
32
47
|
alias id identifier
|
33
|
-
|
48
|
+
|
49
|
+
# The *qualified* identifier for this role.
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# api.user('bob').role_id # => "conjur:user:bob"
|
53
|
+
#
|
54
|
+
# @return [String] the *qualified* identifier
|
34
55
|
def roleid
|
35
56
|
[ account, kind, identifier ].join(':')
|
36
57
|
end
|
37
|
-
|
58
|
+
|
59
|
+
alias role_id roleid
|
60
|
+
|
61
|
+
# @api private
|
62
|
+
# Create this role.
|
63
|
+
#
|
64
|
+
# You probably want to use {Conjur::API#create_role} instead.
|
38
65
|
def create(options = {})
|
39
66
|
log do |logger|
|
40
67
|
logger << "Creating role #{kind}:#{identifier}"
|
@@ -44,7 +71,32 @@ module Conjur
|
|
44
71
|
end
|
45
72
|
self.put(options)
|
46
73
|
end
|
47
|
-
|
74
|
+
|
75
|
+
# Find all roles of which this role is a member. This relationship is recursively expanded,
|
76
|
+
# so if `a` is a member of `b`, and `b` is a member of `c`, `a.all` will include `c`.
|
77
|
+
#
|
78
|
+
# ### Permissions
|
79
|
+
# You must be a member of the role to call this method (note that the `admin` user is
|
80
|
+
# a member of every role).
|
81
|
+
#
|
82
|
+
# You can restrict the roles returned to one or more role ids. This feature is mainly useful
|
83
|
+
# for checking whether this role is a member of any of a set of roles.
|
84
|
+
#
|
85
|
+
# @example Show all roles of which `"conjur:group:pubkeys-1.0/key-managers"` is a member
|
86
|
+
# # Add alice to the group, so we see something interesting
|
87
|
+
# key_managers = api.group('pubkeys-1.0/key-managers')
|
88
|
+
# key_managers.add_member api.user('alice')
|
89
|
+
#
|
90
|
+
# # Show the memberships, mapped to the member ids.
|
91
|
+
# key_managers.role.all.map(&:roleid)
|
92
|
+
# # => ["conjur:group:pubkeys-1.0/admin", "conjur:user:alice"]
|
93
|
+
#
|
94
|
+
# @example See if role `"conjur:user:alice"` is a member of either `"conjur:groups:developers"` or `"conjur:group:ops"`
|
95
|
+
# is_member = not api.role('conjur:user:alice').all(filter: ['conjur:group:developers', 'conjur:group:ops']).empty?
|
96
|
+
#
|
97
|
+
# @param [Hash] options options for the request
|
98
|
+
# @option options [String, #roleid, Array<String, #roleid>] :filter only return roles in this list
|
99
|
+
# @return [Array<Conjur::Role>] Roles of which this role is a member
|
48
100
|
def all(options = {})
|
49
101
|
query_string = "?all"
|
50
102
|
|
@@ -59,14 +111,95 @@ module Conjur
|
|
59
111
|
end
|
60
112
|
|
61
113
|
alias memberships all
|
62
|
-
|
114
|
+
|
115
|
+
# Check to see if this role is a member of another role. Membership is transitive.
|
116
|
+
#
|
117
|
+
# ### Permissions
|
118
|
+
# You must be logged in as a member of this role in order to call this method. Note that if you
|
119
|
+
# pass a role of which you aren't a member to this method, it will return false rather than raising an
|
120
|
+
# exception.
|
121
|
+
#
|
122
|
+
# @example Permissions
|
123
|
+
# alice_api = Conjur::API.new_from_key "alice", "alice-password"
|
124
|
+
# admin_api = Conjur::API.new_from_key "admin", "admin-password"
|
125
|
+
#
|
126
|
+
# # admin_view is the role as seen by the admin user
|
127
|
+
# admin_view = admin_api.role('conjur:group:pubkeys-1.0/key-managers')
|
128
|
+
# admin_view.member_of? alice_api.current_role # => false
|
129
|
+
# alice_api.current_role.member_of? admin_view # => false
|
130
|
+
#
|
131
|
+
# # alice_view is the role as seen by alice (who isn't a member of the key-managers group)
|
132
|
+
# alice_view = alice_api.role('conjur:group:pubkeys-1.0/key-managers')
|
133
|
+
# alice_view.member_of? alice_api.current_role # raises RestClient::Forbidden
|
134
|
+
# alice_api.current_role.member_of? alice_view # false
|
135
|
+
#
|
136
|
+
# @param [String, #roleid] other_role the role or role id of which we might be a member
|
137
|
+
# @return [Boolean] whether this role is a member of `other_role`
|
138
|
+
# @raise [RestClient::Forbidden] if you don't have permission to perform this operation
|
63
139
|
def member_of?(other_role)
|
64
140
|
other_role = cast(other_role, :roleid)
|
65
141
|
not all(filter: other_role).empty?
|
66
142
|
end
|
67
|
-
|
68
|
-
#
|
69
|
-
#
|
143
|
+
|
144
|
+
# Grant this role to another one. The role given by the `member` argument will become
|
145
|
+
# a member of this role, and have all of its permissions.
|
146
|
+
#
|
147
|
+
# ### Permissions
|
148
|
+
# You must have admin permissions on this role.
|
149
|
+
#
|
150
|
+
# @example Allow `'alice'` to do everything that `'bob'` can do (perhaps better!).
|
151
|
+
# bob = api.role 'cook:bob'
|
152
|
+
# alice = api.role 'cook:alice'
|
153
|
+
#
|
154
|
+
# # bob is allowed to 'fry' a resource called 'food:bacon'
|
155
|
+
# bob.permitted? "food:bacon", "fry" # => true
|
156
|
+
#
|
157
|
+
# # alice isn't
|
158
|
+
# alice.permitted? "food:bacon", "fry" # => false
|
159
|
+
#
|
160
|
+
# # grant the role 'cook:bob' to alice, so that she can participate in our culture's
|
161
|
+
# # bizarre bacon obsession!
|
162
|
+
# bob.grant_to alice
|
163
|
+
#
|
164
|
+
# # Now she can fry some bacon!
|
165
|
+
# alice.permitted? 'food:bacon', 'fry' # => true
|
166
|
+
#
|
167
|
+
# @example Make `alice` a member of `job:cook`, and let her grant that role to others
|
168
|
+
# # Create an api logged in as 'alice'. We assume that `api` is an admin.
|
169
|
+
# alice_api = Conjur::API.new_from_key 'alice', 'alice-password'
|
170
|
+
#
|
171
|
+
# # First do it without the `admin_option`
|
172
|
+
# api.role('job:cook').grant_to alice_api.current_role
|
173
|
+
#
|
174
|
+
# # Alice can't grant the role to bob
|
175
|
+
# alice_api.role('job:cook').grant_to 'user:bob' # => raises RestClient::Forbidden
|
176
|
+
#
|
177
|
+
# # Make alice an admin of the role
|
178
|
+
# api.role('job:cook').grant_to alice_api.current_role, admin_option: true
|
179
|
+
#
|
180
|
+
# # Now she can grant the role to bob
|
181
|
+
# alice_api.role('job:cook').grant_to 'user:bob' # Works!
|
182
|
+
#
|
183
|
+
# @example Take away a member's admin privilege
|
184
|
+
# # alice_api is an api logged in as user "alice", who has admin rights on the role 'job:cooks'.
|
185
|
+
# # Notice that she can grant the role to 'eve'
|
186
|
+
# alice_api.role('job:cook').grant_to 'eve'
|
187
|
+
#
|
188
|
+
# # We don't want her to do this any more
|
189
|
+
# admin_api.role('job:cook').grant_to 'user:alice', admin_option: false
|
190
|
+
#
|
191
|
+
# # She's still a member
|
192
|
+
# alice_api.member_of?('job:cook') # => true
|
193
|
+
#
|
194
|
+
# # But she can't grant the role to 'bob'
|
195
|
+
# alice_api.role('job:cook').grant_to 'user:bob' # raises RestClient:Forbidden
|
196
|
+
#
|
197
|
+
# @param [String, #roleid] member the role that will become a member of this role
|
198
|
+
# @param [Hash] options options for the grant
|
199
|
+
# @option options [Boolean] :admin_option when given, the admin flag on the role grant will be set to
|
200
|
+
# this value.
|
201
|
+
# @return [void]
|
202
|
+
# @raise [RestClient::Forbidden] if you don't have permission to perform the operation
|
70
203
|
def grant_to(member, options={})
|
71
204
|
member = cast(member, :roleid)
|
72
205
|
log do |logger|
|
@@ -78,6 +211,35 @@ module Conjur
|
|
78
211
|
self["?members&member=#{query_escape member}"].put(options)
|
79
212
|
end
|
80
213
|
|
214
|
+
# Remove (revoke) a member from this role. This operation is the inverse of {#grant_to}
|
215
|
+
#
|
216
|
+
# ### Permissions
|
217
|
+
# You must have admin permissions on this role
|
218
|
+
#
|
219
|
+
#
|
220
|
+
# @example Bob has been fired from his job as a cook.
|
221
|
+
# # currently, he's a member, and therefore is allowed to 'fry' the 'bacon' resource
|
222
|
+
# bob = api.role('user:bob')
|
223
|
+
# bob.member_of? 'job:cook' # true
|
224
|
+
# bob.permitted? 'food:bacon', 'fry' # true
|
225
|
+
#
|
226
|
+
# # Revoke 'job:cook'
|
227
|
+
# api.role('job:cook').revoke_from 'user:bob'
|
228
|
+
#
|
229
|
+
# # Now he's not a member, and he can't fry bacon any more
|
230
|
+
# bob.member_of? 'job:cook' # false
|
231
|
+
# bob.permitted? 'food:bacon', 'fry' # false
|
232
|
+
#
|
233
|
+
# # Note that if alice had her bacon frying permissions through her membership in the role 'user:bob',
|
234
|
+
# # she'll lose them too:
|
235
|
+
# api.role('user:alice').member_of? 'user:bob' # true
|
236
|
+
# api.role('user:alice').permitted? 'food:bacon', 'fry' # => false
|
237
|
+
#
|
238
|
+
#
|
239
|
+
# @param [String, #roleid] member the member to revoke this role from
|
240
|
+
# @param [Hash] options included for backwards compatibility. Don't use it.
|
241
|
+
# @return [void]
|
242
|
+
# @raise [RestClient::Forbidden] If you don't have permission to perform this operation
|
81
243
|
def revoke_from(member, options = {})
|
82
244
|
member = cast(member, :roleid)
|
83
245
|
log do |logger|
|
@@ -89,6 +251,46 @@ module Conjur
|
|
89
251
|
self["?members&member=#{query_escape member}"].delete(options)
|
90
252
|
end
|
91
253
|
|
254
|
+
# Check to see if this role is allowed to perform `privilege` on `resource`.
|
255
|
+
#
|
256
|
+
# ### Permissions
|
257
|
+
# Any authenticated role may call this method. However, instead of raising a 404 if a resource
|
258
|
+
# or role doesn't exist, it will return false. This is to prevent bad guys from finding out which roles
|
259
|
+
# and resources exist.
|
260
|
+
#
|
261
|
+
# @example
|
262
|
+
# bacon = api.create_resource 'food:bacon'
|
263
|
+
# eggs = api.create_resoure 'food:eggs'
|
264
|
+
# bob = api.create_role 'cook:bob'
|
265
|
+
#
|
266
|
+
# # Bob can't do anything initially
|
267
|
+
# bob.permitted? bacon, 'fry' # => false
|
268
|
+
# bob.permitted? eggs, 'poach' # => false
|
269
|
+
#
|
270
|
+
# # Let him poach eggs
|
271
|
+
# eggs.permit 'poach', bob
|
272
|
+
#
|
273
|
+
# # Now it's permitted
|
274
|
+
# bob.permitted? eggs, 'poach' # => true
|
275
|
+
#
|
276
|
+
# @example Somethign a bit more realistic
|
277
|
+
# # Say we have a service layer that needs access to a database connection string.
|
278
|
+
# # The layer is called 'web', and the connection string is stored in a variable 'mysql-uri'
|
279
|
+
# web_layer = api.layer 'web'
|
280
|
+
# mysql_uri = api.variable 'mysql-uri'
|
281
|
+
#
|
282
|
+
# # The web layer can't see the value of the variable right now:
|
283
|
+
# web_layer.role.permitted? mysql_uri, 'execute' # => false
|
284
|
+
#
|
285
|
+
# # Let's permit that
|
286
|
+
# mysql_uri.permit 'execute', web_layer
|
287
|
+
#
|
288
|
+
# # Now it's allowed to fetch the connection string
|
289
|
+
# web_layer.role.permitted? mysql_uri, 'execute' # => true
|
290
|
+
#
|
291
|
+
# @param [#resourceid, String] resource the resource to check the permission against
|
292
|
+
# @param [String] privilege the privilege to check
|
293
|
+
# @return [Boolean] true if this role has the privilege on the resource
|
92
294
|
def permitted?(resource, privilege, options = {})
|
93
295
|
resource = cast(resource, :resourceid)
|
94
296
|
# NOTE: in previous versions there was 'kind' passed separately. Now it is part of id
|
@@ -98,10 +300,19 @@ module Conjur
|
|
98
300
|
false
|
99
301
|
end
|
100
302
|
|
101
|
-
|
303
|
+
|
304
|
+
# Fetch the members of this role. The results are *not* recursively expanded (in contrast to {#memberships}).
|
305
|
+
#
|
306
|
+
# ### Permissions
|
307
|
+
# You must be a member of the role to call this method.
|
308
|
+
#
|
309
|
+
# @param [Hash] options unused and included only for backwards compatibility
|
310
|
+
# @return [Array<Conjur::RoleGrant>] the role memberships
|
311
|
+
# @raise [RestClient::Forbidden] if you don't have permission to perform this operation
|
312
|
+
def members
|
102
313
|
JSON.parse(self["?members"].get(options)).collect do |json|
|
103
314
|
RoleGrant.parse_from_json(json, self.options)
|
104
315
|
end
|
105
316
|
end
|
106
317
|
end
|
107
|
-
end
|
318
|
+
end
|