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

Add access-token in proxy response headers #109

Merged
merged 5 commits into from
Nov 16, 2018

Conversation

epot
Copy link
Contributor

@epot epot commented Nov 8, 2018

Problem

I need to do a collateral call to google APIs from my backend to get additional information about the user. For that, I need to have the access token.

Solution

Return the access token in the header key X-Forwarded-AccessToken.

Notes

Let me know if that is a good idea, and I'll make this tests are updated.

@@ -1037,6 +1037,7 @@ func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) (er
}

req.Header.Set("X-Forwarded-User", session.User)
req.Header.Set("X-Forwarded-AccessToken", session.AccessToken)

Choose a reason for hiding this comment

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

I don't think we want want to pass the Access Token by default in plaintext in the header to the upstream as it seems like it could escalate to be a security vulnerability. Maybe we can figure out a way to make this a configured opt-in header to set.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean by Maybe we can figure out a way to make this a configured opt-in header to set? I have no idea how secure this has to be, I feared an answer like that :).

Choose a reason for hiding this comment

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

Similar to what is done in bitly/oauth2_proxy we could conditionally pass this in if the config file has something set like PassAccessToken. I think that passing the access token should be done with caution though, as an upstream could potentially do something like log it and create a security vulnerability.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah nice. Well, I would definitely use such option. If you want me to re-work this PR to offer this feature, let me know ;).

Choose a reason for hiding this comment

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

That sounds good to me. Thank you for opening and working on this!

Copy link
Contributor

Choose a reason for hiding this comment

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

Also Azure has 4kb access tokens. 😝

@shrayolacrayon
Copy link

@epot one question i have, is what kinds of requests are you trying to make with the google API? Are they queries to get more information about the authenticated user?
One other possible, and maybe more complicated solution that would be to have a set of enrichment APIs that sso can proxy with the google API, which would allow us to not have to pass the access token to the upstream at all.

@epot
Copy link
Contributor Author

epot commented Nov 9, 2018

Yes that is exactly that: I want to get the user email, full name, profile picture... And possibly team if it's an enterprise account.
I thought about what you suggest, but we would then need to pass those information in all the http headers?

@epot epot force-pushed the add-access-token branch 2 times, most recently from bd46ae2 to 02862ee Compare November 9, 2018 08:54
@shrayolacrayon
Copy link

This would probably be an endpoint on sso-proxy or sso-auth that the upstream would call. For now, since there is precedence for adding the access token in oauth2_proxy we can move forward with the first proposed solution.
I will also open an issue for the preferred abstraction, with the intention having that be the end solution, and eventually deprecating passing the access token in a header.

@sporkmonger
Copy link
Contributor

The challenge w/ trying to do it all via extra endpoints rather than passing the token through is that this will vary by provider.

@epot
Copy link
Contributor Author

epot commented Nov 12, 2018

Ok, let me know what you want me to add on top of what is already there to push this PR forward!

@@ -71,6 +72,8 @@ type Options struct {
CookieSecure bool `envconfig:"COOKIE_SECURE" default:"true"`
CookieHTTPOnly bool `envconfig:"COOKIE_HTTP_ONLY"`

PassAccessToken bool `envconfig:"PASS_ACCESS_TOKEN" default:"false"`

Choose a reason for hiding this comment

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

can we add a simple unit test here for the new config value in options_test.go?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And done as well!

@@ -1037,6 +1040,11 @@ func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) (er
}

req.Header.Set("X-Forwarded-User", session.User)

Choose a reason for hiding this comment

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

can we also add some test in oauthproxy_test.go to test that the right header is being set?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, done!

@shrayolacrayon
Copy link

@sporkmonger I think you're right that there would need to be separate enrichment APIs for each provider, however I think that that the proposed abstraction is better from a security perspective than passing the access token in plain text to the upstream.

@epot added some requests for tests, then I think we can get this merged!

@epot
Copy link
Contributor Author

epot commented Nov 13, 2018

Ok @shrayolacrayon here we go!

@shrayolacrayon shrayolacrayon merged commit 6c0f66f into buzzfeed:master Nov 16, 2018
@sporkmonger
Copy link
Contributor

I'm clearly a bit late, but just realized this PR implemented this globally rather than per-upstream. That seems like a mistake. I don't want to ship access tokens to every single application (expecting to be deploying on the order of like 30 services behind the proxy), but I have one or two that certainly would benefit from having it.

@mreiferson
Copy link
Contributor

I think there are two ways to look at this:

  1. It's a short-term solution in lieu of the alternative "enrichment" API proposal, in which case a global config might be reasonable

or

  1. We don't actually think that the "enrichment" API proposal is viable, in which case I think a per-upstream config is warranted if we expect this to be a long-term solution

In general, I agree that a per-upstream config is preferable.

WDYT @shrayolacrayon?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants