hammer_cli 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/bin/hammer +1 -1
  3. data/config/cli_config.template.yml +4 -1
  4. data/doc/release_notes.md +5 -0
  5. data/lib/hammer_cli/abstract.rb +9 -4
  6. data/lib/hammer_cli/apipie/api_connection.rb +1 -1
  7. data/lib/hammer_cli/ca_cert_fetcher.rb +15 -4
  8. data/lib/hammer_cli/ca_cert_manager.rb +18 -33
  9. data/lib/hammer_cli/exceptions.rb +1 -0
  10. data/lib/hammer_cli/exit_codes.rb +2 -1
  11. data/lib/hammer_cli/ssloptions.rb +19 -10
  12. data/lib/hammer_cli/version.rb +1 -1
  13. data/lib/hammer_cli.rb +1 -0
  14. data/man/hammer.1.gz +0 -0
  15. data/test/unit/apipie/api_connection_test.rb +0 -1
  16. data/test/unit/ca_cert_manager_test.rb +23 -33
  17. data/test/unit/fixtures/certs/non_ca_cert.pem +27 -0
  18. metadata +50 -322
  19. data/test/reports/TEST-Fields-ContainerField-display-.xml +0 -7
  20. data/test/reports/TEST-Fields-ContainerField-display-blank-is-allowed.xml +0 -15
  21. data/test/reports/TEST-Fields-ContainerField-display-blank-is-not-allowed.xml +0 -15
  22. data/test/reports/TEST-Fields-ContainerField.xml +0 -7
  23. data/test/reports/TEST-Fields-Field-display-.xml +0 -7
  24. data/test/reports/TEST-Fields-Field-display-blank-is-allowed.xml +0 -11
  25. data/test/reports/TEST-Fields-Field-display-blank-is-not-allowed.xml +0 -11
  26. data/test/reports/TEST-Fields-Field-hide-blank-.xml +0 -11
  27. data/test/reports/TEST-Fields-Field-parameters.xml +0 -9
  28. data/test/reports/TEST-Fields-Field.xml +0 -13
  29. data/test/reports/TEST-HammerCLI-AbstractCommand-build-options.xml +0 -15
  30. data/test/reports/TEST-HammerCLI-AbstractCommand-exception-handler.xml +0 -13
  31. data/test/reports/TEST-HammerCLI-AbstractCommand-logging.xml +0 -21
  32. data/test/reports/TEST-HammerCLI-AbstractCommand-option-builder.xml +0 -11
  33. data/test/reports/TEST-HammerCLI-AbstractCommand-options.xml +0 -11
  34. data/test/reports/TEST-HammerCLI-AbstractCommand-output.xml +0 -19
  35. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-remove-subcommand.xml +0 -11
  36. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-subcommand-.xml +0 -13
  37. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-subcommand.xml +0 -11
  38. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior.xml +0 -7
  39. data/test/reports/TEST-HammerCLI-AbstractCommand.xml +0 -11
  40. data/test/reports/TEST-HammerCLI-Apipie-Command-options.xml +0 -11
  41. data/test/reports/TEST-HammerCLI-Apipie-Command-resource-defined.xml +0 -9
  42. data/test/reports/TEST-HammerCLI-Apipie-Command-setting-resources.xml +0 -19
  43. data/test/reports/TEST-HammerCLI-Apipie-Command.xml +0 -9
  44. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-aliasing-resources.xml +0 -13
  45. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-filtering-options.xml +0 -15
  46. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-required-options.xml +0 -11
  47. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-setting-correct-normalizers.xml +0 -9
  48. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-with-hash-params.xml +0 -11
  49. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-with-one-simple-param.xml +0 -15
  50. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder.xml +0 -7
  51. data/test/reports/TEST-HammerCLI-Completer-command-completion.xml +0 -29
  52. data/test/reports/TEST-HammerCLI-Completer-option-value-completion.xml +0 -17
  53. data/test/reports/TEST-HammerCLI-Completer-subcommand-completion.xml +0 -19
  54. data/test/reports/TEST-HammerCLI-Completer.xml +0 -7
  55. data/test/reports/TEST-HammerCLI-CompleterLine-line-complete.xml +0 -25
  56. data/test/reports/TEST-HammerCLI-CompleterLine-splitting-words.xml +0 -29
  57. data/test/reports/TEST-HammerCLI-CompleterLine.xml +0 -7
  58. data/test/reports/TEST-HammerCLI-CompleterWord-complete-.xml +0 -23
  59. data/test/reports/TEST-HammerCLI-CompleterWord-quote.xml +0 -15
  60. data/test/reports/TEST-HammerCLI-CompleterWord-quoted-.xml +0 -13
  61. data/test/reports/TEST-HammerCLI-CompleterWord.xml +0 -7
  62. data/test/reports/TEST-HammerCLI-Connection.xml +0 -21
  63. data/test/reports/TEST-HammerCLI-ExceptionHandler.xml +0 -21
  64. data/test/reports/TEST-HammerCLI-I18n.xml +0 -11
  65. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-password.xml +0 -11
  66. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-username.xml +0 -11
  67. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-verbose.xml +0 -9
  68. data/test/reports/TEST-HammerCLI-MainCommand-loading-context.xml +0 -7
  69. data/test/reports/TEST-HammerCLI-MainCommand.xml +0 -7
  70. data/test/reports/TEST-HammerCLI-Modules-find-by-name.xml +0 -13
  71. data/test/reports/TEST-HammerCLI-Modules-load-a-module-module-not-found.xml +0 -13
  72. data/test/reports/TEST-HammerCLI-Modules-load-a-module-module-runtime-exception.xml +0 -13
  73. data/test/reports/TEST-HammerCLI-Modules-load-a-module-success.xml +0 -15
  74. data/test/reports/TEST-HammerCLI-Modules-load-a-module.xml +0 -7
  75. data/test/reports/TEST-HammerCLI-Modules-load-all-modules.xml +0 -9
  76. data/test/reports/TEST-HammerCLI-Modules-names.xml +0 -13
  77. data/test/reports/TEST-HammerCLI-Modules.xml +0 -7
  78. data/test/reports/TEST-HammerCLI-OptionBuilderContainer.0.xml +0 -7
  79. data/test/reports/TEST-HammerCLI-OptionBuilderContainer.xml +0 -11
  80. data/test/reports/TEST-HammerCLI-Options-Normalizers-abstract.xml +0 -9
  81. data/test/reports/TEST-HammerCLI-Options-Normalizers-bool.xml +0 -31
  82. data/test/reports/TEST-HammerCLI-Options-Normalizers-datetime.xml +0 -17
  83. data/test/reports/TEST-HammerCLI-Options-Normalizers-enum.xml +0 -15
  84. data/test/reports/TEST-HammerCLI-Options-Normalizers-enumlist.xml +0 -21
  85. data/test/reports/TEST-HammerCLI-Options-Normalizers-json-input.xml +0 -15
  86. data/test/reports/TEST-HammerCLI-Options-Normalizers-key-value-list.xml +0 -17
  87. data/test/reports/TEST-HammerCLI-Options-Normalizers-list.xml +0 -15
  88. data/test/reports/TEST-HammerCLI-Options-Normalizers.xml +0 -7
  89. data/test/reports/TEST-HammerCLI-Options-OptionDefinition-context.xml +0 -9
  90. data/test/reports/TEST-HammerCLI-Options-OptionDefinition-formatters.xml +0 -11
  91. data/test/reports/TEST-HammerCLI-Options-OptionDefinition.xml +0 -7
  92. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-error-messages.xml +0 -15
  93. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-messages.xml +0 -11
  94. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-test-data-for-field.xml +0 -15
  95. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract.xml +0 -17
  96. data/test/reports/TEST-HammerCLI-Output-Adapter-Base-print-collection-show-ids.xml +0 -9
  97. data/test/reports/TEST-HammerCLI-Output-Adapter-Base-print-collection.xml +0 -27
  98. data/test/reports/TEST-HammerCLI-Output-Adapter-Base.xml +0 -7
  99. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-formatters.xml +0 -11
  100. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-fields-with-collections.xml +0 -13
  101. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-fields-with-containers.xml +0 -11
  102. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-ids.xml +0 -11
  103. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection.xml +0 -11
  104. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-message.xml +0 -11
  105. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues.xml +0 -7
  106. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-column-width.xml +0 -15
  107. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-formatters.xml +0 -11
  108. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-handle-ids.xml +0 -11
  109. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-sort-columns.xml +0 -9
  110. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection.xml +0 -11
  111. data/test/reports/TEST-HammerCLI-Output-Adapter-Table.xml +0 -7
  112. data/test/reports/TEST-HammerCLI-Output-Definition-empty-.xml +0 -11
  113. data/test/reports/TEST-HammerCLI-Output-Definition.xml +0 -11
  114. data/test/reports/TEST-HammerCLI-Output-Dsl-collection.xml +0 -13
  115. data/test/reports/TEST-HammerCLI-Output-Dsl-custom-fields.xml +0 -11
  116. data/test/reports/TEST-HammerCLI-Output-Dsl-fields.xml +0 -15
  117. data/test/reports/TEST-HammerCLI-Output-Dsl-label.xml +0 -13
  118. data/test/reports/TEST-HammerCLI-Output-Dsl-path-definition.xml +0 -13
  119. data/test/reports/TEST-HammerCLI-Output-Dsl.xml +0 -9
  120. data/test/reports/TEST-HammerCLI-Output-FieldFilter.xml +0 -13
  121. data/test/reports/TEST-HammerCLI-Output-Formatters-BooleanFormatter.xml +0 -11
  122. data/test/reports/TEST-HammerCLI-Output-Formatters-ColorFormatter.xml +0 -9
  123. data/test/reports/TEST-HammerCLI-Output-Formatters-DateFormatter.xml +0 -11
  124. data/test/reports/TEST-HammerCLI-Output-Formatters-FieldFormatter.xml +0 -13
  125. data/test/reports/TEST-HammerCLI-Output-Formatters-FormatterContainer.xml +0 -13
  126. data/test/reports/TEST-HammerCLI-Output-Formatters-FormatterLibrary.xml +0 -11
  127. data/test/reports/TEST-HammerCLI-Output-Formatters-KeyValueFormatter.xml +0 -13
  128. data/test/reports/TEST-HammerCLI-Output-Formatters-ListFormatter.xml +0 -13
  129. data/test/reports/TEST-HammerCLI-Output-Formatters-LongTextFormatter.xml +0 -13
  130. data/test/reports/TEST-HammerCLI-Output-Output-adapters.xml +0 -17
  131. data/test/reports/TEST-HammerCLI-Output-Output-data.xml +0 -15
  132. data/test/reports/TEST-HammerCLI-Output-Output-formatters.xml +0 -9
  133. data/test/reports/TEST-HammerCLI-Output-Output-messages.xml +0 -19
  134. data/test/reports/TEST-HammerCLI-Output-Output.xml +0 -7
  135. data/test/reports/TEST-HammerCLI-Output-RecordCollection.xml +0 -13
  136. data/test/reports/TEST-HammerCLI-Settings-load-from-paths.xml +0 -15
  137. data/test/reports/TEST-HammerCLI-Settings.xml +0 -25
  138. data/test/reports/TEST-HammerCLI-ShellHistory-loading-old-history.xml +0 -11
  139. data/test/reports/TEST-HammerCLI-ShellHistory-saving-history.xml +0 -15
  140. data/test/reports/TEST-HammerCLI-ShellHistory.xml +0 -7
  141. data/test/reports/TEST-MiniTest-Spec.xml +0 -7
  142. data/test/reports/TEST-String-camelize.xml +0 -11
  143. data/test/reports/TEST-String-formatting.xml +0 -17
  144. data/test/reports/TEST-String-indent.xml +0 -11
  145. data/test/reports/TEST-String-interactive-.xml +0 -13
  146. data/test/reports/TEST-String.xml +0 -7
  147. data/test/reports/TEST-constraints-HammerCLI-Validator-AllConstraint-exist-.xml +0 -13
  148. data/test/reports/TEST-constraints-HammerCLI-Validator-AllConstraint.xml +0 -7
  149. data/test/reports/TEST-constraints-HammerCLI-Validator-AnyConstraint-exist-.xml +0 -13
  150. data/test/reports/TEST-constraints-HammerCLI-Validator-AnyConstraint.xml +0 -7
  151. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-exist-.xml +0 -9
  152. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-rejected.xml +0 -13
  153. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-required.xml +0 -13
  154. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint.xml +0 -7
  155. data/test/reports/TEST-constraints.xml +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a51bb0421b077ec5f6b58516eb36bfb36593543a
4
- data.tar.gz: e10795cc718d474a9b71e084472c2e9455bcc208
3
+ metadata.gz: 230906bc19a41759805ad05e51cee6244938cc5e
4
+ data.tar.gz: 7e4389026de508ce212c3af34823bc1606b6851e
5
5
  SHA512:
6
- metadata.gz: 177b9fe7bcfc57623a87fe32890a44ffe8ce2ed9c25bdcde061c87670fb8a1a6e5cf5993046262eabbf993984621e119fda6ec72ce880531f998893da80c6a9d
7
- data.tar.gz: 37f64d084f60e2e87fa99ac7f1b2ffe670a7577ec715e349439dce07432d9deee7e2193b16be8b35c896d75777a7dd0e55360b2c8e529b2ffbebb8adf2ac2df4
6
+ metadata.gz: 55c6841e58e1645e48eb83e147d662abc847cf99f18df1f5636b6fb9a09be79e133d99429fa626c3e6ca2456003091e7e74f2813ac43dc22ee163c0f2862b54d
7
+ data.tar.gz: ddeec7d17a560050722bddc473bbc2ff8bba5e967c3cf3f7772249fcf300ca38d03db2f5d8d75df0be5e1b10025eafeef257bf4b8ca5280d71720537ea0e6a0f
data/bin/hammer CHANGED
@@ -125,7 +125,7 @@ require 'hammer_cli'
125
125
 
126
126
  if preparser.fetch_ca_cert
127
127
  require 'hammer_cli/ca_cert_fetcher'
128
- ca_path = HammerCLI::SSLOptions.get_options[:ssl_ca_path]
128
+ ca_path = HammerCLI::SSLOptions.new.get_local_ca_store_path
129
129
  exit HammerCLI::CACertFetcher.new.fetch_ca_cert(preparser.fetch_ca_cert, ca_path)
130
130
  end
131
131
 
@@ -38,7 +38,7 @@
38
38
  #:ssl_ca_file: '/path/to/ca_certificate.pem'
39
39
 
40
40
  # Path to a direcotry with ca file
41
- #:ssl_ca_path: '~/.hammer/certs'
41
+ #:ssl_ca_path: '/path/to/ca'
42
42
 
43
43
  # Turn SSL verification on/off
44
44
  #:verify_ssl: true
@@ -51,3 +51,6 @@
51
51
 
52
52
  # Enable standard authentication in addition to client certificate authentication
53
53
  #:ssl_with_basic_auth: true
54
+
55
+ # local CA cert store path
56
+ #:local_ca_store_path: '~/.hammer/certs'
data/doc/release_notes.md CHANGED
@@ -1,6 +1,11 @@
1
1
  Release notes
2
2
  =============
3
3
 
4
+ ### 0.10.2 (2017-05-05)
5
+ * Retry command on session expiry ([#19431](http://projects.theforeman.org/issues/19431))
6
+ * Prevent fetching of non-CA certificates ([#19391](http://projects.theforeman.org/issues/19391))
7
+ * Use local ca cert store instead of ssl_ca_path ([#19390](http://projects.theforeman.org/issues/19390))
8
+
4
9
  ### 0.10.1 (2017-04-24)
5
10
  * Require apipie-bindings >= 0.2.0 ([#19083](http://projects.theforeman.org/issues/19083))
6
11
  * Install server CA cert without root access ([#19083](http://projects.theforeman.org/issues/19083))
@@ -24,11 +24,16 @@ module HammerCLI
24
24
  end
25
25
 
26
26
  def run(arguments)
27
- exit_code = super
28
- raise "exit code must be integer" unless exit_code.is_a? Integer
27
+ begin
28
+ begin
29
+ exit_code = super
30
+ raise "exit code must be integer" unless exit_code.is_a? Integer
31
+ rescue => e
32
+ exit_code = handle_exception(e)
33
+ end
34
+ logger.debug 'Retrying the command' if (exit_code == HammerCLI::EX_RETRY)
35
+ end while (exit_code == HammerCLI::EX_RETRY)
29
36
  return exit_code
30
- rescue => e
31
- handle_exception e
32
37
  end
33
38
 
34
39
  def parse(arguments)
@@ -7,7 +7,7 @@ module HammerCLI::Apipie
7
7
 
8
8
  def initialize(params, options = {})
9
9
  @logger = options[:logger]
10
- @api = ApipieBindings::API.new(params, HammerCLI::SSLOptions.get_options)
10
+ @api = ApipieBindings::API.new(params, HammerCLI::SSLOptions.new.get_options(params[:uri]))
11
11
  if options[:reload_cache]
12
12
  @api.clean_cache
13
13
  @logger.debug 'Apipie cache was cleared' unless @logger.nil?
@@ -1,13 +1,13 @@
1
1
  require 'hammer_cli/ca_cert_manager'
2
2
  module HammerCLI
3
3
  class CACertFetcher
4
- def fetch_ca_cert(service_uri, ca_path)
4
+ def fetch_ca_cert(service_uri, ca_store_path)
5
5
  begin
6
6
  uri = URI.parse(service_uri)
7
7
  raise URI::InvalidURIError.new(_("Unable to find hostname in #{service_uri}")) if uri.host.nil?
8
8
  raise URI::InvalidURIError.new(scheme_error(uri)) unless uri.scheme == 'https'
9
- ca_cert_manager = HammerCLI::CACertManager.new(ca_path)
10
- raw_cert = HammerCLI::CACertDownloader.new.download(uri)
9
+ ca_cert_manager = HammerCLI::CACertManager.new(ca_store_path)
10
+ raw_cert = HammerCLI::CertDownloader.new.download(uri)
11
11
  cert_file = ca_cert_manager.cert_file_name(uri)
12
12
  ca_cert_manager.store_ca_cert(raw_cert, cert_file)
13
13
 
@@ -17,8 +17,9 @@ module HammerCLI
17
17
  deb_update_cmd = "update-ca-certificates"
18
18
  cert_file = ca_cert_manager.cert_file_name(uri)
19
19
 
20
- puts _("CA certificate for #{service_uri} was stored to #{cert_file}")
20
+ puts _("CA certificate for %{uri} was stored to %{file}") % {:uri => service_uri, :file => cert_file}
21
21
  puts _("Now hammer can use the downloaded certificate to verify SSL connection to the server.")
22
+ puts _("It will be used automatically when ssl_ca_path and ssl_ca_file options are not set.")
22
23
  puts
23
24
  puts _("Be aware that hammer cannot verify whether the certificate is correct and you should verify its authenticity.")
24
25
  puts
@@ -44,6 +45,16 @@ module HammerCLI
44
45
  $stderr.puts _("Couldn't parse URI '%s'.") % service_uri
45
46
  $stderr.puts e.message
46
47
  return HammerCLI::EX_SOFTWARE
48
+ rescue HammerCLI::NoCACertificate => e
49
+ $stderr.puts _("The CA certificate for %{uri} couldn't be downloaded. No CA cert was found.") % {:uri => service_uri}
50
+ $stderr.puts
51
+ $stderr.puts _("Make sure your server sends cert chain including the CA.")
52
+ $stderr.puts _("To see the actual chain you can use openssl command")
53
+ $stderr.puts " $ openssl s_client -showcerts -connect #{uri.host}:#{uri.port} </dev/null"
54
+ $stderr.puts
55
+ $stderr.puts _("You can also download the certificate manually and store it as #{cert_file}")
56
+ $stderr.puts _("If you choose any other location set the ssl_ca_path or ssl_ca_file configuration options appropriately.")
57
+ return HammerCLI::EX_SOFTWARE
47
58
  rescue StandardError => e
48
59
  logger = Logging.logger['CACertFetcher']
49
60
  msg = [_('Fetching the CA certificate failed:')]
@@ -2,58 +2,43 @@ require 'fileutils'
2
2
 
3
3
  module HammerCLI
4
4
  class CACertManager
5
- attr_reader :ca_path
5
+ attr_reader :ca_store_path
6
6
 
7
- def initialize(ca_path)
8
- @ca_path = ca_path
7
+ def initialize(ca_store_path)
8
+ @ca_store_path = File.expand_path(ca_store_path)
9
9
  end
10
10
 
11
11
  def store_ca_cert(raw_cert, cert_file)
12
- ensure_ca_path_exist
12
+ raise HammerCLI::NoCACertificate.new unless is_ca_cert?(raw_cert)
13
+ ensure_ca_store_exist
13
14
  File.write(cert_file, raw_cert)
14
- hash = cert_hash(raw_cert)
15
- create_link(hash, cert_file)
16
15
  cert_file
17
16
  end
18
17
 
19
- def cert_hash(raw_cert)
20
- cert = OpenSSL::X509::Certificate.new(raw_cert)
21
- subject = OpenSSL::X509::Name.new(cert.subject)
22
- subject.hash
23
- end
24
-
25
- def create_link(hash, cert_file)
26
- ensure_ca_path_exist
27
- cert_link = File.join(ca_path, "#{hash.to_s(16)}.%s")
28
- count = 0
29
- # increase hash index if file or link to different target already exist
30
- while plain_file?(cert_link % count) || link_to_different_target?(cert_link % count, cert_file) do
31
- count += 1
32
- end
33
- File.symlink(cert_file, cert_link % count) unless File.symlink?(cert_link % count)
18
+ def cert_file_name(uri)
19
+ File.join(ca_store_path, "#{uri.host}_#{uri.port}.pem")
34
20
  end
35
21
 
36
- def cert_file_name(uri)
37
- File.join(ca_path, "#{uri.host}.pem")
22
+ def cert_exist?(uri)
23
+ File.exist?(cert_file_name(uri))
38
24
  end
39
25
 
40
26
  protected
41
27
 
42
-
43
- def ensure_ca_path_exist
44
- FileUtils.mkpath(ca_path) unless File.directory?(ca_path)
45
- end
46
-
47
- def plain_file?(path)
48
- File.exist?(path) && !File.symlink?(path)
28
+ def ensure_ca_store_exist
29
+ FileUtils.mkpath(ca_store_path) unless File.directory?(ca_store_path)
49
30
  end
50
31
 
51
- def link_to_different_target?(path, target)
52
- File.symlink?(path) && File.expand_path(File.readlink(path)) != File.expand_path(target)
32
+ def is_ca_cert?(cert)
33
+ cert = OpenSSL::X509::Certificate.new(cert) if cert.is_a? String
34
+ cert.extensions.any? do |ex|
35
+ (ex.oid == 'basicConstraints' && ex.value.upcase == 'CA:TRUE') ||
36
+ (ex.oid == 'keyUsage' && ex.value =~ /Cert(ificate )?Sign/i)
37
+ end
53
38
  end
54
39
  end
55
40
 
56
- class CACertDownloader
41
+ class CertDownloader
57
42
  def download(uri)
58
43
  noverify_ssl_connection = OpenSSL::SSL::SSLSocket.new(TCPSocket.new(uri.host, uri.port), noverify_ssl_context)
59
44
  noverify_ssl_connection.connect
@@ -4,5 +4,6 @@ module HammerCLI
4
4
  class OperationNotSupportedError < StandardError; end
5
5
  class ModuleLoadingError < StandardError; end
6
6
  class ModuleDisabledButRequired < StandardError; end
7
+ class NoCACertificate < StandardError; end
7
8
 
8
9
  end
@@ -4,7 +4,7 @@ module HammerCLI
4
4
  EX_USAGE = 64 # command line usage error
5
5
  EX_DATAERR = 65 # data format error
6
6
  EX_NOINPUT = 66 # cannot open input
7
- EX_NOUSER = 67 # addressee unknown
7
+ EX_NOUSER = 67 # addressee unknown
8
8
  EX_NOHOST = 68 # host name unknown
9
9
  EX_UNAVAILABLE = 69 # service unavailable
10
10
  EX_SOFTWARE = 70 # internal software error
@@ -20,4 +20,5 @@ module HammerCLI
20
20
  # non POSIX codes
21
21
  EX_NOT_FOUND = 128 # resource was not found
22
22
  EX_UNAUTHORIZED = 129 # authorization failed
23
+ EX_RETRY = 666 # retry the command
23
24
  end
@@ -1,17 +1,18 @@
1
1
  module HammerCLI
2
2
  class SSLOptions
3
- DEFAULT_SSL_CA_PATH = "~/.hammer/certs"
3
+ DEFAULT_LOCAL_CA_STORE_PATH = "~/.hammer/certs"
4
4
 
5
- def initialize(settings = HammerCLI::Settings, logger = Logging.logger['SSLoptions'])
6
- @settings = settings
7
- @logger = logger
5
+ def initialize(options={})
6
+ @settings = options.fetch(:settings, HammerCLI::Settings)
7
+ @logger = options.fetch(:logger, Logging.logger['SSLoptions'])
8
+ @ca_manager = options.fetch(:ca_manager, HammerCLI::CACertManager.new(DEFAULT_LOCAL_CA_STORE_PATH))
8
9
  end
9
10
 
10
- def self.get_options(settings = HammerCLI::Settings, logger = Logging.logger['SSLoptions'])
11
- self.new(settings, logger).get_options
11
+ def get_local_ca_store_path
12
+ @settings.get(:ssl, :local_ca_store_path) || DEFAULT_LOCAL_CA_STORE_PATH
12
13
  end
13
14
 
14
- def get_options
15
+ def get_options(uri = nil)
15
16
  ssl_options = {}
16
17
  for sslopt in [:ssl_ca_file, :ssl_ca_path, :verify_ssl] do
17
18
  ssloptval = read_ssl_option(sslopt)
@@ -19,13 +20,21 @@ module HammerCLI
19
20
  end
20
21
  ssl_options.merge!(cert_key_options)
21
22
 
22
- ssl_options[:ssl_ca_path] = DEFAULT_SSL_CA_PATH if ssl_options[:ssl_ca_path].nil?
23
+ # enable ssl verification
24
+ ssl_options[:verify_ssl] = true if ssl_options[:verify_ssl].nil?
25
+
26
+ if ssl_options[:verify_ssl] && uri && !ssl_options[:ssl_ca_file] && !ssl_options[:ssl_ca_path]
27
+ uri = URI.parse(uri) if uri.is_a?(String)
28
+ if @ca_manager.cert_exist?(uri)
29
+ ssl_options[:ssl_ca_file] = @ca_manager.cert_file_name(uri)
30
+ @logger.info("Matching CA cert was found in local CA store #{ssl_options[:ssl_ca_file]}")
31
+ end
32
+ end
33
+
23
34
  [:ssl_ca_file, :ssl_ca_path].each do |opt|
24
35
  ssl_options[opt] = File.expand_path(ssl_options[opt]) unless ssl_options[opt].nil?
25
36
  end
26
37
 
27
- # enable ssl verification
28
- ssl_options[:verify_ssl] = true if ssl_options[:verify_ssl].nil?
29
38
  @logger.debug("SSL options: #{ApipieBindings::Utils::inspect_data(ssl_options)}")
30
39
  ssl_options
31
40
  end
@@ -1,5 +1,5 @@
1
1
  module HammerCLI
2
2
  def self.version
3
- @version ||= Gem::Version.new '0.10.1'
3
+ @version ||= Gem::Version.new '0.10.2'
4
4
  end
5
5
  end
data/lib/hammer_cli.rb CHANGED
@@ -5,6 +5,7 @@ require 'hammer_cli/version'
5
5
  require 'hammer_cli/modules'
6
6
  require 'hammer_cli/exit_codes'
7
7
  require 'hammer_cli/settings'
8
+ require 'hammer_cli/ca_cert_manager'
8
9
  require 'hammer_cli/connection'
9
10
  require 'hammer_cli/validator'
10
11
  require 'hammer_cli/output'
data/man/hammer.1.gz CHANGED
Binary file
@@ -10,7 +10,6 @@ describe HammerCLI::Apipie::ApiConnection do
10
10
  def api_stub(params = {}, options = {})
11
11
  api_stub = stub()
12
12
  options[:verify_ssl] = true if options[:verify_ssl].nil?
13
- options[:ssl_ca_path] = File.expand_path(HammerCLI::SSLOptions::DEFAULT_SSL_CA_PATH) if options[:ssl_ca_path].nil?
14
13
  ApipieBindings::API.expects(:new).with(params, options).returns(api_stub)
15
14
  api_stub
16
15
  end
@@ -6,59 +6,49 @@ require 'hammer_cli/ca_cert_manager'
6
6
  describe HammerCLI::CACertManager do
7
7
 
8
8
  before(:all) do
9
- @ca_path = Dir.mktmpdir('ca_cert_manager')
9
+ @ca_store_path = Dir.mktmpdir('ca_cert_manager')
10
10
  end
11
11
 
12
12
  after(:all) do
13
- FileUtils.rm_rf(@ca_path) if File.exist?(@ca_path)
13
+ FileUtils.rm_rf(@ca_store_path) if File.exist?(@ca_store_path)
14
14
  end
15
15
 
16
16
  let(:service_uri) { URI.parse("https://test.host.com") }
17
- let(:ca_cert_manager) { HammerCLI::CACertManager.new(@ca_path) }
17
+ let(:ca_cert_manager) { HammerCLI::CACertManager.new(@ca_store_path) }
18
18
  let(:cert_file) { ca_cert_manager.cert_file_name(service_uri) }
19
+ let(:ca_cert_fixture) { File.join(File.dirname(__FILE__), '/fixtures/certs/ca_cert.pem') }
20
+ let(:non_ca_cert_fixture) { File.join(File.dirname(__FILE__), '/fixtures/certs/non_ca_cert.pem') }
19
21
 
20
22
  describe '#store_ca_cert' do
21
- let(:cert_fixture) { File.join(File.dirname(__FILE__), '/fixtures/certs/ca_cert.pem') }
22
-
23
23
  it 'stores ca cert' do
24
- new_cert_file = ca_cert_manager.store_ca_cert(File.read(cert_fixture), cert_file)
25
- assert File.exist?(File.join(@ca_path, "2c543cd1.0"))
24
+ new_cert_file = ca_cert_manager.store_ca_cert(File.read(ca_cert_fixture), cert_file)
26
25
  assert File.exist?(cert_file)
27
26
  assert_equal cert_file, new_cert_file
28
27
  end
29
- end
30
-
31
- describe '#create_link' do
32
- let(:hash) { 123456789 }
33
- let(:hash_file) { hash.to_s(16) }
34
28
 
35
- it "creates link to cert" do
36
- FileUtils.touch(cert_file)
37
- ca_cert_manager.create_link(hash, cert_file)
38
- assert File.exist?(File.join(@ca_path, "#{hash_file}.0"))
29
+ it 'refuses non-CA cert' do
30
+ assert_raises HammerCLI::NoCACertificate do
31
+ ca_cert_manager.store_ca_cert(File.read(non_ca_cert_fixture), cert_file)
32
+ end
39
33
  end
34
+ end
40
35
 
41
- it "creates ca path if missing" do
42
- FileUtils.rm_rf(@ca_path) if File.exist?(@ca_path)
43
- ca_cert_manager.create_link(hash, cert_file)
44
- FileUtils.touch(cert_file)
45
- assert File.exist?(File.join(@ca_path, "#{hash_file}.0"))
36
+ describe '#cert_exist?' do
37
+ it 'return true if the cert exist' do
38
+ ca_cert_manager.store_ca_cert(File.read(ca_cert_fixture), cert_file)
39
+ assert ca_cert_manager.cert_exist?(service_uri)
46
40
  end
47
41
 
48
- it "does not create new link if it already exist" do
49
- FileUtils.touch(cert_file)
50
- File.symlink(cert_file, File.join(@ca_path, "#{hash_file}.0"))
51
- ca_cert_manager.create_link(hash, cert_file)
52
- assert File.exist?(File.join(@ca_path, "#{hash_file}.0"))
53
- refute File.exist?(File.join(@ca_path, "#{hash_file}.1"))
42
+ it 'return false if the cert does not exist' do
43
+ refute ca_cert_manager.cert_exist?(service_uri)
54
44
  end
45
+ end
55
46
 
56
- it "does not override existing link if it has different target" do
57
- FileUtils.touch(cert_file)
58
- FileUtils.touch(File.join(@ca_path, "#{hash_file}.0"))
59
- ca_cert_manager.create_link(hash, cert_file)
60
- assert File.exist?(File.join(@ca_path, "#{hash_file}.0"))
61
- assert File.exist?(File.join(@ca_path, "#{hash_file}.1"))
47
+ describe '#cert_file_name' do
48
+ it 'make file name from host uri' do
49
+ uri = URI.parse("https://test.example.com:1111")
50
+ filename = ca_cert_manager.cert_file_name(uri)
51
+ assert_equal File.join(ca_cert_manager.ca_store_path,'test.example.com_1111.pem'), filename
62
52
  end
63
53
  end
64
54
  end
@@ -0,0 +1,27 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEgDCCA2igAwIBAgIIdKMhNG6e8c4wDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE
3
+ BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
4
+ cm5ldCBBdXRob3JpdHkgRzIwHhcNMTcwNDEyMTMyODAwWhcNMTcwNzA1MTMyODAw
5
+ WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
6
+ TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
7
+ Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDI5ZXl
8
+ lffcMQiwJGs2CxZToWbi16Q7LL6H8y3xuRwDn//gp8qX8Jcv4x7KG4aEipB8wOUm
9
+ jrZs2Q1BT8VIqfQLLqhSrP61LZfuAzv/v1WAw7CmtvqCH91qKM/SkOXyCJK1Cf2/
10
+ +i5oLoY2NnxV7iM7+tidPSF4ZPMjtb13ABVcdr49lDlSZce8YXDoWtlr9hjfAPEF
11
+ mzxlSsA5gPv/BNUhgW8Rna3UWwl4jgKAFOgLybKTharhnEl14cYUeDJ/HnGLc8L1
12
+ 6es05HjHsz6J3jpXi9x0X1b5lQfeEFYLBPQ3nPjGgOZvECLLl8esBkpAWy+BLGd0
13
+ vPYRWZnnnOU3+i33AgMBAAGjggFLMIIBRzAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
14
+ KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
15
+ XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
16
+ MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
17
+ A1UdDgQWBBRfEHz1zg9lsVjVptJ9ncVQH7wzIzAMBgNVHRMBAf8EAjAAMB8GA1Ud
18
+ IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMCEGA1UdIAQaMBgwDAYKKwYBBAHW
19
+ eQIFATAIBgZngQwBAgIwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29n
20
+ bGUuY29tL0dJQUcyLmNybDANBgkqhkiG9w0BAQsFAAOCAQEAgo6rk/60YN5JYhPO
21
+ oBm3nTawx+0FW/rFh6tEsxUl2x6d6eYN/W95Wx2ofJFTe0blC5W40GHyFjuGoEGb
22
+ 7soS+gUMsMNb1oiz8osD/OOce70afUcGMSB1qEXC2Q7plCqnJSTDIEsO1r7O0Y6n
23
+ JUqvdrB/LqihaKYnYKsSM6ya+i3fX55KfamkqeRmDIVOspDNcy8zl+EbAX3sJk3j
24
+ k2bitWNktp37t+suGhimvmOVaP/EVRMl8z5RUrNTi8q2M1BzDOZD5k/Hhxy1UFpr
25
+ QwHC6MuyOpgKBIHQguLvzD2I3dyK1GzzsfiyYx3eCJVq4f5iAfSkaxf8spWIhIRo
26
+ YgQaig==
27
+ -----END CERTIFICATE-----