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

OIDC ID Token, Authorization Headers, Refreshing and Verification #14

Merged
merged 7 commits into from Jan 22, 2019

Conversation

JoelSpeed
Copy link
Member

@JoelSpeed JoelSpeed commented Jan 15, 2019

This PR replaces: bitly/oauth2_proxy#621

Description

This PR includes the commits from/replaces #534 and #620 and adds proper OIDC token validation. Please see both original PRs for descriptions and conversations about the PRs.

This now fixes #530

To summarise:

#534: Adds the ability to expose the raw OIDC token to applications behind the proxy
#620: Implement background refreshing of OIDC tokens when cookie_refresh is set > 0
Verification: Implement ValidateSessionState for the OIDC provider to properly verify the id_token. The default providers implementation does not work with OIDC and was causing issues with refreshing

This PR has become quite large but, having opened #620, I realised there was a bug if the cookie_refresh period was shorter than the id_token lifetime (Thanks @jhohertz), to fix this, I needed to correctly implement ValidateSessionState for OIDC which then in turn needs the changes from #534

So the resulting PR is a combination of fixes that adds a bunch of new stuff to the OIDC provider

Motivation and Context

This makes the OIDC implementation complete in terms of refreshing and token verification. It also allows the OIDC ID tokens to be exposed via an authorization header which can then be proxied into the Kubernetes Dashboard.

How Has This Been Tested?

This has been running in our production for around 6 months now and we haven't seen any issues with it. OAuth2 Proxy plus dex with the OAuth2 Proxy in nginx auth_request mode

Checklist:

  • My change requires a change to the documentation or CHANGELOG.
  • I have updated the documentation/CHANGELOG accordingly.
  • I have created a feature (non-master) branch for my PR.

README.md Outdated Show resolved Hide resolved
Copy link
Member

@loshz loshz left a comment

Choose a reason for hiding this comment

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

LGTM - just a few minor comments.

oauthproxy.go Outdated Show resolved Hide resolved
oauthproxy.go Outdated Show resolved Hide resolved
oauthproxy.go Show resolved Hide resolved
oauthproxy.go Show resolved Hide resolved
oauthproxy.go Show resolved Hide resolved
oauthproxy.go Outdated Show resolved Hide resolved
@luispollo
Copy link

Hello @JoelSpeed. Thanks for contributing this! Do you have a Docker image built from this PR that is publicly accessible, like you did for the previous repo?

@jhohertz
Copy link

Just wanted to jump in and day we've been using some of these patches from @JoelSpeed for around 6 months as well with great results, and am excited to see some new life in the project on his repositories.

Let me know anything I can do to help move things forward.

@luispollo
Copy link

@JoelSpeed Never mind, I see the Dockerfile in the repo. 😝

Copy link
Member Author

@JoelSpeed JoelSpeed left a comment

Choose a reason for hiding this comment

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

@syscll I've addressed your comments.

I didn't change the fmt.Errorf to an errors.New though as the codebase is littered with a mix of them and I personally prefer fmt.Errorf as I see it used a lot more often, WDYT?

oauthproxy.go Show resolved Hide resolved
oauthproxy.go Show resolved Hide resolved
oauthproxy.go Show resolved Hide resolved
@zentale
Copy link

zentale commented Jan 22, 2019

@luispollo small remark, ca-certificates package is not installed on the image of this branch. (master is not merged) This causes tls to not work.
Thx for the work guys.

Copy link
Member

@loshz loshz left a comment

Choose a reason for hiding this comment

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

LGTM 👍

@JoelSpeed JoelSpeed merged commit 440d2f3 into master Jan 22, 2019
@JoelSpeed JoelSpeed deleted the oidc branch January 22, 2019 15:56
@tlawrie
Copy link

tlawrie commented Feb 11, 2019

@JoelSpeed the refresh token is working however I am experiencing the issue where by multiple requests made at the same time (due to reactjs calls) are causing a failure.

One of the calls will make it through to refresh the token, however the other duplicate calls will fail with

createSessionState() - rawIDToken: 
createSessionState() - ok: false
RefreshSessionIfNeeded() - Error: unable to update session: token response did not contain an id_token

Which means I have multiple calls happening at the same time, and one call succeeds with the refresh. The rests make the refresh call to not get a good response as the refresh token has already been redeemed.

I implemented what is suggested here (https://gist.github.com/JoelSpeed/9f4dbf6f79f6498d12ccd6ff0bc096e2) lines 41-53 as you have previously mentioned back last year.

@JoelSpeed
Copy link
Member Author

@tlawrie We've been running that fix for a while now and have seen the problem pretty much disappear. It would be good to think up a long term proper solution for this but the only way I can see that happening is by having some central state storage which would defeat the lovely horizontal scalability of the current design. Welcome to ideas on that!

@tlawrie
Copy link

tlawrie commented Feb 12, 2019

@JoelSpeed it might be my implementation of the fix. I currently have the following in the ingress and ingress-controller

Ingress

"ingress.kubernetes.io/configuration-snippet": "
    proxy_pass_request_body     off;
    proxy_cache                   authentication;
    proxy_cache_key               $cookie_bmrg_auth_proxy_dev;
    proxy_cache_valid             202 401 3s;
    proxy_cache_lock              on;
    proxy_ignore_headers          Set-Cookie;",

Ingress Controller

"http-snippet": "proxy_cache_path        /var/run/cache levels=1:2 keys_zone=authentication:10m inactive=3s;\n",

It could also be that something strange is happening in the oidc provider when connected to our provider that is causing the empty ID Token. Looking at the code in RedeemRefreshToken() it merges the context with the new refreshtoken etc. I am not sure how the context.Background() works. Is it possible that it can have an empty ID Token?

@@ -750,6 +847,12 @@ func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) int
if p.PassAccessToken && session.AccessToken != "" {
req.Header["X-Forwarded-Access-Token"] = []string{session.AccessToken}
}
if p.PassAuthorization && session.IDToken != "" {
req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", session.IDToken)}

Choose a reason for hiding this comment

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

@JoelSpeed , I wonder why the idToken is set as Authorization header? Should not this be set as X-Auth-Id-Token or something like that?

michael-freidgeim-webjet pushed a commit to MNF/oauth2-proxy that referenced this pull request Sep 4, 2021
added "web"  to package AI web path.
vjacynycz pushed a commit to vjacynycz/oauth2-proxy that referenced this pull request Jul 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants