From 90e6fbcb49b8e0313574a3741a1ed3d21a44414a Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 2 Aug 2019 17:36:58 +0200 Subject: [PATCH 1/2] Use wildcard location configurations fix #561 --- app/functions.sh | 55 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/app/functions.sh b/app/functions.sh index 578f17ec..64ed07da 100644 --- a/app/functions.sh +++ b/app/functions.sh @@ -23,10 +23,61 @@ function check_nginx_proxy_container_run { fi } +function ascending_wildcard_locations { + # Given foo.bar.baz.example.com as argument, will output: + # - *.bar.baz.example.com + # - *.baz.example.com + # - *.example.com + local domain="${1:?}" + local first_label + regex="^[[:alnum:]_\-]+(\.[[:alpha:]]+)?$" + until [[ "$domain" =~ $regex ]]; do + first_label="${domain%%.*}" + domain="${domain/${first_label}./}" + echo "*.${domain}" + done +} + +function descending_wildcard_locations { + # Given foo.bar.baz.example.com as argument, will output: + # - foo.bar.baz.example.* + # - foo.bar.baz.* + # - foo.bar.* + # - foo.* + local domain="${1:?}" + local last_label + regex="^[[:alnum:]_\-]+$" + until [[ "$domain" =~ $regex ]]; do + last_label="${domain##*.}" + domain="${domain/.${last_label}/}" + echo "${domain}.*" + done +} + +function enumerate_wildcard_locations { + # Goes through ascending then descending wildcard locations for a given FQDN + local domain="${1:?}" + ascending_wildcard_locations "$domain" + descending_wildcard_locations "$domain" +} + function add_location_configuration { local domain="${1:-}" - # If no domain was passed or if the domain has no custom conf, use default instead - [[ -z "$domain" || ! -f "${VHOST_DIR}/${domain}" ]] && domain=default + local wildcard_domain + # If no domain was passed use default instead + [[ -z "$domain" ]] && domain='default' + + # If the domain does not have an exact matching location file, test the possible + # wildcard locations files. Use default is no location file is present at all. + if [[ ! -f "${VHOST_DIR}/${domain}" ]]; then + for wildcard_domain in $(enumerate_wildcard_locations "$domain"); do + if [[ -f "${VHOST_DIR}/${wildcard_domain}" ]]; then + domain="$wildcard_domain" + break + fi + domain='default' + done + fi if [[ -f "${VHOST_DIR}/${domain}" && -n $(sed -n "/$START_HEADER/,/$END_HEADER/p" "${VHOST_DIR}/${domain}") ]]; then # If the config file exist and already have the location configuration, end with exit code 0 From 308bd8f81c03e2094506050b737261980533e4a4 Mon Sep 17 00:00:00 2001 From: Nicolas Duchon Date: Fri, 2 Aug 2019 19:33:44 +0200 Subject: [PATCH 2/2] Add tests for wildcard locations --- .../location_config/expected-std-out.txt | 7 ++++ test/tests/location_config/run.sh | 41 ++++++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/test/tests/location_config/expected-std-out.txt b/test/tests/location_config/expected-std-out.txt index c90f71d1..1d979181 100644 --- a/test/tests/location_config/expected-std-out.txt +++ b/test/tests/location_config/expected-std-out.txt @@ -1 +1,8 @@ Started letsencrypt container for test location_config +*.bar.baz.example.com +*.baz.example.com +*.example.com +foo.bar.baz.example.* +foo.bar.baz.* +foo.bar.* +foo.* diff --git a/test/tests/location_config/run.sh b/test/tests/location_config/run.sh index fb466307..14e813d8 100755 --- a/test/tests/location_config/run.sh +++ b/test/tests/location_config/run.sh @@ -10,8 +10,10 @@ vhost_path='/etc/nginx/vhost.d' location_file="${TRAVIS_BUILD_DIR}/test/tests/location_config/le2.wtf" echo "$test_comment" > "$location_file" -# Create le1.wtf configuration file from inside the nginx container +# Create le1.wtf configuration file, *.le3.wtf and test.* from inside the nginx container docker exec "$NGINX_CONTAINER_NAME" sh -c "echo '### This is a test comment' > /etc/nginx/vhost.d/le1.wtf" +docker exec "$NGINX_CONTAINER_NAME" sh -c "echo '### This is a test comment' > /etc/nginx/vhost.d/\*.example.com" +docker exec "$NGINX_CONTAINER_NAME" sh -c "echo '### This is a test comment' > /etc/nginx/vhost.d/test.\*" # Zero the default configuration file. docker exec "$NGINX_CONTAINER_NAME" sh -c "echo '' > /etc/nginx/vhost.d/default" @@ -30,6 +32,8 @@ IFS=',' read -r -a domains <<< "$TEST_DOMAINS" function cleanup { # Cleanup the files created by this run of the test to avoid foiling following test(s). docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/vhost.d/le1.wtf' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/vhost.d/\*.example.com' + docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/vhost.d/test.\*' # Stop the LE container docker stop "$le_container_name" > /dev/null } @@ -51,6 +55,9 @@ function check_location { fi } +# check the wildcard location enumeration function +docker exec "$le_container_name" bash -c 'source /app/functions.sh; enumerate_wildcard_locations foo.bar.baz.example.com' + # default configuration file should be empty config_path="$vhost_path/default" if docker exec "$le_container_name" [ ! -s "$config_path" ]; then @@ -58,8 +65,8 @@ if docker exec "$le_container_name" [ ! -s "$config_path" ]; then docker exec "$le_container_name" cat "$config_path" fi -# le1.wtf and le2.wtf configuration files should only contains the test comment -for domain in "${domains[@]:0:2}"; do +# custom configuration files should only contains the test comment +for domain in "${domains[@]:0:2}" '*.example.com' 'test.*'; do config_path="$vhost_path/$domain" if check_location "$le_container_name" "$config_path"; then echo "Unexpected location configuration on $config_path at container startup:" @@ -99,6 +106,30 @@ for domain in "${domains[@]:0:2}"; do fi done +# Adding subdomain.example.com location configurations should use the *.example.com file +domain="subdomain.example.com" +config_path="$vhost_path/*.example.com" +docker exec "$le_container_name" bash -c "source /app/functions.sh; add_location_configuration $domain" +if ! check_location "$le_container_name" "$config_path" ; then + echo "Unexpected location configuration on $config_path after call to add_location_configuration $domain:" + docker exec "$le_container_name" cat "$config_path" +elif ! docker exec "$le_container_name" grep -q "$test_comment" "$config_path"; then + echo "$config_path should still have test comment after call to add_location_configuration $domain:" + docker exec "$le_container_name" cat "$config_path" +fi + +# Adding test.domain.tld location configurations should use the test.* file +domain="test.domain.tld" +config_path="$vhost_path/test.*" +docker exec "$le_container_name" bash -c "source /app/functions.sh; add_location_configuration $domain" +if ! check_location "$le_container_name" "$config_path" ; then + echo "Unexpected location configuration on $config_path after call to add_location_configuration $domain:" + docker exec "$le_container_name" cat "$config_path" +elif ! docker exec "$le_container_name" grep -q "$test_comment" "$config_path"; then + echo "$config_path should still have test comment after call to add_location_configuration $domain:" + docker exec "$le_container_name" cat "$config_path" +fi + # Remove all location configurations docker exec "$le_container_name" bash -c "source /app/functions.sh; remove_all_location_configurations" @@ -109,8 +140,8 @@ if docker exec "$le_container_name" [ ! -s "$config_path" ]; then docker exec "$le_container_name" cat "$config_path" fi -# le1.wtf and le2.wtf configuration files should have reverted to only containing the test comment -for domain in "${domains[@]:0:2}"; do +# Custom configuration files should have reverted to only containing the test comment +for domain in "${domains[@]:0:2}" '*.example.com' 'test.*'; do config_path="$vhost_path/$domain" if check_location "$le_container_name" "$config_path"; then echo "Unexpected location configuration on $config_path after call to remove_all_location_configurations:"