mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #43882 from rails/rm-allow-ip-with-port
Allow IPs with port in the HostAuthorization middleware
This commit is contained in:
commit
334dfef1f5
2 changed files with 123 additions and 9 deletions
|
@ -17,7 +17,15 @@ module ActionDispatch
|
|||
# if +config.consider_all_requests_local+ is set to true, otherwise the body is empty.
|
||||
class HostAuthorization
|
||||
ALLOWED_HOSTS_IN_DEVELOPMENT = [".localhost", IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0")]
|
||||
PORT_REGEX = /(?::\d+)?/.freeze
|
||||
PORT_REGEX = /(?::\d+)/ # :nodoc:
|
||||
IPV4_HOSTNAME = /(?<host>\d+\.\d+\.\d+\.\d+)#{PORT_REGEX}?/ # :nodoc:
|
||||
IPV6_HOSTNAME = /(?<host>[a-f0-9]*:[a-f0-9.:]+)/i # :nodoc:
|
||||
IPV6_HOSTNAME_WITH_PORT = /\[#{IPV6_HOSTNAME}\]#{PORT_REGEX}/i # :nodoc:
|
||||
VALID_IP_HOSTNAME = Regexp.union( # :nodoc:
|
||||
/\A#{IPV4_HOSTNAME}\z/,
|
||||
/\A#{IPV6_HOSTNAME}\z/,
|
||||
/\A#{IPV6_HOSTNAME_WITH_PORT}\z/,
|
||||
)
|
||||
|
||||
class Permissions # :nodoc:
|
||||
def initialize(hosts)
|
||||
|
@ -30,11 +38,17 @@ module ActionDispatch
|
|||
|
||||
def allows?(host)
|
||||
@hosts.any? do |allowed|
|
||||
allowed === host
|
||||
rescue
|
||||
# IPAddr#=== raises an error if you give it a hostname instead of
|
||||
# IP. Treat similar errors as blocked access.
|
||||
false
|
||||
if allowed.is_a?(IPAddr)
|
||||
begin
|
||||
allowed === extract_hostname(host)
|
||||
rescue
|
||||
# IPAddr#=== raises an error if you give it a hostname instead of
|
||||
# IP. Treat similar errors as blocked access.
|
||||
false
|
||||
end
|
||||
else
|
||||
allowed === host
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -50,16 +64,20 @@ module ActionDispatch
|
|||
end
|
||||
|
||||
def sanitize_regexp(host)
|
||||
/\A#{host}#{PORT_REGEX}\z/
|
||||
/\A#{host}#{PORT_REGEX}?\z/
|
||||
end
|
||||
|
||||
def sanitize_string(host)
|
||||
if host.start_with?(".")
|
||||
/\A([a-z0-9-]+\.)?#{Regexp.escape(host[1..-1])}#{PORT_REGEX}\z/i
|
||||
/\A([a-z0-9-]+\.)?#{Regexp.escape(host[1..-1])}#{PORT_REGEX}?\z/i
|
||||
else
|
||||
/\A#{Regexp.escape host}#{PORT_REGEX}\z/i
|
||||
/\A#{Regexp.escape host}#{PORT_REGEX}?\z/i
|
||||
end
|
||||
end
|
||||
|
||||
def extract_hostname(host)
|
||||
host.slice(VALID_IP_HOSTNAME, "host") || host
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultResponseApp # :nodoc:
|
||||
|
|
|
@ -166,6 +166,102 @@ class HostAuthorizationTest < ActionDispatch::IntegrationTest
|
|||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "localhost using IPV4 works in dev" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT)
|
||||
|
||||
get "/", env: {
|
||||
"HOST" => "127.0.0.1",
|
||||
"action_dispatch.show_detailed_exceptions" => true
|
||||
}
|
||||
|
||||
assert_response :ok
|
||||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "localhost using IPV4 with port works in dev" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT)
|
||||
|
||||
get "/", env: {
|
||||
"HOST" => "127.0.0.1:3000",
|
||||
"action_dispatch.show_detailed_exceptions" => true
|
||||
}
|
||||
|
||||
assert_response :ok
|
||||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "localhost using IPV4 binding in all addresses works in dev" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT)
|
||||
|
||||
get "/", env: {
|
||||
"HOST" => "0.0.0.0",
|
||||
"action_dispatch.show_detailed_exceptions" => true
|
||||
}
|
||||
|
||||
assert_response :ok
|
||||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "localhost using IPV4 with port binding in all addresses works in dev" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT)
|
||||
|
||||
get "/", env: {
|
||||
"HOST" => "0.0.0.0:3000",
|
||||
"action_dispatch.show_detailed_exceptions" => true
|
||||
}
|
||||
|
||||
assert_response :ok
|
||||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "localhost using IPV6 works in dev" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT)
|
||||
|
||||
get "/", env: {
|
||||
"HOST" => "::1",
|
||||
"action_dispatch.show_detailed_exceptions" => true
|
||||
}
|
||||
|
||||
assert_response :ok
|
||||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "localhost using IPV6 with port works in dev" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT)
|
||||
|
||||
get "/", env: {
|
||||
"HOST" => "[::1]:3000",
|
||||
"action_dispatch.show_detailed_exceptions" => true
|
||||
}
|
||||
|
||||
assert_response :ok
|
||||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "localhost using IPV6 binding in all addresses works in dev" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT)
|
||||
|
||||
get "/", env: {
|
||||
"HOST" => "::",
|
||||
"action_dispatch.show_detailed_exceptions" => true
|
||||
}
|
||||
|
||||
assert_response :ok
|
||||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "localhost using IPV6 with port binding in all addresses works in dev" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT)
|
||||
|
||||
get "/", env: {
|
||||
"HOST" => "[::]:3000",
|
||||
"action_dispatch.show_detailed_exceptions" => true
|
||||
}
|
||||
|
||||
assert_response :ok
|
||||
assert_match "Success", response.body
|
||||
end
|
||||
|
||||
test "hosts with port works" do
|
||||
@app = ActionDispatch::HostAuthorization.new(App, ["host.test"])
|
||||
|
||||
|
|
Loading…
Reference in a new issue