1
0
mirror of https://github.com/nginx-proxy/nginx-proxy synced 2024-09-25 13:40:47 +02:00

Merge pull request #587 from kamermans/feature_x_forwarded_port

Added X-Forwarded-Port and proxy headers tests
This commit is contained in:
Jason Wilder 2016-12-02 11:17:44 -07:00 committed by GitHub
commit e60fefad27
8 changed files with 185 additions and 12 deletions

View File

@ -223,6 +223,7 @@ proxy_set_header Connection $proxy_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";

View File

@ -24,6 +24,13 @@ map $http_x_forwarded_proto $proxy_x_forwarded_proto {
'' $scheme;
}
# If we receive X-Forwarded-Port, pass it through; otherwise, pass along the
# server port the client connected to
map $http_x_forwarded_port $proxy_x_forwarded_port {
default $http_x_forwarded_port;
'' $server_port;
}
# If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any
# Connection header that may have been passed to this server
map $http_upgrade $proxy_connection {
@ -51,6 +58,7 @@ proxy_set_header Connection $proxy_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
# Mitigate httpoxy attack (see README for details)
proxy_set_header Proxy "";

View File

@ -111,13 +111,13 @@ function assert_nginxproxy_behaves {
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# Querying the proxy with Host header → 200
run curl_container $container /data --header "Host: web1.bats"
run curl_container $container /port --header "Host: web1.bats"
assert_output "answer from port 81"
run curl_container $container /data --header "Host: web2.bats"
run curl_container $container /port --header "Host: web2.bats"
assert_output "answer from port 82"
# Querying the proxy with unknown Host header → 503
run curl_container $container /data --header "Host: webFOO.bats" --head
run curl_container $container /port --header "Host: webFOO.bats" --head
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
}

139
test/headers.bats Normal file
View File

@ -0,0 +1,139 @@
#!/usr/bin/env bats
load test_helpers
SUT_CONTAINER=bats-nginx-proxy-${TEST_FILE}
function setup {
# make sure to stop any web container before each test so we don't
# have any unexpected container running with VIRTUAL_HOST or VIRUTAL_PORT set
stop_bats_containers web
}
@test "[$TEST_FILE] start a nginx-proxy container" {
# GIVEN
run nginxproxy $SUT_CONTAINER -v /var/run/docker.sock:/tmp/docker.sock:ro
assert_success
docker_wait_for_log $SUT_CONTAINER 9 "Watching docker events"
}
@test "[$TEST_FILE] nginx-proxy passes arbitrary header" {
# WHEN
prepare_web_container bats-host-1 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-1
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "Foo: Bar" -H "Host: web.bats"
assert_output -l 'Foo: Bar'
}
##### Testing the handling of X-Forwarded-For #####
@test "[$TEST_FILE] nginx-proxy generates X-Forwarded-For" {
# WHEN
prepare_web_container bats-host-2 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-2
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "Host: web.bats"
assert_output -p 'X-Forwarded-For:'
}
@test "[$TEST_FILE] nginx-proxy passes X-Forwarded-For" {
# WHEN
prepare_web_container bats-host-3 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-3
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "X-Forwarded-For: 1.2.3.4" -H "Host: web.bats"
assert_output -p 'X-Forwarded-For: 1.2.3.4, '
}
##### Testing the handling of X-Forwarded-Proto #####
@test "[$TEST_FILE] nginx-proxy generates X-Forwarded-Proto" {
# WHEN
prepare_web_container bats-host-4 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-4
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "Host: web.bats"
assert_output -l 'X-Forwarded-Proto: http'
}
@test "[$TEST_FILE] nginx-proxy passes X-Forwarded-Proto" {
# WHEN
prepare_web_container bats-host-5 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-5
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "X-Forwarded-Proto: https" -H "Host: web.bats"
assert_output -l 'X-Forwarded-Proto: https'
}
##### Testing the handling of X-Forwarded-Port #####
@test "[$TEST_FILE] nginx-proxy generates X-Forwarded-Port" {
# WHEN
prepare_web_container bats-host-6 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-6
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "Host: web.bats"
assert_output -l 'X-Forwarded-Port: 80'
}
@test "[$TEST_FILE] nginx-proxy passes X-Forwarded-Port" {
# WHEN
prepare_web_container bats-host-7 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-7
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "X-Forwarded-Port: 1234" -H "Host: web.bats"
assert_output -l 'X-Forwarded-Port: 1234'
}
##### Other headers
@test "[$TEST_FILE] nginx-proxy generates X-Real-IP" {
# WHEN
prepare_web_container bats-host-8 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-8
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "Host: web.bats"
assert_output -p 'X-Real-IP: '
}
@test "[$TEST_FILE] nginx-proxy passes Host" {
# WHEN
prepare_web_container bats-host-9 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-9
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "Host: web.bats"
assert_output -l 'Host: web.bats'
}
@test "[$TEST_FILE] nginx-proxy supresses Proxy for httpoxy protection" {
# WHEN
prepare_web_container bats-host-10 80 -e VIRTUAL_HOST=web.bats
dockergen_wait_for_event $SUT_CONTAINER start bats-host-10
sleep 1
# THEN
run curl_container $SUT_CONTAINER /headers -H "Proxy: tcp://foo.com" -H "Host: web.bats"
refute_output -l 'Proxy: tcp://foo.com'
}
@test "[$TEST_FILE] stop all bats containers" {
stop_bats_containers
}

View File

@ -26,15 +26,15 @@ function setup {
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# THEN querying the proxy with unknown Host header → 503
run curl_container $SUT_CONTAINER /data --header "Host: webFOO.bats" --head
run curl_container $SUT_CONTAINER /port --header "Host: webFOO.bats" --head
assert_output -l 0 $'HTTP/1.1 503 Service Temporarily Unavailable\r'
# THEN
run curl_container $SUT_CONTAINER /data --header 'Host: multiple-hosts-1-A.bats'
run curl_container $SUT_CONTAINER /port --header 'Host: multiple-hosts-1-A.bats'
assert_output "answer from port 80"
# THEN
run curl_container $SUT_CONTAINER /data --header 'Host: multiple-hosts-1-B.bats'
run curl_container $SUT_CONTAINER /port --header 'Host: multiple-hosts-1-B.bats'
assert_output "answer from port 80"
}

View File

@ -58,7 +58,7 @@ function setup {
# $1 port we are expecting an response from
function assert_response_is_from_port {
local -r port=$1
run curl_container $SUT_CONTAINER /data --header "Host: web.bats"
run curl_container $SUT_CONTAINER /port --header "Host: web.bats"
assert_output "answer from port $port"
}

View File

@ -124,6 +124,7 @@ function prepare_web_container {
--name $container_name \
$expose_option \
-w /var/www/ \
-v $DIR/web_helpers:/var/www:ro \
$options \
-e PYTHON_PORTS="$ports" \
python:3 bash -c "
@ -131,10 +132,7 @@ function prepare_web_container {
declare -a PIDS
for port in \$PYTHON_PORTS; do
echo starting a web server listening on port \$port;
mkdir /var/www/\$port
cd /var/www/\$port
echo \"answer from port \$port\" > data
python -m http.server \$port &
./webserver.py \$port &
PIDS+=(\$!)
done
wait \${PIDS[@]}
@ -146,7 +144,7 @@ function prepare_web_container {
# THEN querying directly port works
IFS=$' \t\n' # See https://github.com/sstephenson/bats/issues/89
for port in $ports; do
run retry 5 1s docker run --label bats-type="curl" appropriate/curl --silent --fail http://$(docker_ip $container_name):$port/data
run retry 5 1s docker run --label bats-type="curl" appropriate/curl --silent --fail http://$(docker_ip $container_name):$port/port
assert_output "answer from port $port"
done
}

27
test/web_helpers/webserver.py Executable file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
import os, sys
import http.server
import socketserver
class BatsHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
root = os.getcwd()
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
if self.path == "/headers":
self.wfile.write(self.headers.as_string().encode())
elif self.path == "/port":
response = "answer from port %s\n" % PORT
self.wfile.write(response.encode())
else:
self.wfile.write("No route for this path!\n".encode())
if __name__ == '__main__':
PORT = int(sys.argv[1])
socketserver.TCPServer.allow_reuse_address = True
httpd = socketserver.TCPServer(('0.0.0.0', PORT), BatsHandler)
httpd.serve_forever()