Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sso-proxy: add preserve host configuration option #55

Merged
merged 7 commits into from
Dec 1, 2018

Conversation

sporkmonger
Copy link
Contributor

When pointing the proxy directly at an AWS ALB, e.g., the host name will be xxx.yyy.zzz.elb.amazonaws.com, however the service itself will typically be expecting a hostname akin to servicename.intranet.company.com. This change adds a config option that will send the original Host header sent by the client through without change. It also changes the behavior of the X-Forwarded-Host header handling code so that the header will only be set if it doesn't already exist. Currently the existing code will create a second X-Forwarded-Host with potentially a different value if there's a proxy chain, which seems likely to be a bug.

Since the new config option is named PreserveHost and the default zero value is false, the default behavior should continue to be the current behavior. However for either config value this will fix the broken X-Forwarded-Host behavior.

Fixes #52. Will conflict with #49. I'll clean up whichever gets merged second.

@sporkmonger sporkmonger force-pushed the preserve-host-config branch 3 times, most recently from 7a4bd0f to f362a2e Compare September 18, 2018 21:17
@sporkmonger
Copy link
Contributor Author

Ready for review.

@sporkmonger sporkmonger force-pushed the preserve-host-config branch 3 times, most recently from 40c5338 to 2f0eb24 Compare September 24, 2018 20:12
@sporkmonger
Copy link
Contributor Author

I think this could be a table-driven test as well, but would need to edit existing tests rather than creating new ones I think.

@@ -263,6 +263,129 @@ func TestNewReverseProxyTLSSkipVerify(t *testing.T) {
}
}

func TestNewReverseProxyPreserveHost(t *testing.T) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make these table drive tests as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost done w/ these and so far confirmed that replacing a bunch of test functions w/ two bigger table-driven test functions hasn't altered code coverage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -81,6 +82,7 @@ type OptionsConfig struct {
SkipAuthRegex []string `yaml:"skip_auth_regex"`
AllowedGroups []string `yaml:"allowed_groups"`
TLSSkipVerify bool `yaml:"tls_skip_verify"`
PreserveHost bool `yaml:"preserve_host"`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be good to add a config unit test as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@jphines
Copy link
Contributor

jphines commented Nov 16, 2018

👋 hi @sporkmonger!

I'll be helping you get this PR merged! Looks like there are some lingering comments from @shrayolacrayon -- is there anything from us you need to get those resolved?

@sporkmonger
Copy link
Contributor Author

sporkmonger commented Nov 17, 2018

Hey, sorry about the delay, was heads-down on the Azure AD PR. I’ve got this on my plate next.

@mreiferson mreiferson changed the title Add preserve host configuration option sso-proxy: add preserve host configuration option Nov 26, 2018
@mreiferson mreiferson added the enhancement New feature or request label Nov 26, 2018
@sporkmonger
Copy link
Contributor Author

This should be ready to review again.

@digitalresistor
Copy link

X-Forwarded-Host should be specified multiple times, preferably each time a new proxy forwards it and had received the request using an alternate "Host:" line from an upstream.

Having two is not a bug.

HTTP header folding will change:

X-Forwarded-Host: example.com
X-Forwarded-Host: whatever.internal.example.com

into:

X-Forwarded-Host: example.com, whatever.internal.example.com

It is up to client libraries to parse the X-Forwarded-Host and use the first value: example.com (the proxy closest to the original client), unless it only trusts 1 proxy, in which case it should use whatever.internal.example.com instead.

Yes, why do you have to count the proxies you trust, well because the following:

X-Forwarded-Host: attacker.com, example.com, whatever.internal.example.com, lb.whatever.example.com

And the application is configured to only support 3 proxies, then attacker.com should be dropped as it is not trusted, and is likely from an attacker sending an X-Forwarded-Host directly to your first proxy, which is dutifully passing it on as it doesn't strip HTTP headers (Amazon ELB for instance doesn't strip those headers, it also doesn't add an X-Forwarded-Host, but instead passes the Host: header through untouched...).

Please don't remove the multiple X-Forwarded-Host headers, unless there is some knob to turn that on/off.

@sporkmonger
Copy link
Contributor Author

I'd advocate for using https://tools.ietf.org/html/rfc7239, which is actually specified, unlike X-Forwarded-Host, but sadly it's not well supported yet. But yeah, this probably shouldn't have been in this PR in the first place. Dropped it.

@@ -212,9 +214,13 @@ func NewRewriteReverseProxy(route *RewriteRoute, config *UpstreamConfig) *httput
}
director := httputil.NewSingleHostReverseProxy(target).Director

req.Header.Add("X-Forwarded-Host", req.Host)
if req.Header.Get("X-Forwarded-Host") == "" {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is one more instance where a new X-Forwarded-Host is not added if there is already one in the request.

@@ -427,7 +427,7 @@ func TestRoundTrip(t *testing.T) {
}{
{
name: "no error",
url: "https://www.example.com/",
url: "http://www.example.com/",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it's already been fixed actually.

@jphines
Copy link
Contributor

jphines commented Nov 30, 2018

@bertjwregeer Thanks for the review! I was going to leave a similar comment regarding the X-Forwarded-Host and that I wasn't super comfortable being with it potentially being overridden by the client.

@sporkmonger Going to run some integration tests and see if I can get this merged this afternoon.

@digitalresistor
Copy link

@jphines I'm a maintainer for a pure python web server, I've been knee deep in X-Forwarded-* stuff for supporting proxies and munging the WSGI environment to match, so I did a drive by review :-)

@sporkmonger
Copy link
Contributor Author

sporkmonger commented Dec 1, 2018 via email

@jphines jphines merged commit 6a6f920 into buzzfeed:master Dec 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

sso-proxy: configuration option to preserve client Host header
5 participants