From 6b973a956550c3703395570deb94dcedc39766d9 Mon Sep 17 00:00:00 2001 From: Lewis Marshall Date: Thu, 26 Feb 2015 00:55:41 +0000 Subject: [PATCH 1/3] Refactor nginx tests Signed-off-by: Lewis Marshall --- tests/unit/nginx-vhosts.bats | 93 ++++++++++++++++++------------------ tests/unit/test_helper.bash | 4 ++ 2 files changed, 50 insertions(+), 47 deletions(-) diff --git a/tests/unit/nginx-vhosts.bats b/tests/unit/nginx-vhosts.bats index 8c9660a48..968400090 100644 --- a/tests/unit/nginx-vhosts.bats +++ b/tests/unit/nginx-vhosts.bats @@ -15,6 +15,44 @@ teardown() { disable_tls_wildcard } +assert_ssl_domain() { + local domain=$1 + assert_app_domain "${domain}" + assert_http_redirect "http://${domain}" "https://${domain}/" + assert_http_success "https://${domain}" +} + +assert_nonssl_domain() { + local domain=$1 + assert_app_domain "${domain}" + assert_http_success "http://${domain}" +} + +assert_app_domain() { + local domain=$1 + run /bin/bash -c "dokku domains $TEST_APP | grep -xF ${domain}" + echo "output: "$output + echo "status: "$status + assert_output "${domain}" +} + +assert_http_redirect() { + local from=$1 + local to=$2 + run curl -kSso /dev/null -w "%{redirect_url}" "${from}" + echo "output: "$output + echo "status: "$status + assert_output "${to}" +} + +assert_http_success() { + local url=$1 + run curl -kSso /dev/null -w "%{http_code}" "${url}" + echo "output: "$output + echo "status: "$status + assert_output "200" +} + @test "nginx (no server tokens)" { deploy_app run /bin/bash -c "curl -s -D - $(dokku url $TEST_APP) -o /dev/null | egrep '^Server' | egrep '[0-9]+'" @@ -24,70 +62,31 @@ teardown() { } @test "nginx:build-config (wildcard SSL)" { - destroy_app setup_test_tls_wildcard - create_app - run dokku domains:add $TEST_APP wildcard.dokku.me - echo "output: "$output - echo "status: "$status - assert_success + add_domain "wildcard.dokku.me" deploy_app - run bash -c "response=\"$(curl -LkSs wildcard.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" - echo "output: "$output - echo "status: "$status - assert_success + assert_ssl_domain "wildcard.dokku.me" } @test "nginx:build-config (with SSL CN mismatch)" { setup_test_tls deploy_app - run /bin/bash -c "dokku domains $TEST_APP | egrep ^node-js-app\.dokku\.me$" - echo "output: "$output - echo "status: "$status - assert_output "node-js-app.dokku.me" - run bash -c "response=\"$(curl -LkSs node-js-app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" - echo "output: "$output - echo "status: "$status - assert_success + assert_ssl_domain "node-js-app.dokku.me" } @test "nginx:build-config (with SSL and Multiple SANs)" { setup_test_tls_with_sans deploy_app - run /bin/bash -c "dokku domains $TEST_APP | egrep ^test\.dokku\.me$" - echo "output: "$output - echo "status: "$status - assert_output "test.dokku.me" - run /bin/bash -c "dokku domains $TEST_APP | grep ^www\.test\.dokku\.me$" - echo "output: "$output - echo "status: "$status - assert_output "www.test.dokku.me" - run bash -c "response=\"$(curl -LkSs test.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" - echo "output: "$output - echo "status: "$status - assert_success - run bash -c "response=\"$(curl -LkSs www.test.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" - echo "output: "$output - echo "status: "$status - assert_success - run bash -c "response=\"$(curl -LkSs www.test.app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" - echo "output: "$output - echo "status: "$status - assert_success + assert_ssl_domain "test.dokku.me" + assert_ssl_domain "www.test.dokku.me" + assert_ssl_domain "www.test.app.dokku.me" } @test "nginx:build-config (no global VHOST and domains:add)" { destroy_app rm "$DOKKU_ROOT/VHOST" create_app - run dokku domains:add $TEST_APP www.test.app.dokku.me - echo "output: "$output - echo "status: "$status - assert_success + add_domain "www.test.app.dokku.me" deploy_app - sleep 5 # wait for nginx to reload - run bash -c "response=\"$(curl -s -S www.test.app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" - echo "output: "$output - echo "status: "$status - assert_success + assert_nonssl_domain "www.test.app.dokku.me" } diff --git a/tests/unit/test_helper.bash b/tests/unit/test_helper.bash index 08b05c45a..08d16f8ae 100644 --- a/tests/unit/test_helper.bash +++ b/tests/unit/test_helper.bash @@ -92,6 +92,10 @@ destroy_app() { echo $TEST_APP | dokku apps:destroy $TEST_APP } +add_domain() { + dokku domains:add $TEST_APP $1 +} + deploy_app() { APP_TYPE="$1"; APP_TYPE=${APP_TYPE:="nodejs-express"} TMP=$(mktemp -d -t "$TARGET.XXXXX") From a4d79e2de99b67f9709c324fe99c0ca1fb605911 Mon Sep 17 00:00:00 2001 From: Lewis Marshall Date: Thu, 26 Feb 2015 00:48:21 +0000 Subject: [PATCH 2/3] Support multiple domains using a wildcard TLS certificate Previous to this change, each TLS domain would be written to nginx.conf using the nginx.ssl.conf template (lines 69-73) but with an empty "server_name" directive (because NOSSL_SERVER_NAME was not set). This would then become irrelevant because nginx.conf would get truncated on line 88, and a single parsing of the template would then be written to nginx.conf on line 89, meaning only the last TLS domain would be set up to actually use TLS. This patch changes this behaviour so that all TLS domains get added to nginx.conf using the nginx.ssl.conf template (which includes redirecting HTTP -> HTTPS), and all non-TLS domains get added using the nginx.conf template, so do not get redirected to a TLS domain. Signed-off-by: Lewis Marshall --- plugins/nginx-vhosts/commands | 27 ++++++++++++++++----------- tests/unit/nginx-vhosts.bats | 6 ++++-- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index a75745871..98a5a2e43 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -45,10 +45,9 @@ EOF SSL_DIRECTIVES="" fi - NGINX_CONF="$PLUGIN_PATH/nginx-vhosts/templates/nginx.conf" + NGINX_CONF=$(mktemp -t "nginx.conf.XXXXXX") SCHEME="http" if [[ -n "$SSL_INUSE" ]]; then - NGINX_CONF="$PLUGIN_PATH/nginx-vhosts/templates/nginx.ssl.conf" SCHEME="https" SSL_HOSTNAME=$(openssl x509 -in $SSL_INUSE/server.crt -noout -subject | tr '/' '\n' | grep CN= | cut -c4-) @@ -66,28 +65,34 @@ EOF SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$|^${SSL_HOSTNAME_ALT_REGEX}$" $VHOST_PATH || exit 0) NONSSL_VHOSTS=$(egrep -v "^${SSL_HOSTNAME}$|^${SSL_HOSTNAME_ALT}$" $VHOST_PATH || exit 0) + NGINX_TEMPLATE="$PLUGIN_PATH/nginx-vhosts/templates/nginx.ssl.conf" while read line; do dokku_log_info1 "Configuring SSL for $line..." SSL_SERVER_NAME=$line - eval "cat <<< \"$(< $NGINX_CONF)\" >> $DOKKU_ROOT/$APP/nginx.conf" + NOSSL_SERVER_NAME=$line + eval "cat <<< \"$(< $NGINX_TEMPLATE)\" >> $NGINX_CONF" done <<< "$SSL_VHOSTS" fi + NOSSL_SERVER_NAME=$(echo $NONSSL_VHOSTS | tr '\n' ' ') APP_NGINX_TEMPLATE="$DOKKU_ROOT/$APP/nginx.conf.template" if [[ -f $APP_NGINX_TEMPLATE ]]; then dokku_log_info1 "Overriding default nginx.conf with detected nginx.conf.template" - NGINX_CONF=$APP_NGINX_TEMPLATE + eval "cat <<< \"$(< $APP_NGINX_TEMPLATE)\" > $NGINX_CONF" + elif [[ -n "$NONSSL_VHOSTS" ]]; then + xargs -i echo "-----> Configuring {}..." <<< "$NONSSL_VHOSTS" + NGINX_TEMPLATE="$PLUGIN_PATH/nginx-vhosts/templates/nginx.conf" + eval "cat <<< \"$(< $NGINX_TEMPLATE)\" >> $NGINX_CONF" fi - xargs -i echo "-----> Configuring {}..." < $VHOST_PATH - # Include SSL_VHOSTS so we can redirect http to https on that hostname as well - NOSSL_SERVER_NAME=$(echo $NONSSL_VHOSTS $SSL_VHOSTS| tr '\n' ' ') + if [[ -n "$DOKKU_APP_LISTEN_PORT" ]] && [[ -n "$DOKKU_APP_LISTEN_IP" ]]; then + echo "upstream $APP { server $DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT; }" >> $NGINX_CONF + fi + + dokku_log_info1 "Creating $SCHEME nginx.conf" + mv $NGINX_CONF "$DOKKU_ROOT/$APP/nginx.conf" if [[ -n "$DOKKU_APP_LISTEN_PORT" ]] && [[ -n "$DOKKU_APP_LISTEN_IP" ]]; then - dokku_log_info1 "Creating $SCHEME nginx.conf" - echo "upstream $APP { server $DOKKU_APP_LISTEN_IP:$DOKKU_APP_LISTEN_PORT; }" > $DOKKU_ROOT/$APP/nginx.conf - eval "cat <<< \"$(< $NGINX_CONF)\" >> $DOKKU_ROOT/$APP/nginx.conf" - dokku_log_info1 "Running nginx-pre-reload" pluginhook nginx-pre-reload $APP $DOKKU_APP_LISTEN_PORT $DOKKU_APP_LISTEN_IP diff --git a/tests/unit/nginx-vhosts.bats b/tests/unit/nginx-vhosts.bats index 968400090..8855c45ee 100644 --- a/tests/unit/nginx-vhosts.bats +++ b/tests/unit/nginx-vhosts.bats @@ -63,9 +63,11 @@ assert_http_success() { @test "nginx:build-config (wildcard SSL)" { setup_test_tls_wildcard - add_domain "wildcard.dokku.me" + add_domain "wildcard1.dokku.me" + add_domain "wildcard2.dokku.me" deploy_app - assert_ssl_domain "wildcard.dokku.me" + assert_ssl_domain "wildcard1.dokku.me" + assert_ssl_domain "wildcard2.dokku.me" } @test "nginx:build-config (with SSL CN mismatch)" { From 9202f110ab0fed589f909d690596e8c0065a3edc Mon Sep 17 00:00:00 2001 From: Lewis Marshall Date: Sun, 8 Mar 2015 21:24:09 +0000 Subject: [PATCH 3/3] Fix wildcard TLS domain detection As per RFC 2818 [0], a CN of *.dokku.me will only match direct subdomains of dokku.me, not sub-subdomains like www.test.dokku.me, but Dokku currently enables TLS for subdomains of all levels. I have changed the regex from .*\.dokku\.me to [^.]*\.dokku\.me so TLS is only enabled for direct subdomains. [0] - http://tools.ietf.org/html/rfc2818#section-3.1 Signed-off-by: Lewis Marshall --- plugins/nginx-vhosts/commands | 4 ++-- tests/unit/nginx-vhosts.bats | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index 98a5a2e43..e7fa81a13 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -52,13 +52,13 @@ EOF SSL_HOSTNAME=$(openssl x509 -in $SSL_INUSE/server.crt -noout -subject | tr '/' '\n' | grep CN= | cut -c4-) if [[ -n "$SSL_HOSTNAME" ]]; then - SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | sed 's|\.|\\.|g' | sed 's/\*/\.\*/g') + SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g') [[ -z "$(egrep "^${SSL_HOSTNAME_REGEX}$" $VHOST_PATH)" ]] && echo "$SSL_HOSTNAME" >> $VHOST_PATH fi SSL_HOSTNAME_ALT=$(openssl x509 -in $SSL_INUSE/server.crt -noout -text | grep --after-context=1 '509v3 Subject Alternative Name:' | tail -n 1 | sed -e "s/[[:space:]]*DNS://g" | tr ',' '\n' || true) if [[ -n "$SSL_HOSTNAME_ALT" ]]; then - SSL_HOSTNAME_ALT_REGEX=$(echo "$SSL_HOSTNAME_ALT" | sed 's|\.|\\.|g' | sed 's/\*/\.\*/g') + SSL_HOSTNAME_ALT_REGEX=$(echo "$SSL_HOSTNAME_ALT" | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g') [[ -z "$(egrep "^${SSL_HOSTNAME_ALT_REGEX}$" $VHOST_PATH)" ]] && echo "$SSL_HOSTNAME_ALT" >> $VHOST_PATH fi diff --git a/tests/unit/nginx-vhosts.bats b/tests/unit/nginx-vhosts.bats index 8855c45ee..f3440cc9f 100644 --- a/tests/unit/nginx-vhosts.bats +++ b/tests/unit/nginx-vhosts.bats @@ -65,9 +65,11 @@ assert_http_success() { setup_test_tls_wildcard add_domain "wildcard1.dokku.me" add_domain "wildcard2.dokku.me" + add_domain "www.test.dokku.me" deploy_app assert_ssl_domain "wildcard1.dokku.me" assert_ssl_domain "wildcard2.dokku.me" + assert_nonssl_domain "www.test.dokku.me" } @test "nginx:build-config (with SSL CN mismatch)" {