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.
- checksums.yaml +4 -4
- data/bin/hammer +1 -1
- data/config/cli_config.template.yml +4 -1
- data/doc/release_notes.md +5 -0
- data/lib/hammer_cli/abstract.rb +9 -4
- data/lib/hammer_cli/apipie/api_connection.rb +1 -1
- data/lib/hammer_cli/ca_cert_fetcher.rb +15 -4
- data/lib/hammer_cli/ca_cert_manager.rb +18 -33
- data/lib/hammer_cli/exceptions.rb +1 -0
- data/lib/hammer_cli/exit_codes.rb +2 -1
- data/lib/hammer_cli/ssloptions.rb +19 -10
- data/lib/hammer_cli/version.rb +1 -1
- data/lib/hammer_cli.rb +1 -0
- data/man/hammer.1.gz +0 -0
- data/test/unit/apipie/api_connection_test.rb +0 -1
- data/test/unit/ca_cert_manager_test.rb +23 -33
- data/test/unit/fixtures/certs/non_ca_cert.pem +27 -0
- metadata +50 -322
- data/test/reports/TEST-Fields-ContainerField-display-.xml +0 -7
- data/test/reports/TEST-Fields-ContainerField-display-blank-is-allowed.xml +0 -15
- data/test/reports/TEST-Fields-ContainerField-display-blank-is-not-allowed.xml +0 -15
- data/test/reports/TEST-Fields-ContainerField.xml +0 -7
- data/test/reports/TEST-Fields-Field-display-.xml +0 -7
- data/test/reports/TEST-Fields-Field-display-blank-is-allowed.xml +0 -11
- data/test/reports/TEST-Fields-Field-display-blank-is-not-allowed.xml +0 -11
- data/test/reports/TEST-Fields-Field-hide-blank-.xml +0 -11
- data/test/reports/TEST-Fields-Field-parameters.xml +0 -9
- data/test/reports/TEST-Fields-Field.xml +0 -13
- data/test/reports/TEST-HammerCLI-AbstractCommand-build-options.xml +0 -15
- data/test/reports/TEST-HammerCLI-AbstractCommand-exception-handler.xml +0 -13
- data/test/reports/TEST-HammerCLI-AbstractCommand-logging.xml +0 -21
- data/test/reports/TEST-HammerCLI-AbstractCommand-option-builder.xml +0 -11
- data/test/reports/TEST-HammerCLI-AbstractCommand-options.xml +0 -11
- data/test/reports/TEST-HammerCLI-AbstractCommand-output.xml +0 -19
- data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-remove-subcommand.xml +0 -11
- data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-subcommand-.xml +0 -13
- data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-subcommand.xml +0 -11
- data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior.xml +0 -7
- data/test/reports/TEST-HammerCLI-AbstractCommand.xml +0 -11
- data/test/reports/TEST-HammerCLI-Apipie-Command-options.xml +0 -11
- data/test/reports/TEST-HammerCLI-Apipie-Command-resource-defined.xml +0 -9
- data/test/reports/TEST-HammerCLI-Apipie-Command-setting-resources.xml +0 -19
- data/test/reports/TEST-HammerCLI-Apipie-Command.xml +0 -9
- data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-aliasing-resources.xml +0 -13
- data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-filtering-options.xml +0 -15
- data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-required-options.xml +0 -11
- data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-setting-correct-normalizers.xml +0 -9
- data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-with-hash-params.xml +0 -11
- data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-with-one-simple-param.xml +0 -15
- data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder.xml +0 -7
- data/test/reports/TEST-HammerCLI-Completer-command-completion.xml +0 -29
- data/test/reports/TEST-HammerCLI-Completer-option-value-completion.xml +0 -17
- data/test/reports/TEST-HammerCLI-Completer-subcommand-completion.xml +0 -19
- data/test/reports/TEST-HammerCLI-Completer.xml +0 -7
- data/test/reports/TEST-HammerCLI-CompleterLine-line-complete.xml +0 -25
- data/test/reports/TEST-HammerCLI-CompleterLine-splitting-words.xml +0 -29
- data/test/reports/TEST-HammerCLI-CompleterLine.xml +0 -7
- data/test/reports/TEST-HammerCLI-CompleterWord-complete-.xml +0 -23
- data/test/reports/TEST-HammerCLI-CompleterWord-quote.xml +0 -15
- data/test/reports/TEST-HammerCLI-CompleterWord-quoted-.xml +0 -13
- data/test/reports/TEST-HammerCLI-CompleterWord.xml +0 -7
- data/test/reports/TEST-HammerCLI-Connection.xml +0 -21
- data/test/reports/TEST-HammerCLI-ExceptionHandler.xml +0 -21
- data/test/reports/TEST-HammerCLI-I18n.xml +0 -11
- data/test/reports/TEST-HammerCLI-MainCommand-loading-context-password.xml +0 -11
- data/test/reports/TEST-HammerCLI-MainCommand-loading-context-username.xml +0 -11
- data/test/reports/TEST-HammerCLI-MainCommand-loading-context-verbose.xml +0 -9
- data/test/reports/TEST-HammerCLI-MainCommand-loading-context.xml +0 -7
- data/test/reports/TEST-HammerCLI-MainCommand.xml +0 -7
- data/test/reports/TEST-HammerCLI-Modules-find-by-name.xml +0 -13
- data/test/reports/TEST-HammerCLI-Modules-load-a-module-module-not-found.xml +0 -13
- data/test/reports/TEST-HammerCLI-Modules-load-a-module-module-runtime-exception.xml +0 -13
- data/test/reports/TEST-HammerCLI-Modules-load-a-module-success.xml +0 -15
- data/test/reports/TEST-HammerCLI-Modules-load-a-module.xml +0 -7
- data/test/reports/TEST-HammerCLI-Modules-load-all-modules.xml +0 -9
- data/test/reports/TEST-HammerCLI-Modules-names.xml +0 -13
- data/test/reports/TEST-HammerCLI-Modules.xml +0 -7
- data/test/reports/TEST-HammerCLI-OptionBuilderContainer.0.xml +0 -7
- data/test/reports/TEST-HammerCLI-OptionBuilderContainer.xml +0 -11
- data/test/reports/TEST-HammerCLI-Options-Normalizers-abstract.xml +0 -9
- data/test/reports/TEST-HammerCLI-Options-Normalizers-bool.xml +0 -31
- data/test/reports/TEST-HammerCLI-Options-Normalizers-datetime.xml +0 -17
- data/test/reports/TEST-HammerCLI-Options-Normalizers-enum.xml +0 -15
- data/test/reports/TEST-HammerCLI-Options-Normalizers-enumlist.xml +0 -21
- data/test/reports/TEST-HammerCLI-Options-Normalizers-json-input.xml +0 -15
- data/test/reports/TEST-HammerCLI-Options-Normalizers-key-value-list.xml +0 -17
- data/test/reports/TEST-HammerCLI-Options-Normalizers-list.xml +0 -15
- data/test/reports/TEST-HammerCLI-Options-Normalizers.xml +0 -7
- data/test/reports/TEST-HammerCLI-Options-OptionDefinition-context.xml +0 -9
- data/test/reports/TEST-HammerCLI-Options-OptionDefinition-formatters.xml +0 -11
- data/test/reports/TEST-HammerCLI-Options-OptionDefinition.xml +0 -7
- data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-error-messages.xml +0 -15
- data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-messages.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-test-data-for-field.xml +0 -15
- data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract.xml +0 -17
- data/test/reports/TEST-HammerCLI-Output-Adapter-Base-print-collection-show-ids.xml +0 -9
- data/test/reports/TEST-HammerCLI-Output-Adapter-Base-print-collection.xml +0 -27
- data/test/reports/TEST-HammerCLI-Output-Adapter-Base.xml +0 -7
- data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-formatters.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-fields-with-collections.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-fields-with-containers.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-ids.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-message.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues.xml +0 -7
- data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-column-width.xml +0 -15
- data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-formatters.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-handle-ids.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-sort-columns.xml +0 -9
- data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Adapter-Table.xml +0 -7
- data/test/reports/TEST-HammerCLI-Output-Definition-empty-.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Definition.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Dsl-collection.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Dsl-custom-fields.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Dsl-fields.xml +0 -15
- data/test/reports/TEST-HammerCLI-Output-Dsl-label.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Dsl-path-definition.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Dsl.xml +0 -9
- data/test/reports/TEST-HammerCLI-Output-FieldFilter.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Formatters-BooleanFormatter.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Formatters-ColorFormatter.xml +0 -9
- data/test/reports/TEST-HammerCLI-Output-Formatters-DateFormatter.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Formatters-FieldFormatter.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Formatters-FormatterContainer.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Formatters-FormatterLibrary.xml +0 -11
- data/test/reports/TEST-HammerCLI-Output-Formatters-KeyValueFormatter.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Formatters-ListFormatter.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Formatters-LongTextFormatter.xml +0 -13
- data/test/reports/TEST-HammerCLI-Output-Output-adapters.xml +0 -17
- data/test/reports/TEST-HammerCLI-Output-Output-data.xml +0 -15
- data/test/reports/TEST-HammerCLI-Output-Output-formatters.xml +0 -9
- data/test/reports/TEST-HammerCLI-Output-Output-messages.xml +0 -19
- data/test/reports/TEST-HammerCLI-Output-Output.xml +0 -7
- data/test/reports/TEST-HammerCLI-Output-RecordCollection.xml +0 -13
- data/test/reports/TEST-HammerCLI-Settings-load-from-paths.xml +0 -15
- data/test/reports/TEST-HammerCLI-Settings.xml +0 -25
- data/test/reports/TEST-HammerCLI-ShellHistory-loading-old-history.xml +0 -11
- data/test/reports/TEST-HammerCLI-ShellHistory-saving-history.xml +0 -15
- data/test/reports/TEST-HammerCLI-ShellHistory.xml +0 -7
- data/test/reports/TEST-MiniTest-Spec.xml +0 -7
- data/test/reports/TEST-String-camelize.xml +0 -11
- data/test/reports/TEST-String-formatting.xml +0 -17
- data/test/reports/TEST-String-indent.xml +0 -11
- data/test/reports/TEST-String-interactive-.xml +0 -13
- data/test/reports/TEST-String.xml +0 -7
- data/test/reports/TEST-constraints-HammerCLI-Validator-AllConstraint-exist-.xml +0 -13
- data/test/reports/TEST-constraints-HammerCLI-Validator-AllConstraint.xml +0 -7
- data/test/reports/TEST-constraints-HammerCLI-Validator-AnyConstraint-exist-.xml +0 -13
- data/test/reports/TEST-constraints-HammerCLI-Validator-AnyConstraint.xml +0 -7
- data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-exist-.xml +0 -9
- data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-rejected.xml +0 -13
- data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-required.xml +0 -13
- data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint.xml +0 -7
- data/test/reports/TEST-constraints.xml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 230906bc19a41759805ad05e51cee6244938cc5e
|
4
|
+
data.tar.gz: 7e4389026de508ce212c3af34823bc1606b6851e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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: '
|
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))
|
data/lib/hammer_cli/abstract.rb
CHANGED
@@ -24,11 +24,16 @@ module HammerCLI
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def run(arguments)
|
27
|
-
|
28
|
-
|
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,
|
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(
|
10
|
-
raw_cert = HammerCLI::
|
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
|
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 :
|
5
|
+
attr_reader :ca_store_path
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@
|
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
|
-
|
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
|
20
|
-
|
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
|
37
|
-
File.
|
22
|
+
def cert_exist?(uri)
|
23
|
+
File.exist?(cert_file_name(uri))
|
38
24
|
end
|
39
25
|
|
40
26
|
protected
|
41
27
|
|
42
|
-
|
43
|
-
|
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
|
52
|
-
|
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
|
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,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
|
-
|
3
|
+
DEFAULT_LOCAL_CA_STORE_PATH = "~/.hammer/certs"
|
4
4
|
|
5
|
-
def initialize(
|
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
|
11
|
-
|
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
|
-
|
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
|
data/lib/hammer_cli/version.rb
CHANGED
data/lib/hammer_cli.rb
CHANGED
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
|
-
@
|
9
|
+
@ca_store_path = Dir.mktmpdir('ca_cert_manager')
|
10
10
|
end
|
11
11
|
|
12
12
|
after(:all) do
|
13
|
-
FileUtils.rm_rf(@
|
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(@
|
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(
|
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
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
42
|
-
|
43
|
-
ca_cert_manager.
|
44
|
-
|
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
|
49
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
ca_cert_manager.
|
60
|
-
|
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-----
|