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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +4 -0
  4. data/lib/conjur-api/version.rb +1 -1
  5. data/lib/conjur/acts_as_asset.rb +44 -3
  6. data/lib/conjur/acts_as_resource.rb +53 -4
  7. data/lib/conjur/acts_as_user.rb +17 -7
  8. data/lib/conjur/annotations.rb +49 -3
  9. data/lib/conjur/api.rb +30 -3
  10. data/lib/conjur/api/deputies.rb +25 -1
  11. data/lib/conjur/api/resources.rb +109 -5
  12. data/lib/conjur/api/roles.rb +103 -11
  13. data/lib/conjur/api/secrets.rb +16 -1
  14. data/lib/conjur/api/users.rb +65 -1
  15. data/lib/conjur/api/variables.rb +65 -1
  16. data/lib/conjur/audit-api.rb +3 -0
  17. data/lib/conjur/authn-api.rb +4 -0
  18. data/lib/conjur/authz-api.rb +4 -0
  19. data/lib/conjur/base.rb +31 -30
  20. data/lib/conjur/build_from_response.rb +11 -0
  21. data/lib/conjur/cast.rb +5 -1
  22. data/lib/conjur/core-api.rb +22 -2
  23. data/lib/conjur/deputy.rb +19 -2
  24. data/lib/conjur/env.rb +18 -3
  25. data/lib/conjur/escape.rb +65 -4
  26. data/lib/conjur/event_source.rb +15 -2
  27. data/lib/conjur/graph.rb +103 -12
  28. data/lib/conjur/has_id.rb +13 -1
  29. data/lib/conjur/has_identifier.rb +9 -6
  30. data/lib/conjur/has_owner.rb +21 -7
  31. data/lib/conjur/host.rb +8 -0
  32. data/lib/conjur/layer-api.rb +4 -0
  33. data/lib/conjur/layer.rb +50 -3
  34. data/lib/conjur/log.rb +22 -2
  35. data/lib/conjur/log_source.rb +27 -0
  36. data/lib/conjur/path_based.rb +47 -2
  37. data/lib/conjur/pubkeys-api.rb +12 -0
  38. data/lib/conjur/role.rb +220 -9
  39. data/lib/conjur/role_grant.rb +50 -2
  40. data/lib/conjur/secret.rb +9 -1
  41. data/lib/conjur/standard_methods.rb +31 -3
  42. data/lib/conjur/user.rb +55 -3
  43. data/spec/lib/role_spec.rb +1 -2
  44. metadata +2 -2
@@ -23,18 +23,20 @@ require 'conjur/graph'
23
23
 
24
24
  module Conjur
25
25
  class API
26
- ##
27
- # Fetch a digraph (or a forest of digraphs) representing of
28
- # role memberships related transitively to any of a list of roles.
29
- #
30
- # @param [Array<Conjur::Role, String>] roles the digraph (or forest thereof) of
31
- # the ancestors and descendants of these roles or role ids will be returned
32
- # @param [Hash] options options determining the graph returned
33
- # @option opts [Boolean] :ancestors Whether to return ancestors of the given roles (true by default)
34
- # @option opts [Boolean] :descendants Whether to return descendants of the given roles (true by default)
35
- # @option opts [Conjur::Role, String] :as_role Only roles visible to this role will be included in the graph
26
+ #@!group Authorization: Roles
27
+
28
+ # Fetch a {Conjur::Graph} representing the relationships of a given role or roles. Such graphs are transitive,
29
+ # and follow the normal permissions for role visibility.
30
+ #
31
+ # @param [Array<Conjur::Role, String>, String, Conjur::Role] roles role or or array of roles
32
+ # roles whose relationships we're interested in
33
+ # @param [Hash] options options for the request
34
+ # @option options [Boolean] :ancestors Whether to return ancestors of the given roles (true by default)
35
+ # @option options [Boolean] :descendants Whether to return descendants of the given roles (true by default)
36
+ # @option options [Conjur::Role, String] :as_role Only roles visible to this role will be included in the graph
36
37
  # @return [Conjur::Graph] An object representing the role memberships digraph
37
38
  def role_graph roles, options = {}
39
+ roles = [roles] unless roles.kind_of? Array
38
40
  roles.map!{|r| normalize_roleid(r) }
39
41
  options[:as_role] = normalize_roleid(options[:as_role]) if options.include?(:as_role)
40
42
  options.reverse_merge! as_role: normalize_roleid(current_role), descendants: true, ancestors: true
@@ -45,24 +47,108 @@ module Conjur
45
47
  Conjur::Graph.new RestClient::Resource.new(Conjur::Authz::API.host, credentials)["#{Conjur.account}/roles?#{query}"].get
46
48
  end
47
49
 
50
+ # Create a {Conjur::Role} with the given id.
51
+ #
52
+ # ### Permissions
53
+ # * All Conjur roles can create new roles.
54
+ # * The creator role (either the current role or the role given by the `:acting_as` option)
55
+ # is made a member of the new role. The new role is also made a member of itself.
56
+ # * If you give an `:acting_as` option, you must be a (transitive) member of the `:acting_as`
57
+ # role.
58
+ # * The new role is granted to the creator role with *admin option*: that is, the creator role
59
+ # is able to grant the created role to other roles.
60
+ #
61
+ # @example Basic role creation
62
+ # # Current role is 'user:jon', assume the organizational account is 'conjur'
63
+ # api.current_role # => 'conjur:user:jon'
64
+ #
65
+ # # Create a Conjur actor to control the permissions of a chron job (rebuild_indices)
66
+ # role = api.create_role 'robot:rebuild_indices'
67
+ # role.role_id # => "conjur:robot:rebuild_indices"
68
+ # role.members.map{ |grant| grant.member.role_id } # => ['conjur:user:jon', 'conjur:robot:rebuild_indices']
69
+ # api.role('user:jon').admin_of?(role) # => true
70
+ #
71
+ #
72
+ # @param [String] role a qualified role identifier for the new role
73
+ # @param [Hash] options options for the action
74
+ # @option options [String] :acting_as the resource will effectively be created by this role
75
+ # @return [Conjur::Role] the created role
76
+ # @raise [RestClient::MethodNotAllowed] if the role already exists. Note that this differs from
77
+ # the `RestClient::Conflict` exception raised when trying to create existing high level (user, group, etc.)
78
+ # Conjur assets.
48
79
  def create_role(role, options = {})
49
80
  role(role).tap do |r|
50
81
  r.create(options)
51
82
  end
52
83
  end
53
84
 
85
+ # Return a {Conjur::Role} representing a role with the given id. Note that the {Conjur::Role} may or
86
+ # may not exist (see {Conjur::Exists#exists?}).
87
+ #
88
+ # ### Permissions
89
+ # Because this method returns roles that may or may not exist, it doesn't require any permissions to call it:
90
+ # in fact, it does not perform an HTTP request (except for authentication if necessary).
91
+ #
92
+ # @example Create and show a role
93
+ # api.create_role 'cat:iggy'
94
+ # iggy = api.role 'cat:iggy'
95
+ # iggy.exists? # true
96
+ # iggy.members.map(&:member).map(&:roleid) # => ['conjur:user:admin']
97
+ # api.current_role.roleid # => 'conjur:user:admin' # creator role is a member of created role.
98
+ #
99
+ # @example No permissions are required to call this method
100
+ # api.current_role # => "user:no-access"
101
+ #
102
+ # # current role is only a member of itself, so it can't see other roles.
103
+ # api.current_role.memberships.count # => 1
104
+ # admin = api.role 'user:admin' # OK
105
+ # admin.exists? # => true
106
+ # admin.members # => RestClient::Forbidden: 403 Forbidden
107
+ #
108
+ # @param [String] role the id of the role, which must contain at least kind and id tokens (account is optional).
109
+ # @return [Conjur::Role] an object representing the role
54
110
  def role role
55
111
  Role.new(Conjur::Authz::API.host, credentials)[self.class.parse_role_id(role).join('/')]
56
112
  end
57
113
 
114
+ # Return a {Conjur::Role} object representing the role (typically a user or host) that this api is authenticated
115
+ # as. This is derived either from the `login` argument to {Conjur::API.new_from_key} or from the contents of the
116
+ # `token` given to {Conjur::API.new_from_token}.
117
+ #
118
+ # @example Current role for a user
119
+ # api = Conjur::API.new_from_key 'jon', 'somepassword'
120
+ # api.current_role.roleid # => 'conjur:user:jon'
121
+ #
122
+ # @example Current role for a host
123
+ # host = api.create_host id: 'exapmle-host'
124
+ #
125
+ # # Host and User have an `api` method that returns an api with their credentials. Note
126
+ # # that this only works with a newly created host or user, which has an `api_key` attribute.
127
+ # host.api.current_role.roleid # => 'conjur:host:example-host'
128
+ #
129
+ # @return [Conjur::Role] the authenticated role for this API instance
58
130
  def current_role
59
131
  role_from_username username
60
132
  end
61
133
 
134
+
135
+ #@!endgroup
136
+
137
+ # @api private
138
+ #
139
+ # Get a Role instance from a username or host id
140
+ # @param [String] username the username or host id
141
+ # @return [Conjur::Role]
62
142
  def role_from_username username
63
143
  role(role_name_from_username username)
64
144
  end
65
145
 
146
+ # @api private
147
+ #
148
+ # Convert a username or host id to a role identifier.
149
+ # This handles conversion of logins like 'host/foo' to 'host:foo'
150
+ # @param [String] username the user name or host id
151
+ # @return [String] A full role id for the user or host
66
152
  def role_name_from_username username = self.username
67
153
  tokens = username.split('/')
68
154
  if tokens.size == 1
@@ -71,8 +157,14 @@ module Conjur
71
157
  [ tokens[0], tokens[1..-1].join('/') ].join(':')
72
158
  end
73
159
  end
74
-
160
+
75
161
  private
162
+
163
+ # @api private
164
+ # Use of this method is deprecated in favor of Conjur::Cast#cast
165
+ # @deprecated
166
+ # @param [String, Conjur::Role] role object to extract a role id from
167
+ # @return [String] the role id
76
168
  def normalize_roleid role
77
169
  case role
78
170
  when String then role
@@ -22,10 +22,25 @@ require 'conjur/secret'
22
22
 
23
23
  module Conjur
24
24
  class API
25
+
26
+ # @api private
27
+ #
28
+ # Create a Conjur secret. Secrets are a low-level construcct upon which variables
29
+ # are built,
30
+ #
31
+ # @param [String] value the secret data
32
+ # @return [Conjur::Secret] the new secret
25
33
  def create_secret(value, options = {})
26
34
  standard_create Conjur::Core::API.host, :secret, nil, options.merge(value: value)
27
35
  end
28
-
36
+
37
+ # @api private
38
+ #
39
+ # Fetch a Conjur secret by id. Secrets are a low-level construct upon which variables
40
+ # are built, and should not generally be used directly.
41
+ #
42
+ # @param [String] id the *unqualified* identifier for the secret
43
+ # @return [Conjur::Secret] an object representing the secret
29
44
  def secret id
30
45
  standard_show Conjur::Core::API.host, :secret, id
31
46
  end
@@ -7,7 +7,7 @@
7
7
  # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
8
  # the Software, and to permit persons to whom the Software is furnished to do so,
9
9
  # subject to the following conditions:
10
- #
10
+ ##
11
11
  # The above copyright notice and this permission notice shall be included in all
12
12
  # copies or substantial portions of the Software.
13
13
  #
@@ -22,16 +22,80 @@ require 'conjur/user'
22
22
 
23
23
  module Conjur
24
24
  class API
25
+ #@!group Directory: Users
26
+
27
+ # Create a {http://developer.conjur.net/reference/services/directory/user Conjur User}. Conjur users
28
+ # are identities for humans.
29
+ #
30
+ # When you create a user for the first time, the returned object will have an `api_key` field. You can then
31
+ # use this to set a password for the user if you want to. Note that when the user is fetched later with the {#user}
32
+ # method, it **will not have an api_key**. Use it or lose it.
33
+ #
34
+ # ### Permissions
35
+ # Any authenticated role may call this method.
36
+ #
37
+ # @example Create a user 'alice' and set her password to 'frogger'
38
+ # alice = api.create_user 'alice', password: 'frogger'
39
+ #
40
+ # # Now we can login as 'alice'.
41
+ # alice_api = Conjur::API.new_from_key 'alice', 'frogger'
42
+ # alice_api.current_role # => 'conjur:user:alice'
43
+ #
44
+ # @example Create a user and save her `api_key` for later use
45
+ # alice = api.create_user 'alice' # note that we're not giving a password
46
+ # save_api_key 'alice', alice.api_key
47
+ #
48
+ # @param [String] login the login for the new user
49
+ # @param [Hash] options options for user creation
50
+ # @option options [String] :acting_as Qualified id of a role to perform the action as
51
+ # @option options [String, Integer] :uidnumber UID number to assign to the new user. If not given, one will be generated.
52
+ # @option options [String] :password when present, the user will be given a password in addition to a randomly
53
+ # generated api key.
54
+ # @return [Conjur::User] an object representing the new user
55
+ # @raise [RestClient::Conflict] If the user already exists, or a user with the given uidnumber exists.
25
56
  def create_user(login, options = {})
26
57
  standard_create Conjur::Core::API.host, :user, nil, options.merge(login: login)
27
58
  end
28
59
 
60
+ # Return an object representing a user with the given login. The {Conjur::User} object returned
61
+ # may or may not exist. You can check whether it exists with the {Conjur::Exists#exists?} method.
62
+ #
63
+ # The returned {Conjur::User} will *not* have an api_key.
64
+ #
65
+ # ### Permissions
66
+ # Any authenticated role may call this method.
67
+ #
68
+ # @param [String] login the user's login
69
+ # @return [Conjur::User] an object representing the user
29
70
  def user login
30
71
  standard_show Conjur::Core::API.host, :user, login
31
72
  end
32
73
 
74
+ # @api private
75
+ #
76
+ # @note In the future, further options for search may be added, but presently this only supports uid search.
77
+ #
78
+ # Find users by uidnumber.
79
+ #
80
+ #
81
+ # When a user is created it is assigned a uid number. When the uid number is not specified when creating the user,
82
+ # a sequential uid number will be generated, starting at 1000. uidnumbers are used when synchronizing with LDAP directories
83
+ # and to assign a UNIX user id number when using {http://developer.conjur.net/tutorials/ssh/conjur-ssh.html Conjur SSH login}.
84
+ #
85
+ # ### Note
86
+ # Although users are uniquely identified by their uidnumber, the result of this method is an array of user ids for compatibility
87
+ # reasons.
88
+ #
89
+ # ### Permissions
90
+ # Only roles of which you are a member will be returned
91
+ #
92
+ # @param [Hash] options query to send
93
+ # @option options [String, Integer] :uidnumber (required) the uidnumber to search for
94
+ # @return [Array<String>] a one element array containing the users login.
33
95
  def find_users options
34
96
  JSON.parse( RestClient::Resource.new(Conjur::Core::API.host, credentials)["users/search?#{options.to_query}"].get )
35
97
  end
98
+
99
+ #@!endgroup
36
100
  end
37
101
  end
@@ -22,14 +22,77 @@ require 'conjur/variable'
22
22
 
23
23
  module Conjur
24
24
  class API
25
+ #@!group Directory: Variables
26
+
27
+ # Create a {http://developer.conjur.net/reference/services/directory/variable Conjur Variable}.
28
+ # See {Conjur::Variable} for operations on Conjur variables.
29
+ #
30
+ # ### Permissions
31
+ # Any authenticated role may call this method
32
+ #
33
+ # @example Create a variable to store a database connection string
34
+ # db_uri = "mysql://username:password@mysql.somehost.com/mydb"
35
+ # var = api.create_variable 'text/plain', 'mysql-connection-string', id: 'production/mysql/uri'
36
+ # var.add_value db_uri
37
+ #
38
+ # # Alternatively, we could have done this:
39
+ # var = api.create_variable 'text/plain', 'mysql-connection-string',
40
+ # id: 'production/mysql/uri',
41
+ # value: db_uri
42
+ #
43
+ # @example Create a variable with a unique random id
44
+ # var = api.create_variable 'text/plain', 'secret'
45
+ # var.id # => 'kngeqg'
46
+ #
47
+ # @param [String] mime_type MIME type for the variable value, used to set the `"Content-Type"`header
48
+ # when serving the variable's value. Must be non-empty.
49
+ # @param [String] kind user defined `kind` for the variable. This is useful as a simple way to document
50
+ # the variable's purpose. Must be non-empty
51
+ # @param [Hash] options options for the new variable
52
+ # @option options [String] :id specify an id for the new variable. Must be non-empty.
53
+ # @option options [String] :value specify an initial value for the variable
54
+ # @return [Conjur::Variable] an object representing the new variable
55
+ # @raise [RestClient::Conflict] if you give an `:id` option and the variable already exists
56
+ # @raise [RestClient::UnprocessableEntity] if `mime_type`, `kind`, or `options[:id]` is the empty string.
25
57
  def create_variable(mime_type, kind, options = {})
26
58
  standard_create Conjur::Core::API.host, :variable, nil, options.merge(mime_type: mime_type, kind: kind)
27
59
  end
28
-
60
+
61
+ # Retrieve an object representing a {http://developer.conjur.net/reference/services/directory/variable Conjur Variable}.
62
+ # The {Conjur::Variable} returned may or may not exist, and
63
+ # your permissions on the corresponding resource determine the operations you can perform on it.
64
+ #
65
+ # ### Permissions
66
+ # Any authenticated role can call this method.
67
+ #
68
+ # @param [String] id the unqualified id of the variable
69
+ # @return [Conjur::Variable] and object representing the variable.
29
70
  def variable id
30
71
  standard_show Conjur::Core::API.host, :variable, id
31
72
  end
32
73
 
74
+ # Fetch the values of a list of variables. This operation is more efficient than fetching the
75
+ # values one by one.
76
+ #
77
+ # This method will fail unless:
78
+ # * All of the variables exist
79
+ # * You have permission to `'execute'` all of the variables
80
+ #
81
+ # @example Fetch multiple variable values
82
+ # values = variable_values ['postgres_uri', 'aws_secret_access_key', 'aws_access_key_id']
83
+ # values # =>
84
+ # {
85
+ # "postgres_uri" => "postgres://..."
86
+ # "aws_secret_access_key" => "..."
87
+ # "aws_access_key_id" => "..."
88
+ # }
89
+ #
90
+ # This method is used to implement the {http://developer.conjur.net/reference/tools/utilities/conjurenv `conjur env`}
91
+ # commands. You may consider using that instead to run your program in an environment with the necessary secrets.
92
+ #
93
+ # @param [Array<String>] varlist list of variable ids to fetch
94
+ # @return [Hash] a hash mapping variable ids to variable values
95
+ # @raise [RestClient::Forbidden, RestClient::ResourceNotFound] if any of the variables don't exist or aren't accessible.
33
96
  def variable_values(varlist)
34
97
  raise ArgumentError, "Variables list must be an array" unless varlist.kind_of? Array
35
98
  raise ArgumentError, "Variables list is empty" if varlist.empty?
@@ -42,5 +105,6 @@ module Conjur
42
105
  end
43
106
  end
44
107
 
108
+ #@!endgroup
45
109
  end
46
110
  end
@@ -23,6 +23,9 @@ module Conjur
23
23
  module Audit
24
24
  class API < Conjur::API
25
25
  class << self
26
+ # The URL for the audit service
27
+ #
28
+ # @return [String] the audit service url.
26
29
  def host
27
30
  Conjur.configuration.audit_url
28
31
  end
@@ -22,6 +22,10 @@ module Conjur
22
22
  module Authn
23
23
  class API < Conjur::API
24
24
  class << self
25
+
26
+ # The URL for the audit service
27
+ #
28
+ # @return [String] the audit service url.
25
29
  def host
26
30
  Conjur.configuration.authn_url
27
31
  end
@@ -22,6 +22,10 @@ module Conjur
22
22
  module Authz
23
23
  class API < Conjur::API
24
24
  class << self
25
+
26
+ # The URL for the audit service
27
+ #
28
+ # @return [String] the audit service url.
25
29
  def host
26
30
  Conjur.configuration.authz_url
27
31
  end
data/lib/conjur/base.rb CHANGED
@@ -35,31 +35,7 @@ require 'conjur/cast'
35
35
  module Conjur
36
36
  # NOTE: You have to put all 'class level' api docs here, because YARD is stoopid :-(
37
37
 
38
- # This class provides access to Conjur services
39
- # **TODO MOAR**
40
- #
41
- # # Conjur Services
42
- #
43
- # ### Public Keys Service
44
- # The {http://developer.conjur.net/reference/services/pubkeys Conjur Public Keys} service provides a
45
- # simple database of public keys with access controlled by Conjur. Reading a user's public keys requires
46
- # no authentication at all -- the user's public keys are public information, after all.
47
- #
48
- # Adding or deleting a public key may only be done if you have permission to update the *public keys
49
- # resource*, which is created when the appliance is launched, and has a resource id
50
- # `'<organizational account>:service:pubkeys-1.0/public-keys'`. The appliance also comes with a Group named
51
- # `'pubkeys-1.0/key-managers'` that has this permission. Rather than granting each user permission to
52
- # modify the public keys database, you should consider adding users to this group.
53
- #
54
- # A very common use case is {http://developer.conjur.net/tutorials/ssh public key management for SSH}
55
- #
56
- #
57
- # ### Audit Service
58
- #
59
- # The {http://developer.conjur.net/reference/services/audit Conjur Audit Service} allows you to
60
- # fetch audit records.
61
- #
62
- # Generally you will need to have *at least one* privilege on the subject of an event in order to see it.
38
+ # This class provides access to the Conjur services.
63
39
  class API
64
40
  include Escape
65
41
  include LogSource
@@ -184,19 +160,37 @@ module Conjur
184
160
 
185
161
  raise "Expecting ( username and api_key ) or token" unless ( username && api_key ) || token
186
162
  end
187
-
163
+
164
+ #@!attribute [r] api_key
165
+ # The api key used to create this instance. This is only present when you created the api with {Conjur::API.new_from_key}.#
166
+ #
167
+ # @return [String] the api key, or nil if this instance was created from a token.
188
168
  attr_reader :api_key
189
169
 
170
+ # The name of the user as which this api instance is authenticated. This is available whether the api
171
+ # instance was created from credentials or an authentication token.
190
172
  #
173
+ # @return [String] the login of the current user.
191
174
  def username
192
175
  @username || @token['data']
193
176
  end
194
177
 
195
-
178
+ # @api private
179
+ # used to delegate to host providing subclasses.
180
+ # @return [String] the host
196
181
  def host
197
182
  self.class.host
198
183
  end
199
184
 
185
+ # The token used to authenticate requests made with the api. The token will be fetched
186
+ # if it hasn't already, or if it has expired. Accordingly, this method may raise a RestClient::Unauthorized
187
+ # exception if the credentials are invalid.
188
+ #
189
+ # @note calling this method on an {Conjur::API} instance created with {Conjur::API.new_from_token} will have
190
+ # undefined behavior if the token is expired.
191
+ #
192
+ # @return [Hash] the authentication token as a Hash
193
+ # @raise [RestClient::Unauthorized] if the username and api key are invalid.
200
194
  def token
201
195
  @token = nil unless token_valid?
202
196
 
@@ -206,15 +200,22 @@ module Conjur
206
200
 
207
201
  return @token
208
202
  end
209
-
210
- # Authenticate the username and api_key to obtain a request token.
211
- # Tokens are cached by username for a short period of time.
203
+
204
+ # Credentials that can be merged with options to be passed to `RestClient::Resource` HTTP request methods.
205
+ # These include a username and an Authorization header containing the authentication token.
206
+ #
207
+ # @return [Hash] the options.
208
+ # @raise [RestClient::Unauthorized] if fetching the token fails.
209
+ # @see {#token}
212
210
  def credentials
213
211
  { headers: { authorization: "Token token=\"#{Base64.strict_encode64 token.to_json}\"" }, username: username }
214
212
  end
215
213
 
216
214
  private
217
215
 
216
+ # Check to see if @token is defined, and whether it's expired
217
+ #
218
+ # @return [Boolean] whether or not the token is valid.
218
219
  def token_valid?
219
220
  return false unless @token
220
221