conjur-api 4.13.0 → 4.14.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/.yardopts +1 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +0 -1
- data/README.md +59 -18
- data/conjur-api.gemspec +2 -1
- data/lib/conjur/acts_as_asset.rb +6 -9
- data/lib/conjur/acts_as_role.rb +54 -7
- data/lib/conjur/annotations.rb +52 -14
- data/lib/conjur/api/audit.rb +54 -8
- data/lib/conjur/api/authn.rb +54 -9
- data/lib/conjur/api/groups.rb +67 -4
- data/lib/conjur/api/hosts.rb +62 -3
- data/lib/conjur/api/layers.rb +48 -3
- data/lib/conjur/api/pubkeys.rb +140 -9
- data/lib/conjur/api.rb +13 -1
- data/lib/conjur/base.rb +93 -6
- data/lib/conjur/configuration.rb +247 -20
- data/lib/conjur/exists.rb +26 -0
- data/lib/conjur/group.rb +50 -4
- data/lib/conjur/has_attributes.rb +66 -5
- data/lib/conjur/resource.rb +155 -13
- data/lib/conjur/role.rb +1 -1
- data/lib/conjur/standard_methods.rb +7 -2
- data/lib/conjur/variable.rb +168 -6
- data/lib/conjur-api/version.rb +1 -1
- data/lib/conjur-api.rb +2 -0
- data/spec/api/authn_spec.rb +6 -3
- data/spec/api/groups_spec.rb +1 -1
- data/spec/api/pubkeys_spec.rb +4 -4
- data/spec/api/roles_spec.rb +4 -2
- data/spec/api/users_spec.rb +2 -2
- data/spec/api/variables_spec.rb +1 -1
- data/spec/helpers/errors_matcher.rb +34 -0
- data/spec/helpers/request_helpers.rb +10 -0
- data/spec/lib/annotations_spec.rb +5 -2
- data/spec/lib/audit_spec.rb +5 -5
- data/spec/lib/group_spec.rb +1 -1
- data/spec/lib/resource_spec.rb +11 -11
- data/spec/lib/role_spec.rb +8 -7
- data/spec/lib/user_spec.rb +7 -3
- data/spec/ssl_spec.rb +85 -0
- data/spec/standard_methods_helper.rb +2 -0
- data/spec/variable_spec.rb +5 -3
- metadata +34 -7
- data/lib/conjur/patches/rest-client.rb +0 -32
data/lib/conjur/configuration.rb
CHANGED
@@ -21,8 +21,42 @@
|
|
21
21
|
module Conjur
|
22
22
|
|
23
23
|
class << self
|
24
|
-
#
|
25
|
-
|
24
|
+
# Saves the current thread local {Conjur::Configuration},
|
25
|
+
# sets the thread local {Conjur::Configuration} to `config`, yields to the block, and ensures that
|
26
|
+
# the original thread local configuration is restored.
|
27
|
+
#
|
28
|
+
# Because Conjur configuration is accessed from the 'global' {Conjur.configuration} method by all Conjur
|
29
|
+
# API methods, this method provides the ability to set a thread local value for use within the current,
|
30
|
+
# or within a block in a single threaded application.
|
31
|
+
#
|
32
|
+
# Note that the {Conjur.configuration=} method sets the *global* {Conjur::Configuration}, not the thread-local
|
33
|
+
# value.
|
34
|
+
#
|
35
|
+
# @example Override Configuration in a Thread
|
36
|
+
# # in this rather contrived example, we'll override the {Conjur::Configuration#appliance_url} parameter
|
37
|
+
# # used by calls within a thread.
|
38
|
+
#
|
39
|
+
# # Set up the configuration in the main thread
|
40
|
+
# Conjur.configure do |c|
|
41
|
+
# # ...
|
42
|
+
# c.appliance_url = 'https://conjur.main-url.com/api'
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # Start a new thread that will perform requests to another server. In practice, you might
|
46
|
+
# # have a web server that uses a Conjur endpoint specified by a request header.
|
47
|
+
# Thread.new do
|
48
|
+
# Conjur.with_configuration Conjur.config.clone(appliance_url: 'https://conjur.local-url.com/api') do
|
49
|
+
# sleep 2
|
50
|
+
# puts "Thread local url is #{Conjur.config.appliance_url}"
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
# puts "Global url is #{Conjur.config.appliance_url}"
|
54
|
+
# # Outputs:
|
55
|
+
# Global url is https://conjur.main-url.com/api
|
56
|
+
# Thread local url is https://conjur.local-url.com/api
|
57
|
+
#
|
58
|
+
# @return [void]
|
59
|
+
def with_configuration(config)
|
26
60
|
oldvalue = Thread.current[:conjur_configuration]
|
27
61
|
Thread.current[:conjur_configuration] = config
|
28
62
|
yield
|
@@ -31,26 +65,123 @@ module Conjur
|
|
31
65
|
end
|
32
66
|
|
33
67
|
# Gets the current thread-local or global configuration.
|
68
|
+
#
|
69
|
+
# The thread-local Conjur configuration can only be set using the {Conjur.with_configuration}
|
70
|
+
# method. This method will try to return that value first, then the global configuration as
|
71
|
+
# set with {Conjur.configuration=} (which is lazily initialized if not set).
|
72
|
+
#
|
73
|
+
# @return [Conjur::Configuration] the thread-local or global Conjur configuration.
|
34
74
|
def configuration
|
35
75
|
Thread.current[:conjur_configuration] || (@config ||= Configuration.new)
|
36
76
|
end
|
37
77
|
|
38
78
|
# Sets the global configuration.
|
79
|
+
#
|
80
|
+
# This method *has no effect* on the thread local configuration. Use {Conjur.with_configuration} instead if
|
81
|
+
# that's what you want.
|
82
|
+
#
|
83
|
+
# @param [Conjur::Configuration] config the new configuration
|
84
|
+
# @return [Conjur::Configuration] the new value of the configuration
|
39
85
|
def configuration=(config)
|
40
86
|
@config = config
|
41
87
|
end
|
88
|
+
|
89
|
+
alias config configuration
|
90
|
+
alias config= configuration=
|
91
|
+
|
92
|
+
# Configure Conjur with a block.
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# Conjur.configure do |c|
|
96
|
+
# c.account = 'some-account'
|
97
|
+
# c.appliance_url = 'https://conjur.companyname.com/api'
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# @yieldparam [Conjur::Configuration] c the configuration instance to modify.
|
101
|
+
def configure
|
102
|
+
yield configuration
|
103
|
+
end
|
42
104
|
end
|
43
|
-
|
105
|
+
|
106
|
+
# Stores a configuration for the Conjur API client. This class provides *global* and *thread local* storage
|
107
|
+
# for common options used by the Conjur API. Most importantly, it specifies the
|
108
|
+
#
|
109
|
+
# * REST endpoints, derived from the {Conjur::Configuration#appliance_url} and {Conjur::Configuration#account} options
|
110
|
+
# * The certificate used for secure connections to the Conjur appliance ({Conjur::Configuration#cert_file})
|
111
|
+
#
|
112
|
+
# ### Environment Variables
|
113
|
+
#
|
114
|
+
# Option values used by Conjur can be given by environment variables, using a standard naming scheme. Specifically,
|
115
|
+
# an environment variable named `CONJUR_ACCOUNT` will be used to provide a default value for the {Conjur::Configuration#account}
|
116
|
+
# option.
|
117
|
+
#
|
118
|
+
#
|
119
|
+
# ### Required Options
|
120
|
+
#
|
121
|
+
# The {Conjur::Configuration#account} and {Conjur::Configuration#appliance_url} are always required. Except in
|
122
|
+
# special cases, the {Conjur::Configuration#cert_file} is also required, but you may omit it if your Conjur root
|
123
|
+
# certificate is in the OpenSSl default certificate store.
|
124
|
+
#
|
125
|
+
# ### Thread Local Configuration
|
126
|
+
#
|
127
|
+
# While using a globally available configuration is convenient for most applications, sometimes you will need to
|
128
|
+
# use different configurations in different threads. This is supported by returning a thread local version from {Conjur.configuration}
|
129
|
+
# if one has been set by {Conjur.with_configuration}.
|
130
|
+
#
|
131
|
+
# @see Conjur.configuration
|
132
|
+
# @see Conjur.configure
|
133
|
+
# @see Conjur.with_configuration
|
134
|
+
#
|
135
|
+
# @example Basic Configuration
|
136
|
+
# Conjur.configure do |c|
|
137
|
+
# c.account = 'the-account'
|
138
|
+
# c.cert_file = find_conjur_cert_file
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
# @example Setting the appliance_url from an environment variable
|
142
|
+
# ENV['CONJUR_APPLIANCE_URL'] = 'https://some-host.com/api'
|
143
|
+
# Conjur::Configuration.new.appliance_url # => 'https://some-host.com/api'
|
144
|
+
#
|
145
|
+
# @example Using thread local configuration in a web application request handler
|
146
|
+
# # Assume that we're in a request handler thread in a multithreaded web server.
|
147
|
+
#
|
148
|
+
# requested_appliance_url = request.header 'X-Conjur-Appliance-Url'
|
149
|
+
#
|
150
|
+
# with_configuration Conjur.config.clone(appliance_url: requested_appliance_url) do
|
151
|
+
# # `api` is an instance attribute. Note that we can use an api that was created
|
152
|
+
# # before we modified the thread local configuration.
|
153
|
+
#
|
154
|
+
#
|
155
|
+
# # 404 if the user doesn't exist
|
156
|
+
#
|
157
|
+
# user = api.user request.header('X-Conjur-Login')
|
158
|
+
# raise HttpError, 404, "User #{user.login} does not exist" unless user.exists?
|
159
|
+
# # ... finish the request
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
#
|
44
163
|
class Configuration
|
45
|
-
#
|
164
|
+
# @api private
|
46
165
|
attr_reader :explicit
|
47
|
-
|
48
|
-
#
|
166
|
+
|
167
|
+
# @api private
|
49
168
|
attr_reader :supplied
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
169
|
+
|
170
|
+
|
171
|
+
# Create a new {Conjur::Configuration}, setting initial values from
|
172
|
+
# `options`.
|
173
|
+
#
|
174
|
+
# @note `options` must use symbols for keys.
|
175
|
+
#
|
176
|
+
# @example
|
177
|
+
# Conjur.config = Conjur::Configuration.new account: 'companyname'
|
178
|
+
# Conjur.config.account # => 'companyname'
|
179
|
+
#
|
180
|
+
# @param [Hash] options hash of options to set on the new instance.
|
181
|
+
#
|
182
|
+
def initialize options = {}
|
183
|
+
@explicit = options.dup
|
184
|
+
@supplied = options.dup
|
54
185
|
end
|
55
186
|
|
56
187
|
class << self
|
@@ -112,44 +243,129 @@ module Conjur
|
|
112
243
|
end
|
113
244
|
end
|
114
245
|
|
115
|
-
#
|
116
|
-
|
246
|
+
# Return a copy of this {Conjur::Configuration} instance, optionally
|
247
|
+
# updating the copy with options from the `override_options` hash.
|
248
|
+
#
|
249
|
+
# @example
|
250
|
+
# original = Conjur.configuration
|
251
|
+
# original.account # => 'conjur'
|
252
|
+
# copy = original.clone account: 'some-other-account'
|
253
|
+
# copy.account # => 'some-other-account'
|
254
|
+
# original.account # => 'conjur'
|
255
|
+
#
|
256
|
+
# @param [Hash] override_options options to set on the new instance
|
257
|
+
# @return [Conjur::Configuration] a copy of this configuration
|
258
|
+
def clone override_options = {}
|
117
259
|
self.class.new self.explicit.dup.merge(override_options)
|
118
260
|
end
|
119
261
|
|
262
|
+
# Manually set an option. Note that setting an option not present in
|
263
|
+
# {Conjur::Configuration.accepted_options} is a no op.
|
264
|
+
# @api private
|
265
|
+
# @param [Symbol, String] key the name of the option to set
|
266
|
+
# @param [Object] value the option value.
|
120
267
|
def set(key, value)
|
121
268
|
if self.class.accepted_options.include?(key.to_sym)
|
122
269
|
explicit[key.to_sym] = value
|
123
270
|
supplied[key.to_sym] = value
|
124
271
|
end
|
125
272
|
end
|
126
|
-
|
273
|
+
|
274
|
+
# @!attribute authn_url
|
275
|
+
# The url for the {http://developer.conjur.net/reference/services/authentication Conjur authentication service}.
|
276
|
+
#
|
277
|
+
# @note You should not generally set this value. Instead, Conjur will derive it from the
|
278
|
+
# {Conjur::Configuration#account} and {Conjur::Configuration#appliance_url}
|
279
|
+
# properties.
|
280
|
+
#
|
281
|
+
# @return [String] the authentication service url
|
127
282
|
add_option :authn_url do
|
128
283
|
account_service_url 'authn', 0
|
129
284
|
end
|
130
|
-
|
285
|
+
|
286
|
+
# @!attribute authz_url
|
287
|
+
# The url for the {http://developer.conjur.net/reference/services/authorization Conjur authorization service}.
|
288
|
+
#
|
289
|
+
# @note You should not generally set this value. Instead, Conjur will derive it from the
|
290
|
+
# {Conjur::Configuration#account} and {Conjur::Configuration#appliance_url}
|
291
|
+
# properties.
|
292
|
+
#
|
293
|
+
# @return [String] the authorization service url
|
131
294
|
add_option :authz_url do
|
132
295
|
global_service_url 'authz', 100
|
133
296
|
end
|
134
297
|
|
298
|
+
# @!attribute core_url
|
299
|
+
# The url for the {http://developer.conjur.net/reference/services/directory Conjur core/directory service}.
|
300
|
+
#
|
301
|
+
# @note You should not generally set this value. Instead, Conjur will derive it from the
|
302
|
+
# {Conjur::Configuration#account} and {Conjur::Configuration#appliance_url}
|
303
|
+
# properties.
|
304
|
+
#
|
305
|
+
# @return [String] the core/directory service url
|
135
306
|
add_option :core_url do
|
136
307
|
default_service_url 'core', 200
|
137
|
-
end
|
138
|
-
|
308
|
+
end
|
309
|
+
|
310
|
+
# @!attribute audit_url
|
311
|
+
# The url for the {http://developer.conjur.net/reference/services/audit Conjur audit service}.
|
312
|
+
#
|
313
|
+
# @note You should not generally set this value. Instead, Conjur will derive it from the
|
314
|
+
# {Conjur::Configuration#account} and {Conjur::Configuration#appliance_url}
|
315
|
+
# properties.
|
316
|
+
#
|
317
|
+
# @return [String] the audit service url
|
139
318
|
add_option :audit_url do
|
140
319
|
global_service_url 'audit', 300
|
141
320
|
end
|
142
|
-
|
321
|
+
|
322
|
+
# @!attribute appliance_url
|
323
|
+
# The url for your Conjur appliance.
|
324
|
+
#
|
325
|
+
# If your appliance's hostname is `'conjur.companyname.com'`, then your `appliance_url` will
|
326
|
+
# be `'https://conjur.companyname.com/api'`.
|
327
|
+
#
|
328
|
+
# @note If you are using an appliance (if you're not sure, you probably are), this option is *required*.
|
329
|
+
#
|
330
|
+
# @return [String] the appliance URL
|
143
331
|
add_option :appliance_url
|
144
|
-
|
332
|
+
|
333
|
+
# NOTE DO NOT DOCUMENT THIS AS AN ATTRIBUTE, IT IS PRIVATE AND YARD DOESN'T SUPPORT @api private ON ATTRIBUTES.
|
334
|
+
#
|
335
|
+
# The port used to derive ports for conjur services running locally. You will only use this if you are
|
336
|
+
# running the Conjur services locally, in which case you are probably a Conjur developer, and should ask
|
337
|
+
# someone in chat ;-)
|
338
|
+
#
|
145
339
|
add_option :service_base_port, default: 5000
|
146
340
|
|
341
|
+
# @!attribute account
|
342
|
+
# The organizational account used by Conjur.
|
343
|
+
#
|
344
|
+
# On Conjur appliances, this option will be set once when the appliance is first configured. You can get the
|
345
|
+
# value for the acccount option from your conjur administrator, or if you have installed
|
346
|
+
# the {http://developer.conjur.net/client_setup/cli.html Conjur command line tools} by running
|
347
|
+
# {http://developer.conjur.net/reference/services/authentication/whoami.html conjur authn whoami},
|
348
|
+
# or examining your {http://developer.conjur.net/client_setup/cli.html#Configure .conjurrc file}.
|
349
|
+
#
|
350
|
+
# @note this option is **required**, and attempting to make any api calls prior to setting it (either
|
351
|
+
# explicitly or with the `"CONJUR_ACCOUNT"` environment variable) will raise an exception.
|
352
|
+
#
|
353
|
+
# @return [String]
|
147
354
|
add_option :account, required: true
|
148
|
-
|
355
|
+
|
356
|
+
|
357
|
+
# @!attribute env
|
358
|
+
#
|
359
|
+
# The type of environment your program is running in (e.g., `development`, `production`, `test`).
|
360
|
+
#
|
361
|
+
# @deprecated
|
362
|
+
#
|
363
|
+
# @return [String] the environment name
|
149
364
|
add_option :env do
|
150
365
|
ENV['CONJUR_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "production"
|
151
366
|
end
|
152
|
-
|
367
|
+
|
368
|
+
# DEPRECATED SaaS option, do not doc comment!
|
153
369
|
add_option :stack do
|
154
370
|
case env
|
155
371
|
when "production"
|
@@ -159,6 +375,17 @@ module Conjur
|
|
159
375
|
end
|
160
376
|
end
|
161
377
|
|
378
|
+
# @!attribute cert_file
|
379
|
+
#
|
380
|
+
# Path to the certificate file to use when making secure connections to your Conjur appliance.
|
381
|
+
#
|
382
|
+
# This should be the path to the root Conjur SSL certificate in PEM format. You will normally get the
|
383
|
+
# certificate file using the {http://developer.conjur.net/reference/tools/utilities/init.html conjur init} command.
|
384
|
+
# This option is not required if the certificate or its root is in the OpenSSL default cert store.
|
385
|
+
# If your program throws an error indicating that SSL verification has failed, you probably need
|
386
|
+
# to set or fix this option.
|
387
|
+
#
|
388
|
+
# @return [String, nil] path to the certificate file, or nil if you aren't using one.
|
162
389
|
add_option :cert_file
|
163
390
|
|
164
391
|
private
|
data/lib/conjur/exists.rb
CHANGED
@@ -19,7 +19,33 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
+
# Provides an `exists?` method for things that may or may not exist.
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# Most conjur assets returned by `api.asset_name` methods (e.g., {Conjur::API#group}, {Conjur::API#user})
|
26
|
+
# may or may not exist. The {Conjur::Exists#exists?} method lets you determine whether or not such assets
|
27
|
+
# do in fact exist.
|
22
28
|
module Exists
|
29
|
+
|
30
|
+
# Check whether this asset exists by performing a HEAD request to its URL.
|
31
|
+
#
|
32
|
+
# This method will return false if the asset doesn't exist.
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# does_not_exist = api.user 'does-not-exist' # This returns without error.
|
36
|
+
#
|
37
|
+
# # this is wrong!
|
38
|
+
# owner = does_not_exist.ownerid # raises RestClient::ResourceNotFound
|
39
|
+
#
|
40
|
+
# # this is right!
|
41
|
+
# owner = if does_not_exist.exists?
|
42
|
+
# does_not_exist.ownerid
|
43
|
+
# else
|
44
|
+
# nil # or some sensible default
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @param [Hash] options included for compatibility: **don't use this argument**!
|
48
|
+
# @return [Boolean] does it exist?
|
23
49
|
def exists?(options = {})
|
24
50
|
begin
|
25
51
|
self.head(options)
|
data/lib/conjur/group.rb
CHANGED
@@ -18,21 +18,67 @@
|
|
18
18
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
19
|
#
|
20
20
|
module Conjur
|
21
|
+
|
22
|
+
# A Conjur {http://developer.conjur.net/reference/services/directory/group Group} represents a collection of
|
23
|
+
# Conjur {http://developer.conjur.net/reference/services/directory/user Users}.
|
24
|
+
# This class represents Conjur group assets and operations on them.
|
25
|
+
#
|
26
|
+
# You should not create instances of this class directly. Instead, you can get them from
|
27
|
+
# API methods like {Conjur::API#group} and {Conjur::API#groups}.
|
28
|
+
#
|
21
29
|
class Group < RestClient::Resource
|
22
30
|
include ActsAsAsset
|
23
31
|
include ActsAsRole
|
24
|
-
|
32
|
+
|
33
|
+
# Add a user to the group or change whether an existing member can manage other members.
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# # create an empty group
|
37
|
+
# group = api.create_group 'hoommans'
|
38
|
+
# # put a user in the group, with the ability to manage members
|
39
|
+
# group.add_member 'conjur:user:bob', admin_option: True
|
40
|
+
# # Hmm, bob is getting a little suspicious, better lower his privileges.
|
41
|
+
# group.add_member 'conjur:user:bob', admin_option: False
|
42
|
+
#
|
43
|
+
# # Notice that this method is idempotent:
|
44
|
+
# group.add_member 'alice'
|
45
|
+
# group.add_member 'alice' # Does nothing, alice is already a member
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# @param [String, Conjur::User, Conjur::Role] member the member to add. If a String is given, it must
|
49
|
+
# be a *fully qualified* Conjur id.
|
25
50
|
# @param [Hash] options
|
26
|
-
#
|
51
|
+
# @option options [Boolean] :admin_option (False) determines whether the member is able to manage members
|
52
|
+
# of this group.
|
53
|
+
# @return [void]
|
27
54
|
def add_member(member, options = {})
|
28
55
|
role.grant_to member, options
|
29
56
|
end
|
30
|
-
|
57
|
+
|
58
|
+
# Remove a member from this group.
|
59
|
+
#
|
60
|
+
# ### Notes
|
61
|
+
# * Unlike {#add_member}, this method is *not* idempotent.
|
62
|
+
# This means that calling it twice with the same user will raise a `RestClient::ResourceNotFound`
|
63
|
+
# exception.
|
64
|
+
# * The member may be represented as a *qualified* conjur id or a {Conjur::User} instance. Although
|
65
|
+
# it will accept anything that responds to `#roleid`, the behavior when adding or removing a non-user
|
66
|
+
# role is **undefined**.
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# group = api.group 'admins'
|
70
|
+
# group.add_member 'bob'
|
71
|
+
# group.remove_member 'bob' # OK, bob is a member
|
72
|
+
# group.remove_member 'bob' # raises RestClient::ResourceNotFound
|
73
|
+
#
|
74
|
+
# @param [String, Conjur::User,Conjur::Role] member
|
75
|
+
# @return [void]
|
76
|
+
# @raise [RestClient::ResourceNotFound] when you try to remove a user who is not a member of the group.
|
31
77
|
def remove_member(member)
|
32
78
|
role.revoke_from member
|
33
79
|
end
|
34
80
|
|
35
|
-
# Update group properties
|
81
|
+
# Update group properties. Currently the only supported property is `:gidnumber`.
|
36
82
|
#
|
37
83
|
# @param [Hash] props new property values
|
38
84
|
# @option props [Integer] :gidnumber new GID number
|
@@ -19,27 +19,87 @@
|
|
19
19
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
20
|
#
|
21
21
|
module Conjur
|
22
|
+
# Many Conjur assets have key-value attributes. Although these should generally be accessed via
|
23
|
+
# methods on specific asset classes (for example, {Conjur::Resource#owner}), the are available as
|
24
|
+
# a `Hash` on all types supporting attributes.
|
22
25
|
module HasAttributes
|
26
|
+
# Returns this objects {#attributes}. This is primarily to support
|
27
|
+
# simple JSON serialization of Conjur assets.
|
28
|
+
#
|
29
|
+
# @param options [Hash,nil] unused, kept for compatibility reasons
|
30
|
+
# @see #attributes
|
23
31
|
def to_json(options = {})
|
24
32
|
attributes
|
25
33
|
end
|
26
34
|
|
27
|
-
|
35
|
+
# @api private
|
36
|
+
# Set the attributes for this Resource.
|
37
|
+
# @param [Hash] attributes new attributes for the object.
|
38
|
+
# @return [Hash] the new attributes
|
39
|
+
def attributes=(attributes); @attributes = attributes; end
|
40
|
+
|
41
|
+
# Get the attributes for this asset.
|
42
|
+
#
|
43
|
+
# Although the `Hash` returned by this method is mutable, you should treat as immutable unless you know
|
44
|
+
# exactly what you're doing. Each asset's attributes are constrained by a server side schema, which means
|
45
|
+
# that you will get an error if you violate the schema. and then try to save the asset.
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# @note this method will use a cached copy of the objects attributes instead of fetching them
|
49
|
+
# with each call. To ensure that the attributes are fresh, you can use the {#refresh} method
|
50
|
+
#
|
51
|
+
# @return [Hash] the asset's attributes.
|
28
52
|
def attributes
|
29
53
|
return @attributes if @attributes
|
30
54
|
fetch
|
31
55
|
end
|
32
|
-
|
56
|
+
|
57
|
+
|
58
|
+
# Update this asset's attributes on the server.
|
59
|
+
#
|
60
|
+
#
|
61
|
+
# @note If the objects attributes haven't been fetched (for example, by calling {#attributes}),
|
62
|
+
# this method is a no-op.
|
63
|
+
#
|
64
|
+
# Although you can manipulate an assets attributes and then call {#save}, the attributes are constrained
|
65
|
+
# by a server side schema, and attempting to set an attribute that doesn't exist will result in
|
66
|
+
# a 422 Unprocessable Entity error.
|
67
|
+
#
|
68
|
+
# If you want to set arbitrary metadata on an asset, you might consider using the {Conjur::Resource#tags}
|
69
|
+
# method instead.
|
70
|
+
#
|
71
|
+
# @return [void]
|
33
72
|
def save
|
34
|
-
|
73
|
+
if @attributes
|
74
|
+
self.put(attributes.to_json)
|
75
|
+
end
|
35
76
|
end
|
36
77
|
|
37
|
-
# Reload
|
78
|
+
# Reload this asset's attributes. This method can be used to guarantee a current view of the entity in the case
|
38
79
|
# that it has been modified by an update method or by an external party.
|
80
|
+
#
|
81
|
+
# @note any changes to {#attributes} without a call to #save will be overwritten by this method.
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
# res = api.resources.firs
|
85
|
+
# res.attributes # => { ... }
|
86
|
+
# res.attributes['hello'] = 'blah'
|
87
|
+
# res.refresh
|
88
|
+
# res.attributes['hello'] # => nil
|
89
|
+
#
|
90
|
+
#
|
91
|
+
# @return [Hash] the asset's attributes.
|
39
92
|
def refresh
|
40
93
|
fetch
|
41
94
|
end
|
42
95
|
|
96
|
+
# Call a block that will perform actions that might change the asset's attributes.
|
97
|
+
# No matter what happens in the block, this method ensures that the cached attributes
|
98
|
+
# will be invalidated.
|
99
|
+
#
|
100
|
+
# @note this is mainly used internally, but included in the public api for completeness.
|
101
|
+
#
|
102
|
+
# @return [void]
|
43
103
|
def invalidate(&block)
|
44
104
|
yield
|
45
105
|
ensure
|
@@ -47,7 +107,8 @@ module Conjur
|
|
47
107
|
end
|
48
108
|
|
49
109
|
protected
|
50
|
-
|
110
|
+
# @api private
|
111
|
+
# Fetch the attributes, overwriting any current ones.
|
51
112
|
def fetch
|
52
113
|
@attributes = JSON.parse(get.body)
|
53
114
|
end
|