Skip to content

Commit

Permalink
feat: add support for X-Forwarded-Proto header (#665)
Browse files Browse the repository at this point in the history
Closes #153
  • Loading branch information
amoshydra authored Oct 13, 2021
1 parent c89737b commit a8c9354
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 41 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
bash <(curl -s https://codecov.io/bash)
- run: ./test/e2e/run.sh
- run: ./test/reload/run.sh
- run: ./test/forwarded-header/run.sh

workflows:
"test, build, and relase":
Expand Down
13 changes: 6 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ require (
github.com/gobwas/glob v0.2.3
github.com/golang-jwt/jwt/v4 v4.0.0
github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2
github.com/golang/mock v1.4.3
github.com/golang/mock v1.4.4
github.com/google/go-replayers/httpreplay v0.1.0
github.com/google/uuid v1.1.1
github.com/gorilla/websocket v1.4.2
github.com/imdario/mergo v0.3.8
github.com/julienschmidt/httprouter v1.2.0
github.com/karrick/godirwalk v1.16.1 // indirect
github.com/lib/pq v1.3.0
github.com/mattn/goveralls v0.0.6
github.com/mitchellh/copystructure v1.0.0
Expand Down Expand Up @@ -71,11 +70,11 @@ require (
github.com/urfave/negroni v1.0.0
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
gocloud.dev v0.20.0
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 // indirect
golang.org/x/tools v0.0.0-20201029135353-690a3c245f28
google.golang.org/api v0.26.0
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
golang.org/x/tools v0.1.7
google.golang.org/api v0.30.0
gopkg.in/square/go-jose.v2 v2.5.1
)

Expand Down
99 changes: 66 additions & 33 deletions go.sum

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions go_mod_shadow.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build tools
// +build tools

package main
Expand Down
2 changes: 1 addition & 1 deletion proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (d *Proxy) Director(r *http.Request) {
func EnrichRequestedURL(r *http.Request) {
r.URL.Scheme = "http"
r.URL.Host = r.Host
if r.TLS != nil {
if r.TLS != nil || strings.EqualFold(r.Header.Get("X-Forwarded-Proto"), "https") {
r.URL.Scheme = "https"
}
}
Expand Down
26 changes: 26 additions & 0 deletions proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package proxy_test

import (
"context"
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
Expand Down Expand Up @@ -429,6 +430,31 @@ func TestConfigureBackendURL(t *testing.T) {
}
}

func TestEnrichRequestedURL(t *testing.T) {
for k, tc := range []struct {
in *http.Request
expect url.URL
}{
{
in: &http.Request{Host: "test", TLS: &tls.ConnectionState{}, URL: new(url.URL)},
expect: url.URL{Scheme: "https", Host: "test"},
},
{
in: &http.Request{Host: "test", URL: new(url.URL)},
expect: url.URL{Scheme: "http", Host: "test"},
},
{
in: &http.Request{Host: "test", Header: http.Header{"X-Forwarded-Proto": {"https"}}, URL: new(url.URL)},
expect: url.URL{Scheme: "https", Host: "test"},
},
} {
t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) {
proxy.EnrichRequestedURL(tc.in)
assert.EqualValues(t, tc.expect, *tc.in.URL)
})
}
}

//
// func BenchmarkDirector(b *testing.B) {
// backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down
1 change: 1 addition & 0 deletions test/forwarded-header/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.log
25 changes: 25 additions & 0 deletions test/forwarded-header/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
serve:
api:
port: 6061
proxy:
port: 6060

access_rules:
repositories:
- file://./rules.1.json

authenticators:
noop:
enabled: true
anonymous:
enabled: true

authorizers:
allow:
enabled: true
deny:
enabled: true

mutators:
noop:
enabled: true
52 changes: 52 additions & 0 deletions test/forwarded-header/rules.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[
{
"id": "test-rule-http",
"upstream": {
"url": "https://httpbin.org/anything/"
},
"match": {
"url": "http://127.0.0.1:6060/http",
"methods": [
"GET"
]
},
"authenticators": [
{
"handler": "noop"
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
},
{
"id": "test-rule-https",
"upstream": {
"url": "https://httpbin.org/anything/"
},
"match": {
"url": "https://127.0.0.1:6060/https",
"methods": [
"GET"
]
},
"authenticators": [
{
"handler": "noop"
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
}
]
108 changes: 108 additions & 0 deletions test/forwarded-header/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/bin/bash

set -euo pipefail

waitport() {
i=0
while ! nc -z localhost "$1" ; do
sleep 1
if [ $i -gt 10 ]; then
cat ./config.yaml
cat ./oathkeeper.log
exit 1
fi
i=$((i+1))
done
}

cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"


export GO111MODULE=on

(cd ../../; make install)

run_oathkekeper() {
killall oathkeeper || true

export OATHKEEPER_PROXY=http://127.0.0.1:6060
export OATHKEEPER_API=http://127.0.0.1:6061

LOG_LEVEL=debug oathkeeper --config ./config.yaml serve >> ./oathkeeper.log 2>&1 &

waitport 6060
waitport 6061
}

make_request() {
url=$1
expected_status_code=$2
shift 2

[[ $(curl --silent --output /dev/null -f ${url} -w '%{http_code}' "$@") -eq $expected_status_code ]]
}

SUCCESS_TEST=()
FAILED_TEST=()

run_test() {
label=$1
shift 1

result="0"
"$@" || result="1"

if [[ "$result" -eq "0" ]]; then
SUCCESS_TEST+=("$label")
else
FAILED_TEST+=("$label")
fi
}

function finish {
cat ./config.yaml
cat ./rules.1.json
cat ./oathkeeper.log
}
trap finish EXIT

run_oathkekeper

run_test "Executing request against a HTTP rule -> 200" \
make_request "http://127.0.0.1:6060/http" 200

run_test "Executing request against a HTTP rule with forwrded proto HTTP -> 200" \
make_request "http://127.0.0.1:6060/http" 200 -H "X-Forwarded-Proto: http"

run_test "Executing request against a HTTP rule with forwrded proto HTTPS -> 404" \
make_request "http://127.0.0.1:6060/http" 404 -H "X-Forwarded-Proto: https"

run_test "Executing request against a HTTPS rule -> 404" \
make_request "http://127.0.0.1:6060/https" 404

run_test "Executing request against a HTTPS rule with forwarded proto HTTP -> 404" \
make_request "http://127.0.0.1:6060/https" 404 -H "X-Forwarded-Proto: http"

run_test "Executing request against a HTTPS rule with forwarded proto HTTPS -> 200" \
make_request "http://127.0.0.1:6060/https" 200 -H "X-Forwarded-Proto: https"


echo "PASS: ${#SUCCESS_TEST[@]}"
for value in "${SUCCESS_TEST[@]}"
do
echo "- $value"
done

if [[ "${#FAILED_TEST[@]}" -gt 0 ]]; then
echo "FAILED: ${#FAILED_TEST[@]}"
for value in "${FAILED_TEST[@]}"
do
echo "- $value"
done

exit 1
fi

kill %1 || true

trap - EXIT

0 comments on commit a8c9354

Please sign in to comment.