conjur-api 4.14.0 → 4.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|