conjur-api 5.3.0 → 5.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +10 -0
  3. data/.github/CODEOWNERS +10 -0
  4. data/.github/ISSUE_TEMPLATE/bug.md +42 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
  6. data/.github/PULL_REQUEST_TEMPLATE.md +21 -0
  7. data/.gitignore +1 -0
  8. data/.gitleaks.toml +219 -0
  9. data/.overcommit.yml +16 -0
  10. data/.rubocop.yml +3 -0
  11. data/.rubocop_settings.yml +86 -0
  12. data/.rubocop_todo.yml +709 -0
  13. data/CHANGELOG.md +373 -181
  14. data/CONTRIBUTING.md +141 -0
  15. data/Gemfile +1 -1
  16. data/Jenkinsfile +27 -29
  17. data/LICENSE +202 -0
  18. data/README.md +34 -117
  19. data/SECURITY.md +42 -0
  20. data/bin/parse-changelog.sh +12 -0
  21. data/ci/codeclimate.dockerfile +6 -0
  22. data/conjur-api.gemspec +4 -1
  23. data/docker-compose.yml +2 -0
  24. data/features/authenticators.feature +33 -0
  25. data/features/host.feature +39 -9
  26. data/features/step_definitions/api_steps.rb +14 -3
  27. data/features/step_definitions/policy_steps.rb +40 -0
  28. data/features/support/env.rb +2 -0
  29. data/features/update_password.feature +2 -2
  30. data/features/user.feature +47 -6
  31. data/features_v4/support/env.rb +2 -0
  32. data/lib/conjur-api/version.rb +2 -2
  33. data/lib/conjur/acts_as_role.rb +15 -19
  34. data/lib/conjur/acts_as_user.rb +5 -1
  35. data/lib/conjur/api.rb +1 -18
  36. data/lib/conjur/api/authenticators.rb +35 -0
  37. data/lib/conjur/api/authn.rb +3 -3
  38. data/lib/conjur/api/host_factories.rb +20 -19
  39. data/lib/conjur/api/resources.rb +17 -21
  40. data/lib/conjur/api/router/v4.rb +80 -23
  41. data/lib/conjur/api/router/v5.rb +117 -23
  42. data/lib/conjur/base.rb +19 -5
  43. data/lib/conjur/base_object.rb +31 -26
  44. data/lib/conjur/build_object.rb +13 -20
  45. data/lib/conjur/cert_utils.rb +14 -0
  46. data/lib/conjur/configuration.rb +46 -24
  47. data/lib/conjur/id.rb +22 -19
  48. data/lib/conjur/role_grant.rb +13 -18
  49. data/spec/api/host_factories_spec.rb +34 -0
  50. data/spec/api_spec.rb +55 -6
  51. data/spec/base_object_spec.rb +13 -0
  52. data/spec/cert_utils_spec.rb +92 -0
  53. data/spec/configuration_spec.rb +25 -3
  54. data/spec/id_spec.rb +29 -0
  55. data/spec/spec_helper.rb +4 -1
  56. data/spec/ssl_spec.rb +50 -26
  57. data/spec/uri_escape_spec.rb +14 -2
  58. data/test.sh +23 -1
  59. metadata +31 -14
  60. data/LICENSE.md +0 -195
  61. data/lib/conjur/cast.rb +0 -41
  62. data/spec/cast_spec.rb +0 -21
  63. data/spec/vendor/rest_client_spec.rb +0 -41
data/lib/conjur/base.rb CHANGED
@@ -123,19 +123,21 @@ module Conjur
123
123
  #
124
124
  # @return [String] the api key, or nil if this instance was created from a token.
125
125
  attr_reader :api_key
126
-
126
+
127
127
  #@!attribute [r] remote_ip
128
128
  # An optional IP address to be recorded in the audit record for any actions performed by this API instance.
129
129
  attr_reader :remote_ip
130
130
 
131
131
  # The name of the user as which this api instance is authenticated. This is available whether the api
132
- # instance was created from credentials or an authentication token.
132
+ # instance was created from credentials or an authentication token. If the instance was created from
133
+ # credentials, we will use that value directly otherwise we will attempt to extract the username from
134
+ # the token (either the old-style data field or the new-style JWT `sub` field).
133
135
  #
134
136
  # @return [String] the login of the current user.
135
137
  def username
136
- @username || token['data']
138
+ @username || token['data'] || jwt_username(token)
137
139
  end
138
-
140
+
139
141
  # @api private
140
142
  # used to delegate to host providing subclasses.
141
143
  # @return [String] the host
@@ -213,7 +215,7 @@ module Conjur
213
215
  @account = account
214
216
  @username = username
215
217
  @api_key = api_key
216
-
218
+
217
219
  update_token_born
218
220
  end
219
221
 
@@ -323,6 +325,18 @@ module Conjur
323
325
 
324
326
  private
325
327
 
328
+ # Tries to get the username (subject) from a JWT API token by examining
329
+ # its content.
330
+ #
331
+ # @return [String] of the 'sub' payload field from the JWT if present,
332
+ # otherwise return nil
333
+ def jwt_username raw_token
334
+ return nil unless raw_token
335
+ return nil unless raw_token.include? 'payload'
336
+
337
+ JSON.parse(Base64.strict_decode64(raw_token["payload"]))["sub"]
338
+ end
339
+
326
340
  # Tries to refresh the token if possible.
327
341
  #
328
342
  # @return [Hash, false] false if the token couldn't be refreshed due to
@@ -1,37 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2013-2018 CyberArk Ltd.
1
4
  #
2
- # Copyright 2013-2017 Conjur Inc
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
- # this software and associated documentation files (the "Software"), to deal in
6
- # the Software without restriction, including without limitation the rights to
7
- # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
- # the Software, and to permit persons to whom the Software is furnished to do so,
9
- # subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in all
12
- # copies or substantial portions of the Software.
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
13
8
  #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
- # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
- # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
- # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
- # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ # http://www.apache.org/licenses/LICENSE-2.0
20
10
  #
21
- require 'conjur/cast'
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
22
16
 
23
17
  module Conjur
24
18
  class BaseObject
25
- include Cast
26
19
  include QueryString
27
20
  include LogSource
28
21
  include BuildObject
29
22
  include Routing
30
-
23
+
31
24
  attr_reader :id, :credentials
32
-
25
+
33
26
  def initialize id, credentials
34
- @id = cast_to_id(id)
27
+ @id = Id.new id
35
28
  @credentials = credentials
36
29
  end
37
30
 
@@ -41,12 +34,24 @@ module Conjur
41
34
  }
42
35
  end
43
36
 
44
- def account; id.account; end
45
- def kind; id.kind; end
46
- def identifier; id.identifier; end
47
-
37
+ def account
38
+ id.account
39
+ end
40
+
41
+ def kind
42
+ id.kind
43
+ end
44
+
45
+ def identifier
46
+ id.identifier
47
+ end
48
+
48
49
  def username
49
50
  credentials[:username] or raise "No username found in credentials"
50
51
  end
52
+
53
+ def inspect
54
+ "<#{self.class.name} id='#{id.to_s}'>"
55
+ end
51
56
  end
52
57
  end
@@ -1,37 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2013-2018 CyberArk Ltd.
1
4
  #
2
- # Copyright 2013-2017 Conjur Inc
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
- # this software and associated documentation files (the "Software"), to deal in
6
- # the Software without restriction, including without limitation the rights to
7
- # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
- # the Software, and to permit persons to whom the Software is furnished to do so,
9
- # subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in all
12
- # copies or substantial portions of the Software.
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
13
8
  #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
- # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
- # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
- # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
- # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ # http://www.apache.org/licenses/LICENSE-2.0
20
10
  #
21
- require 'conjur/cast'
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
22
16
 
23
17
  module Conjur
24
18
  module BuildObject
25
19
  def self.included base
26
20
  base.module_eval do
27
- extend Cast
28
21
  extend ClassMethods
29
22
  end
30
23
  end
31
24
 
32
25
  module ClassMethods
33
26
  def build_object id, credentials, default_class:
34
- id = cast_to_id(id)
27
+ id = Id.new id
35
28
  class_name = id.kind.classify.to_sym
36
29
  find_class(class_name, default_class)
37
30
  .new(id, credentials)
@@ -44,6 +44,20 @@ module Conjur
44
44
  end
45
45
  end
46
46
  end
47
+
48
+ # Add a certificate to a given store. If the certificate has more than
49
+ # one certificate in its chain, it will be parsed and added to the store
50
+ # one by one. This is done because `OpenSSL::X509::Store.new.add_cert`
51
+ # adds only the intermediate certificate to the store.
52
+ def add_chained_cert store, chained_cert
53
+ parse_certs(chained_cert).each do |cert|
54
+ begin
55
+ store.add_cert cert
56
+ rescue OpenSSL::X509::StoreError => ex
57
+ raise unless ex.message == 'cert already in hash table'
58
+ end
59
+ end
60
+ end
47
61
  end
48
62
  end
49
63
  end
@@ -24,7 +24,6 @@ require 'set'
24
24
  require 'conjur/cert_utils'
25
25
 
26
26
  module Conjur
27
-
28
27
  class << self
29
28
  # Saves the current thread local {Conjur::Configuration},
30
29
  # sets the thread local {Conjur::Configuration} to `config`, yields to the block, and ensures that
@@ -68,7 +67,7 @@ module Conjur
68
67
  ensure
69
68
  Thread.current[:conjur_configuration] = oldvalue
70
69
  end
71
-
70
+
72
71
  # Gets the current thread-local or global configuration.
73
72
  #
74
73
  # The thread-local Conjur configuration can only be set using the {Conjur.with_configuration}
@@ -79,7 +78,7 @@ module Conjur
79
78
  def configuration
80
79
  Thread.current[:conjur_configuration] || (@config ||= Configuration.new)
81
80
  end
82
-
81
+
83
82
  # Sets the global configuration.
84
83
  #
85
84
  # This method *has no effect* on the thread local configuration. Use {Conjur.with_configuration} instead if
@@ -191,25 +190,25 @@ module Conjur
191
190
  @supplied = options.dup
192
191
  @computed = Hash.new
193
192
  end
194
-
193
+
195
194
  class << self
196
195
  # @api private
197
196
  def accepted_options
198
197
  require 'set'
199
198
  @options ||= Set.new
200
199
  end
201
-
200
+
202
201
  # @param [Symbol] name
203
202
  # @param [Hash] options
204
- # @option options [Boolean] :boolean (false) whether this option should have a '?' accessor
203
+ # @option options [Boolean] :boolean (false) whether this option should have a '?' accessor
205
204
  # @option options [Boolean, String] :env Environment variable for this option. Set to false
206
205
  # to disallow environment based configuration. Default is CONJUR_<OPTION_NAME>.
207
206
  # @option options [Proc, *] :default Default value or proc to provide it
208
207
  # @option options [Boolean] :required (false) when true, raise an exception if the option is
209
208
  # not set
210
- # @option options [Proc, #to_proc] :convert proc-ish to convert environment
209
+ # @option options [Proc, #to_proc] :convert proc-ish to convert environment
211
210
  # values to appropriate types
212
- # @param [Proc] def_proc block to provide default values
211
+ # @param [Proc] def_proc block to provide default values
213
212
  # @api private
214
213
  def add_option name, options = {}, &def_proc
215
214
  accepted_options << name
@@ -217,7 +216,7 @@ module Conjur
217
216
  env_var = options[:env] || "CONJUR_#{name.to_s.upcase}"
218
217
  def_val = options[:default]
219
218
  opt_name = name
220
-
219
+
221
220
  def_proc ||= if def_val.respond_to?(:call)
222
221
  def_val
223
222
  elsif options[:required]
@@ -225,10 +224,10 @@ module Conjur
225
224
  else
226
225
  proc { def_val }
227
226
  end
228
-
227
+
229
228
  convert = options[:convert] || ->(x){ x }
230
229
  # Allow a Symbol, for example
231
- convert = convert.to_proc if convert.respond_to?(:to_proc)
230
+ convert = convert.to_proc if convert.respond_to?(:to_proc)
232
231
 
233
232
  define_method("#{name}=") do |value|
234
233
  set name, value
@@ -237,7 +236,7 @@ module Conjur
237
236
  define_method("#{name}_env_var") do
238
237
  allow_env ? env_var : nil
239
238
  end
240
-
239
+
241
240
  define_method(name) do
242
241
  value = computed[name]
243
242
  return value unless value.nil?
@@ -246,7 +245,7 @@ module Conjur
246
245
  supplied[name]
247
246
  elsif allow_env && ENV.member?(env_var)
248
247
  instance_exec(ENV[env_var], &convert)
249
- else
248
+ else
250
249
  instance_eval(&def_proc)
251
250
  end.tap do |value|
252
251
  computed[name] = value
@@ -256,7 +255,7 @@ module Conjur
256
255
  alias_method("#{name}?", name) if options[:boolean]
257
256
  end
258
257
  end
259
-
258
+
260
259
  # Return a copy of this {Conjur::Configuration} instance, optionally
261
260
  # updating the copy with options from the `override_options` hash.
262
261
  #
@@ -290,8 +289,8 @@ module Conjur
290
289
  #
291
290
  # The url for the {http://developer.conjur.net/reference/services/authentication Conjur authentication service}.
292
291
  #
293
- # By default, this will be built from the +appliance_url+. To use a custom authenticator,
294
- # set this option in code or set `CONJUR_AUTHN_URL`.
292
+ # By default, this will be built from the +appliance_url+. To use a custom authenticator,
293
+ # set this option in code or set `CONJUR_AUTHN_URL`.
295
294
  #
296
295
  #
297
296
  # @return [String] the authentication service url
@@ -369,10 +368,30 @@ module Conjur
369
368
  # @see cert_file
370
369
  add_option :ssl_certificate
371
370
 
371
+ # @!attribute rest_client_options
372
+ #
373
+ # Custom options for the underlying RestClient Requests. This defaults to:
374
+ # ```
375
+ # {
376
+ # ssl_cert_store: OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
377
+ # }
378
+ # ``
379
+ #
380
+ # The `ssl_cert_store` value aligns with the default certificate store used by
381
+ # {#apply_cert_config!}.
382
+ #
383
+ # NOTE: When setting the value of rest_client_options the defaults are not retained,
384
+ # you must manually set them on the value you provide.
385
+ add_option :rest_client_options do
386
+ {
387
+ ssl_cert_store: OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
388
+ }
389
+ end
390
+
372
391
  # @!attribute version
373
392
  #
374
393
  # Selects the major API version of the Conjur server. With this setting, the API
375
- # will use the routing scheme for API version `4` or `5`.
394
+ # will use the routing scheme for API version `4` or `5`.
376
395
  #
377
396
  # Methods which are not available in the selected version will raise NoMethodError.
378
397
  add_option :version, default: 5
@@ -383,6 +402,12 @@ module Conjur
383
402
  # This is only available when the API client is running on the Conjur server.
384
403
  add_option :authn_local_socket, default: "/run/authn-local/.socket"
385
404
 
405
+ # Create rest_client_options by merging the input with the
406
+ # rest_client_options present on the configuration object.
407
+ def create_rest_client_options options
408
+ rest_client_options.merge(options || {})
409
+ end
410
+
386
411
  # Calls a major-version-specific function.
387
412
  def version_logic v4_logic, v5_logic
388
413
  case version.to_s
@@ -398,17 +423,14 @@ module Conjur
398
423
  # Add the certificate configured by the {#ssl_certificate} and {#cert_file} options to the certificate
399
424
  # store used by Conjur clients.
400
425
  #
426
+ # NOTE: If you specify a non-default `store` value, you must manually set the
427
+ # `ssl_cert_store` value on {#rest_client_options} to the same value.
428
+ #
401
429
  # @param [OpenSSL::X509::Store] store the certificate store that the certificate will be installed in.
402
430
  # @return [Boolean] whether a certificate was added to the store.
403
431
  def apply_cert_config! store=OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
404
432
  if ssl_certificate
405
- CertUtils.parse_certs(ssl_certificate).each do |cert|
406
- begin
407
- store.add_cert cert
408
- rescue OpenSSL::X509::StoreError => ex
409
- raise unless ex.message == 'cert already in hash table'
410
- end
411
- end
433
+ CertUtils.add_chained_cert(store, ssl_certificate)
412
434
  elsif cert_file
413
435
  ensure_cert_readable!(cert_file)
414
436
  store.add_file cert_file
data/lib/conjur/id.rb CHANGED
@@ -1,23 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2013-2018 CyberArk Ltd.
1
4
  #
2
- # Copyright 2013-2017 Conjur Inc
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
- # this software and associated documentation files (the "Software"), to deal in
6
- # the Software without restriction, including without limitation the rights to
7
- # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
- # the Software, and to permit persons to whom the Software is furnished to do so,
9
- # subject to the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in all
12
- # copies or substantial portions of the Software.
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
13
8
  #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
- # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
- # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
- # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
- # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ # http://www.apache.org/licenses/LICENSE-2.0
20
10
  #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
21
17
  require 'conjur/escape'
22
18
 
23
19
  module Conjur
@@ -28,7 +24,7 @@ module Conjur
28
24
  attr_reader :id
29
25
 
30
26
  def initialize id
31
- @id = id
27
+ @id = Id.normalize id
32
28
  end
33
29
 
34
30
  # The organization account, obtained from the first component of the id.
@@ -56,7 +52,7 @@ module Conjur
56
52
  # Splits the id into 3 components, and then joins them with a forward-slash `/`.
57
53
  def to_url_path
58
54
  id.split(':', 3)
59
- .map(&method(:path_escape))
55
+ .map(&method(:fully_escape))
60
56
  .join('/')
61
57
  end
62
58
 
@@ -64,5 +60,12 @@ module Conjur
64
60
  def to_s
65
61
  id
66
62
  end
63
+
64
+ def self.normalize id
65
+ Array(id).join(':').tap do |id|
66
+ raise ArgumentError, "id must be fully qualified: #{id}" \
67
+ unless id =~ /.*:.*:.*/
68
+ end
69
+ end
67
70
  end
68
71
  end