From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 16 Mar 2020 18:49:26 +0900 Subject: Fresh start --- .../rubygems/test_gem_commands_cert_command.rb | 670 +++++++++++++++++++++ 1 file changed, 670 insertions(+) create mode 100644 jni/ruby/test/rubygems/test_gem_commands_cert_command.rb (limited to 'jni/ruby/test/rubygems/test_gem_commands_cert_command.rb') diff --git a/jni/ruby/test/rubygems/test_gem_commands_cert_command.rb b/jni/ruby/test/rubygems/test_gem_commands_cert_command.rb new file mode 100644 index 0000000..4c1dcc2 --- /dev/null +++ b/jni/ruby/test/rubygems/test_gem_commands_cert_command.rb @@ -0,0 +1,670 @@ +require 'rubygems/test_case' +require 'rubygems/commands/cert_command' +require 'rubygems/fix_openssl_warnings' if RUBY_VERSION < "1.9" + +unless defined?(OpenSSL::SSL) then + warn 'Skipping `gem cert` tests. openssl not found.' +end + +class TestGemCommandsCertCommand < Gem::TestCase + + ALTERNATE_CERT = load_cert 'alternate' + + ALTERNATE_KEY_FILE = key_path 'alternate' + PRIVATE_KEY_FILE = key_path 'private' + PUBLIC_KEY_FILE = key_path 'public' + + ALTERNATE_CERT_FILE = cert_path 'alternate' + CHILD_CERT_FILE = cert_path 'child' + PUBLIC_CERT_FILE = cert_path 'public' + + def setup + super + + @cmd = Gem::Commands::CertCommand.new + + @trust_dir = Gem::Security.trust_dir + end + + def test_certificates_matching + @trust_dir.trust_cert PUBLIC_CERT + @trust_dir.trust_cert ALTERNATE_CERT + + matches = @cmd.certificates_matching '' + + # HACK OpenSSL::X509::Certificate#== is Object#==, so do this the hard way + match = matches.next + assert_equal ALTERNATE_CERT.to_pem, match.first.to_pem + assert_equal @trust_dir.cert_path(ALTERNATE_CERT), match.last + + match = matches.next + assert_equal PUBLIC_CERT.to_pem, match.first.to_pem + assert_equal @trust_dir.cert_path(PUBLIC_CERT), match.last + + assert_raises StopIteration do + matches.next + end + end + + def test_certificates_matching_filter + @trust_dir.trust_cert PUBLIC_CERT + @trust_dir.trust_cert ALTERNATE_CERT + + matches = @cmd.certificates_matching 'alternate' + + match = matches.next + assert_equal ALTERNATE_CERT.to_pem, match.first.to_pem + assert_equal @trust_dir.cert_path(ALTERNATE_CERT), match.last + + assert_raises StopIteration do + matches.next + end + end + + def test_execute_add + @cmd.handle_options %W[--add #{PUBLIC_CERT_FILE}] + + use_ui @ui do + @cmd.execute + end + + cert_path = @trust_dir.cert_path PUBLIC_CERT + + assert_path_exists cert_path + + assert_equal "Added '/CN=nobody/DC=example'\n", @ui.output + assert_empty @ui.error + end + + def test_execute_add_twice + self.class.cert_path 'alternate' + + @cmd.handle_options %W[ + --add #{PUBLIC_CERT_FILE} + --add #{ALTERNATE_CERT_FILE} + ] + + use_ui @ui do + @cmd.execute + end + + expected = <<-EXPECTED +Added '/CN=nobody/DC=example' +Added '/CN=alternate/DC=example' + EXPECTED + + assert_equal expected, @ui.output + assert_empty @ui.error + end + + def test_execute_build + passphrase = 'Foo bar' + + @cmd.handle_options %W[--build nobody@example.com] + + @build_ui = Gem::MockGemUi.new "#{passphrase}\n#{passphrase}" + + use_ui @build_ui do + @cmd.execute + end + + output = @build_ui.output.squeeze("\n").split "\n" + + assert_equal "Passphrase for your Private Key: ", + output.shift + assert_equal "Please repeat the passphrase for your Private Key: ", + output.shift + assert_equal "Certificate: #{File.join @tempdir, 'gem-public_cert.pem'}", + output.shift + assert_equal "Private Key: #{File.join @tempdir, 'gem-private_key.pem'}", + output.shift + + assert_equal "Don't forget to move the key file to somewhere private!", + output.shift + + assert_empty output + assert_empty @build_ui.error + + assert_path_exists File.join(@tempdir, 'gem-private_key.pem') + assert_path_exists File.join(@tempdir, 'gem-public_cert.pem') + end + + def test_execute_build_bad_passphrase_confirmation + passphrase = 'Foo bar' + passphrase_confirmation = 'Fu bar' + + @cmd.handle_options %W[--build nobody@example.com] + + @build_ui = Gem::MockGemUi.new "#{passphrase}\n#{passphrase_confirmation}" + + use_ui @build_ui do + e = assert_raises Gem::CommandLineError do + @cmd.execute + end + + output = @build_ui.output.squeeze("\n").split "\n" + + assert_equal "Passphrase for your Private Key: ", + output.shift + assert_equal "Please repeat the passphrase for your Private Key: ", + output.shift + + assert_empty output + + assert_equal "Passphrase and passphrase confirmation don't match", + e.message + + end + + refute_path_exists File.join(@tempdir, 'gem-private_key.pem') + refute_path_exists File.join(@tempdir, 'gem-public_cert.pem') + end + + def test_execute_build_key + @cmd.handle_options %W[ + --build nobody@example.com + --private-key #{PRIVATE_KEY_FILE} + ] + + use_ui @ui do + @cmd.execute + end + + output = @ui.output.split "\n" + + assert_equal "Certificate: #{File.join @tempdir, 'gem-public_cert.pem'}", + output.shift + + assert_empty output + assert_empty @ui.error + + assert_path_exists File.join(@tempdir, 'gem-public_cert.pem') + refute_path_exists File.join(@tempdir, 'gem-private_key.pem') + end + + def test_execute_build_encrypted_key + @cmd.handle_options %W[ + --build nobody@example.com + --private-key #{ENCRYPTED_PRIVATE_KEY_PATH} + ] + + use_ui @ui do + @cmd.execute + end + + output = @ui.output.split "\n" + + assert_equal "Certificate: #{File.join @tempdir, 'gem-public_cert.pem'}", + output.shift + + assert_empty output + assert_empty @ui.error + + assert_path_exists File.join(@tempdir, 'gem-public_cert.pem') + end + + def test_execute_certificate + use_ui @ui do + @cmd.handle_options %W[--certificate #{PUBLIC_CERT_FILE}] + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + assert_equal PUBLIC_CERT.to_pem, @cmd.options[:issuer_cert].to_pem + end + + def test_execute_list + @trust_dir.trust_cert PUBLIC_CERT + @trust_dir.trust_cert ALTERNATE_CERT + + @cmd.handle_options %W[--list] + + use_ui @ui do + @cmd.execute + end + + assert_equal "/CN=alternate/DC=example\n/CN=nobody/DC=example\n", + @ui.output + assert_empty @ui.error + end + + def test_execute_list_filter + @trust_dir.trust_cert PUBLIC_CERT + @trust_dir.trust_cert ALTERNATE_CERT + + @cmd.handle_options %W[--list nobody] + + use_ui @ui do + @cmd.execute + end + + assert_equal "/CN=nobody/DC=example\n", @ui.output + assert_empty @ui.error + end + + def test_execute_private_key + use_ui @ui do + @cmd.send :handle_options, %W[--private-key #{PRIVATE_KEY_FILE}] + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + assert_equal PRIVATE_KEY.to_pem, @cmd.options[:key].to_pem + end + + def test_execute_encrypted_private_key + use_ui @ui do + @cmd.send :handle_options, %W[--private-key #{ENCRYPTED_PRIVATE_KEY_PATH}] + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + assert_equal ENCRYPTED_PRIVATE_KEY.to_pem, @cmd.options[:key].to_pem + end + + def test_execute_remove + @trust_dir.trust_cert PUBLIC_CERT + + cert_path = @trust_dir.cert_path PUBLIC_CERT + + assert_path_exists cert_path + + @cmd.handle_options %W[--remove nobody] + + use_ui @ui do + @cmd.execute + end + + assert_equal "Removed '/CN=nobody/DC=example'\n", @ui.output + assert_equal '', @ui.error + + refute_path_exists cert_path + end + + def test_execute_remove_multiple + @trust_dir.trust_cert PUBLIC_CERT + @trust_dir.trust_cert ALTERNATE_CERT + + public_path = @trust_dir.cert_path PUBLIC_CERT + alternate_path = @trust_dir.cert_path ALTERNATE_CERT + + assert_path_exists public_path + assert_path_exists alternate_path + + @cmd.handle_options %W[--remove example] + + use_ui @ui do + @cmd.execute + end + + expected = <<-EXPECTED +Removed '/CN=alternate/DC=example' +Removed '/CN=nobody/DC=example' + EXPECTED + + assert_equal expected, @ui.output + assert_equal '', @ui.error + + refute_path_exists public_path + refute_path_exists alternate_path + end + + def test_execute_remove_twice + @trust_dir.trust_cert PUBLIC_CERT + @trust_dir.trust_cert ALTERNATE_CERT + + public_path = @trust_dir.cert_path PUBLIC_CERT + alternate_path = @trust_dir.cert_path ALTERNATE_CERT + + assert_path_exists public_path + assert_path_exists alternate_path + + @cmd.handle_options %W[--remove nobody --remove alternate] + + use_ui @ui do + @cmd.execute + end + + expected = <<-EXPECTED +Removed '/CN=nobody/DC=example' +Removed '/CN=alternate/DC=example' + EXPECTED + + assert_equal expected, @ui.output + assert_equal '', @ui.error + + refute_path_exists public_path + refute_path_exists alternate_path + end + + def test_execute_sign + path = File.join @tempdir, 'cert.pem' + Gem::Security.write ALTERNATE_CERT, path, 0600 + + assert_equal '/CN=alternate/DC=example', ALTERNATE_CERT.issuer.to_s + + @cmd.handle_options %W[ + --private-key #{PRIVATE_KEY_FILE} + --certificate #{PUBLIC_CERT_FILE} + + --sign #{path} + ] + + use_ui @ui do + @cmd.execute + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + cert = OpenSSL::X509::Certificate.new File.read path + + assert_equal '/CN=nobody/DC=example', cert.issuer.to_s + + mask = 0100600 & (~File.umask) + + assert_equal mask, File.stat(path).mode unless win_platform? + end + + def test_execute_sign_encrypted_key + path = File.join @tempdir, 'cert.pem' + Gem::Security.write ALTERNATE_CERT, path, 0600 + + assert_equal '/CN=alternate/DC=example', ALTERNATE_CERT.issuer.to_s + + @cmd.handle_options %W[ + --private-key #{ENCRYPTED_PRIVATE_KEY_PATH} + --certificate #{PUBLIC_CERT_FILE} + + --sign #{path} + ] + + use_ui @ui do + @cmd.execute + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + cert = OpenSSL::X509::Certificate.new File.read path + + assert_equal '/CN=nobody/DC=example', cert.issuer.to_s + + mask = 0100600 & (~File.umask) + + assert_equal mask, File.stat(path).mode unless win_platform? + end + + def test_execute_sign_default + FileUtils.mkdir_p File.join Gem.user_home, '.gem' + + private_key_path = File.join Gem.user_home, '.gem', 'gem-private_key.pem' + Gem::Security.write PRIVATE_KEY, private_key_path + + public_cert_path = File.join Gem.user_home, '.gem', 'gem-public_cert.pem' + Gem::Security.write PUBLIC_CERT, public_cert_path + + path = File.join @tempdir, 'cert.pem' + Gem::Security.write ALTERNATE_CERT, path, 0600 + + assert_equal '/CN=alternate/DC=example', ALTERNATE_CERT.issuer.to_s + + @cmd.handle_options %W[--sign #{path}] + + use_ui @ui do + @cmd.execute + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + cert = OpenSSL::X509::Certificate.new File.read path + + assert_equal '/CN=nobody/DC=example', cert.issuer.to_s + + mask = 0100600 & (~File.umask) + + assert_equal mask, File.stat(path).mode unless win_platform? + end + + def test_execute_sign_default_encrypted_key + FileUtils.mkdir_p File.join(Gem.user_home, '.gem') + + private_key_path = File.join Gem.user_home, '.gem', 'gem-private_key.pem' + Gem::Security.write ENCRYPTED_PRIVATE_KEY, private_key_path, 0600, PRIVATE_KEY_PASSPHRASE + + public_cert_path = File.join Gem.user_home, '.gem', 'gem-public_cert.pem' + Gem::Security.write PUBLIC_CERT, public_cert_path + + path = File.join @tempdir, 'cert.pem' + Gem::Security.write ALTERNATE_CERT, path, 0600 + + assert_equal '/CN=alternate/DC=example', ALTERNATE_CERT.issuer.to_s + + @cmd.handle_options %W[--sign #{path}] + + use_ui @ui do + @cmd.execute + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + cert = OpenSSL::X509::Certificate.new File.read path + + assert_equal '/CN=nobody/DC=example', cert.issuer.to_s + + mask = 0100600 & (~File.umask) + + assert_equal mask, File.stat(path).mode unless win_platform? + end + + def test_execute_sign_no_cert + FileUtils.mkdir_p File.join Gem.user_home, '.gem' + + private_key_path = File.join Gem.user_home, '.gem', 'gem-private_key.pem' + Gem::Security.write PRIVATE_KEY, private_key_path + + path = File.join @tempdir, 'cert.pem' + Gem::Security.write ALTERNATE_CERT, path, 0600 + + assert_equal '/CN=alternate/DC=example', ALTERNATE_CERT.issuer.to_s + + @cmd.handle_options %W[--sign #{path}] + + use_ui @ui do + assert_raises Gem::MockGemUi::TermError do + @cmd.execute + end + end + + assert_equal '', @ui.output + + expected = <<-EXPECTED +ERROR: --certificate not specified and ~/.gem/gem-public_cert.pem does not exist + EXPECTED + + assert_equal expected, @ui.error + end + + def test_execute_sign_no_key + FileUtils.mkdir_p File.join Gem.user_home, '.gem' + + public_cert_path = File.join Gem.user_home, '.gem', 'gem-public_cert.pem' + Gem::Security.write PUBLIC_CERT, public_cert_path + + path = File.join @tempdir, 'cert.pem' + Gem::Security.write ALTERNATE_CERT, path, 0600 + + assert_equal '/CN=alternate/DC=example', ALTERNATE_CERT.issuer.to_s + + @cmd.handle_options %W[--sign #{path}] + + use_ui @ui do + assert_raises Gem::MockGemUi::TermError do + @cmd.execute + end + end + + assert_equal '', @ui.output + + expected = <<-EXPECTED +ERROR: --private-key not specified and ~/.gem/gem-private_key.pem does not exist + EXPECTED + + assert_equal expected, @ui.error + end + + def test_handle_options + @cmd.handle_options %W[ + --add #{PUBLIC_CERT_FILE} + --add #{ALTERNATE_CERT_FILE} + + --remove nobody + --remove example + + --list + --list example + + --build nobody@example + --build other@example + ] + + assert_equal [PUBLIC_CERT.to_pem, ALTERNATE_CERT.to_pem], + @cmd.options[:add].map { |cert| cert.to_pem } + + assert_equal %w[nobody example], @cmd.options[:remove] + + assert_equal %w[nobody@example other@example], + @cmd.options[:build].map { |name| name.to_s } + + assert_equal ['', 'example'], @cmd.options[:list] + end + + def test_handle_options_add_bad + nonexistent = File.join @tempdir, 'nonexistent' + e = assert_raises OptionParser::InvalidArgument do + @cmd.handle_options %W[--add #{nonexistent}] + end + + assert_equal "invalid argument: --add #{nonexistent}: does not exist", + e.message + + bad = File.join @tempdir, 'bad' + FileUtils.touch bad + + e = assert_raises OptionParser::InvalidArgument do + @cmd.handle_options %W[--add #{bad}] + end + + assert_equal "invalid argument: --add #{bad}: invalid X509 certificate", + e.message + end + + def test_handle_options_certificate + nonexistent = File.join @tempdir, 'nonexistent' + e = assert_raises OptionParser::InvalidArgument do + @cmd.handle_options %W[--certificate #{nonexistent}] + end + + assert_equal "invalid argument: --certificate #{nonexistent}: does not exist", + e.message + + bad = File.join @tempdir, 'bad' + FileUtils.touch bad + + e = assert_raises OptionParser::InvalidArgument do + @cmd.handle_options %W[--certificate #{bad}] + end + + assert_equal "invalid argument: " + + "--certificate #{bad}: invalid X509 certificate", + e.message + end + + def test_handle_options_key_bad + nonexistent = File.join @tempdir, 'nonexistent' + e = assert_raises OptionParser::InvalidArgument do + @cmd.handle_options %W[--private-key #{nonexistent}] + end + + assert_equal "invalid argument: " + + "--private-key #{nonexistent}: does not exist", + e.message + + bad = File.join @tempdir, 'bad' + FileUtils.touch bad + + e = assert_raises OptionParser::InvalidArgument do + @cmd.handle_options %W[--private-key #{bad}] + end + + assert_equal "invalid argument: --private-key #{bad}: invalid RSA key", + e.message + + e = assert_raises OptionParser::InvalidArgument do + @cmd.handle_options %W[--private-key #{PUBLIC_KEY_FILE}] + end + + assert_equal "invalid argument: " + + "--private-key #{PUBLIC_KEY_FILE}: private key not found", + e.message + end + + def test_handle_options_sign + @cmd.handle_options %W[ + --private-key #{ALTERNATE_KEY_FILE} + --private-key #{PRIVATE_KEY_FILE} + + --certificate #{ALTERNATE_CERT_FILE} + --certificate #{PUBLIC_CERT_FILE} + + --sign #{ALTERNATE_CERT_FILE} + --sign #{CHILD_CERT_FILE} + ] + + assert_equal PRIVATE_KEY.to_pem, @cmd.options[:key].to_pem + assert_equal PUBLIC_CERT.to_pem, @cmd.options[:issuer_cert].to_pem + + assert_equal [ALTERNATE_CERT_FILE, CHILD_CERT_FILE], @cmd.options[:sign] + end + + def test_handle_options_sign_encrypted_key + @cmd.handle_options %W[ + --private-key #{ALTERNATE_KEY_FILE} + --private-key #{ENCRYPTED_PRIVATE_KEY_PATH} + + --certificate #{ALTERNATE_CERT_FILE} + --certificate #{PUBLIC_CERT_FILE} + + --sign #{ALTERNATE_CERT_FILE} + --sign #{CHILD_CERT_FILE} + ] + + assert_equal ENCRYPTED_PRIVATE_KEY.to_pem, @cmd.options[:key].to_pem + assert_equal PUBLIC_CERT.to_pem, @cmd.options[:issuer_cert].to_pem + + assert_equal [ALTERNATE_CERT_FILE, CHILD_CERT_FILE], @cmd.options[:sign] + end + + def test_handle_options_sign_nonexistent + nonexistent = File.join @tempdir, 'nonexistent' + e = assert_raises OptionParser::InvalidArgument do + @cmd.handle_options %W[ + --private-key #{ALTERNATE_KEY_FILE} + + --certificate #{ALTERNATE_CERT_FILE} + + --sign #{nonexistent} + ] + end + + assert_equal "invalid argument: --sign #{nonexistent}: does not exist", + e.message + end + +end if defined?(OpenSSL::SSL) + -- cgit v1.2.3