aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenny Shen <jenny.shen@shopify.com>2023-07-20 01:42:58 -0400
committergit <svn-admin@ruby-lang.org>2023-07-28 16:08:10 +0000
commitafca1a31d05f3334342628a93d4d796c95e5f5fe (patch)
treef25bfee9a83ff3c2f7e3389b1b446e2e51518905
parent3954a87d65f004e5148597ffa927dc7b9eef6fb8 (diff)
downloadruby-afca1a31d05f3334342628a93d4d796c95e5f5fe.tar.gz
[rubygems/rubygems] Create MockServer object to test WebAuthn logic to prevent real TCPServers from being created and be leaked into other tests
https://github.com/rubygems/rubygems/commit/96d6cb33a2
-rw-r--r--test/rubygems/multifactor_auth_utilities.rb (renamed from test/rubygems/multifactor_auth_fetcher.rb)35
-rw-r--r--test/rubygems/test_gem_commands_owner_command.rb38
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb32
-rw-r--r--test/rubygems/test_gem_commands_yank_command.rb30
-rw-r--r--test/rubygems/test_gem_gemcutter_utilities.rb30
5 files changed, 78 insertions, 87 deletions
diff --git a/test/rubygems/multifactor_auth_fetcher.rb b/test/rubygems/multifactor_auth_utilities.rb
index e90a01c5ba..1133131a76 100644
--- a/test/rubygems/multifactor_auth_fetcher.rb
+++ b/test/rubygems/multifactor_auth_utilities.rb
@@ -74,3 +74,38 @@ class Gem::MultifactorAuthFetcher < Gem::FakeFetcher
"#{@webauthn_url}?port=#{port}"
end
end
+
+##
+# The MockTCPServer for use in tests or to avoid real TCPServer instances to be created
+# when testing code related to the WebAuthn listener.
+#
+# Example:
+#
+# server = Gem::MockTCPServer
+# port = server.addr[1].to_s
+#
+# # this mocks waiting for a request by calling sleep
+# server.accept
+#
+# # this mocks the server closing
+# server.close
+
+class Gem::MockTCPServer
+ attr_reader :port
+
+ def initialize(port = 5678)
+ @port = port
+ end
+
+ def close
+ true
+ end
+
+ def addr
+ ["AF_INET6", @port, "::", "::"]
+ end
+
+ def accept
+ sleep
+ end
+end
diff --git a/test/rubygems/test_gem_commands_owner_command.rb b/test/rubygems/test_gem_commands_owner_command.rb
index d737506ad2..d35232df7e 100644
--- a/test/rubygems/test_gem_commands_owner_command.rb
+++ b/test/rubygems/test_gem_commands_owner_command.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require_relative "helper"
-require_relative "multifactor_auth_fetcher"
+require_relative "multifactor_auth_utilities"
require "rubygems/commands/owner_command"
class TestGemCommandsOwnerCommand < Gem::TestCase
@@ -358,8 +358,7 @@ EOF
def test_with_webauthn_enabled_success
response_success = "Owner added successfully."
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@stub_fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems/freewill/owners", response_success)
@stub_fetcher.respond_with_webauthn_url
@@ -370,11 +369,11 @@ EOF
@cmd.add_owners("freewill", ["user-new1@example.com"])
end
end
- ensure
- server.close
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(port)} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
+ assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
assert_match response_success, @stub_ui.output
@@ -382,8 +381,7 @@ EOF
def test_with_webauthn_enabled_failure
response_success = "Owner added successfully."
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
error = Gem::WebauthnVerificationError.new("Something went wrong")
@stub_fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems/freewill/owners", response_success)
@@ -395,12 +393,12 @@ EOF
@cmd.add_owners("freewill", ["user-new1@example.com"])
end
end
- ensure
- server.close
end
assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(port)} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
+ assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @stub_ui.error
refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
refute_match response_success, @stub_ui.output
@@ -408,8 +406,7 @@ EOF
def test_with_webauthn_enabled_success_with_polling
response_success = "Owner added successfully."
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@stub_fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems/freewill/owners", response_success)
@stub_fetcher.respond_with_webauthn_url
@@ -419,12 +416,10 @@ EOF
use_ui @stub_ui do
@cmd.add_owners("freewill", ["user-new1@example.com"])
end
- ensure
- server.close
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(port)} to authenticate " \
- "via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
"command with the `--otp [your_code]` option.", @stub_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
@@ -433,8 +428,7 @@ EOF
def test_with_webauthn_enabled_failure_with_polling
response_success = "Owner added successfully."
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@stub_fetcher.respond_with_require_otp(
"#{Gem.host}/api/v1/gems/freewill/owners",
@@ -447,13 +441,11 @@ EOF
use_ui @stub_ui do
@cmd.add_owners("freewill", ["user-new1@example.com"])
end
- ensure
- server.close
end
assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(port)} to authenticate " \
- "via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
"command with the `--otp [your_code]` option.", @stub_ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
"or been used already.", @stub_ui.error
diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb
index 1f003f6ac6..bb0363da1a 100644
--- a/test/rubygems/test_gem_commands_push_command.rb
+++ b/test/rubygems/test_gem_commands_push_command.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require_relative "helper"
-require_relative "multifactor_auth_fetcher"
+require_relative "multifactor_auth_utilities"
require "rubygems/commands/push_command"
require "rubygems/config_file"
@@ -423,8 +423,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
def test_with_webauthn_enabled_success
response_success = "Successfully registered gem: freewill (1.0.0)"
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
@fetcher.respond_with_webauthn_url
@@ -435,11 +434,9 @@ class TestGemCommandsPushCommand < Gem::TestCase
@cmd.send_gem(@path)
end
end
- ensure
- server.close
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
@@ -449,8 +446,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
def test_with_webauthn_enabled_failure
response_success = "Successfully registered gem: freewill (1.0.0)"
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
error = Gem::WebauthnVerificationError.new("Something went wrong")
@fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
@@ -463,14 +459,12 @@ class TestGemCommandsPushCommand < Gem::TestCase
@cmd.send_gem(@path)
end
end
- ensure
- server.close
end
end
assert_equal 1, error.exit_code
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error
@@ -480,8 +474,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
def test_with_webauthn_enabled_success_with_polling
response_success = "Successfully registered gem: freewill (1.0.0)"
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
@fetcher.respond_with_webauthn_url
@@ -491,11 +484,9 @@ class TestGemCommandsPushCommand < Gem::TestCase
use_ui @ui do
@cmd.send_gem(@path)
end
- ensure
- server.close
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
@@ -505,8 +496,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
def test_with_webauthn_enabled_failure_with_polling
response_success = "Successfully registered gem: freewill (1.0.0)"
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
@fetcher.respond_with_webauthn_url
@@ -517,15 +507,13 @@ class TestGemCommandsPushCommand < Gem::TestCase
use_ui @ui do
@cmd.send_gem(@path)
end
- ensure
- server.close
end
end
assert_equal 1, error.exit_code
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} to authenticate " \
- "via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
"command with the `--otp [your_code]` option.", @ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
"or been used already.", @ui.error
diff --git a/test/rubygems/test_gem_commands_yank_command.rb b/test/rubygems/test_gem_commands_yank_command.rb
index dcd7ba1a83..bfa0d6421f 100644
--- a/test/rubygems/test_gem_commands_yank_command.rb
+++ b/test/rubygems/test_gem_commands_yank_command.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require_relative "helper"
-require_relative "multifactor_auth_fetcher"
+require_relative "multifactor_auth_utilities"
require "rubygems/commands/yank_command"
class TestGemCommandsYankCommand < Gem::TestCase
@@ -113,8 +113,7 @@ class TestGemCommandsYankCommand < Gem::TestCase
end
def test_with_webauthn_enabled_success
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp("http://example/api/v1/gems/yank", "Successfully yanked")
@fetcher.respond_with_webauthn_url
@@ -129,12 +128,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
@cmd.execute
end
end
- ensure
- server.close
end
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
@@ -143,8 +140,7 @@ class TestGemCommandsYankCommand < Gem::TestCase
end
def test_with_webauthn_enabled_failure
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
error = Gem::WebauthnVerificationError.new("Something went wrong")
@fetcher.respond_with_require_otp("http://example/api/v1/gems/yank", "Successfully yanked")
@@ -161,15 +157,13 @@ class TestGemCommandsYankCommand < Gem::TestCase
@cmd.execute
end
end
- ensure
- server.close
end
end
assert_equal 1, error.exit_code
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error
@@ -178,8 +172,7 @@ class TestGemCommandsYankCommand < Gem::TestCase
end
def test_with_webauthn_enabled_success_with_polling
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp("http://example/api/v1/gems/yank", "Successfully yanked")
@fetcher.respond_with_webauthn_url
@@ -193,12 +186,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
use_ui @ui do
@cmd.execute
end
- ensure
- server.close
end
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
@@ -207,8 +198,7 @@ class TestGemCommandsYankCommand < Gem::TestCase
end
def test_with_webauthn_enabled_failure_with_polling
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp("http://example/api/v1/gems/yank", "Successfully yanked")
@fetcher.respond_with_webauthn_url
@@ -223,15 +213,13 @@ class TestGemCommandsYankCommand < Gem::TestCase
use_ui @ui do
@cmd.execute
end
- ensure
- server.close
end
end
assert_equal 1, error.exit_code
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb
index 8282eb641b..6bd6cfd979 100644
--- a/test/rubygems/test_gem_gemcutter_utilities.rb
+++ b/test/rubygems/test_gem_gemcutter_utilities.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require_relative "helper"
-require_relative "multifactor_auth_fetcher"
+require_relative "multifactor_auth_utilities"
require "rubygems"
require "rubygems/command"
require "rubygems/gemcutter_utilities"
@@ -223,8 +223,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
def test_sign_in_with_webauthn_enabled
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp
@fetcher.respond_with_webauthn_url
@@ -232,11 +231,9 @@ class TestGemGemcutterUtilities < Gem::TestCase
Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:otp] = "Uvh6T57tkWuUnWYo" }) do
util_sign_in
end
- ensure
- server.close
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
@@ -244,8 +241,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
def test_sign_in_with_webauthn_enabled_with_error
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
error = Gem::WebauthnVerificationError.new("Something went wrong")
@fetcher.respond_with_require_otp
@@ -255,13 +251,11 @@ class TestGemGemcutterUtilities < Gem::TestCase
Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:error] = error }) do
util_sign_in
end
- ensure
- server.close
end
end
assert_equal 1, error.exit_code
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @sign_in_ui.error
@@ -270,19 +264,16 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
def test_sign_in_with_webauthn_enabled_with_polling
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp
@fetcher.respond_with_webauthn_url
@fetcher.respond_with_webauthn_polling("Uvh6T57tkWuUnWYo")
TCPServer.stub(:new, server) do
util_sign_in
- ensure
- server.close
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
@@ -290,8 +281,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
def test_sign_in_with_webauthn_enabled_with_polling_failure
- port = 5678
- server = TCPServer.new(port)
+ server = Gem::MockTCPServer.new
@fetcher.respond_with_require_otp
@fetcher.respond_with_webauthn_url
@fetcher.respond_with_webauthn_polling_failure
@@ -299,12 +289,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
assert_raise Gem::MockGemUi::TermError do
TCPServer.stub(:new, server) do
util_sign_in
- ensure
- server.close
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
assert_match "ERROR: Security device verification failed: " \