-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Feature/add option to skip loading claims from profile url #2329
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
Feature/add option to skip loading claims from profile url #2329
Conversation
Any input/feedback from anyone? |
@tuunit @JoelSpeed Any input/thoughts on this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code seems quite simple (which is good). It feels a bit hackish though. Wouldn't it be better to be able to configure (a list of) claims that should be ignored and/or that should be ignored if not available from the ID token? Defaults can then eventually be set from the code for i.e. the Azure provider (if indeed necessary).
@tuunit Do you agree or am I overthinking/overcomplicating?
When we define the scope to be for a resource/api other than MS Graph, e.g. One option is to build the ignore-list internally by inspecting other flags like |
Any update @kvanzuijlen? |
Hi @nilsgstrabo, Sorry, I completely overlooked your response. Thanks for the detailed explanation. I'd be curious what other maintainers think as well. @tuunit @JoelSpeed any comments? |
Hi, will check it this evening! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, a really well written PR. Thanks a lot for all the effort you put into your description of the issue.
providers/provider_data.go
Outdated
var profileURL *url.URL | ||
if !p.SkipClaimsFromProfileURL { | ||
profileURL = p.ProfileURL | ||
} | ||
|
||
extractor, err := util.NewClaimExtractor(context.TODO(), rawIDToken, profileURL, p.getAuthorizationHeader(accessToken)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first I was a bit concerned that this change could cause error messages or other issues because of the uninitialized url.URL
when initializing the ClaimExtractor
. But after checking the implementation of loadProfileClaims()
in providers->util->claim_extractor.go
I say we are good here. As we already handle the case for an unconfigured / nil url.URL
correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And this use case already seems to be well tested in claim_extractor_test.go
as well.
@@ -283,7 +284,12 @@ func (p *ProviderData) buildSessionFromClaims(rawIDToken, accessToken string) (* | |||
} | |||
|
|||
func (p *ProviderData) getClaimExtractor(rawIDToken, accessToken string) (util.ClaimExtractor, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding testing. Could you take some time for extending the test case TestProviderData_buildSessionFromClaims
inside provider_data_test.go
We should be able to set the new skip option inside a new test case entry and get a valid response:
oauth2-proxy/providers/provider_data_test.go
Lines 427 to 441 in 6372710
provider.AllowUnverifiedEmail = tc.AllowUnverified | |
provider.UserClaim = tc.UserClaim | |
provider.EmailClaim = tc.EmailClaim | |
provider.GroupsClaim = tc.GroupsClaim | |
rawIDToken, err := newSignedTestIDToken(tc.IDToken) | |
g.Expect(err).ToNot(HaveOccurred()) | |
ss, err := provider.buildSessionFromClaims(rawIDToken, "") | |
if err != nil { | |
g.Expect(err).To(Equal(tc.ExpectedError)) | |
} | |
if ss != nil { | |
g.Expect(ss).To(Equal(tc.ExpectedSession)) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I will take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing SkipClaimsFromProfileURL turned out to be a bit trickier than expected. The only feasible way I can see, is to use httptest.Server, set ProfileURL (and AccessToken + getAuthorizationHeaderFunc), and test if the server receives a request based on the value for SkipClaimsFromProfileURL. Ref commit 7dc8c14
Please let me know if you have any better ideas or suggestions.
Co-authored-by: Jan Larwig <jan@larwig.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nilsgstrabo
Whats your opinion?
profileURLTracker mock.Mock | ||
) | ||
if tc.SetProfileURL { | ||
profileURLSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with setting up a http test server here. We do something quite similar in claim_extractor_test.go
for the profileURL as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But do we really need to introduce a new go dependency for this "simple" test?
Couldn't we just introduce a simple custom handler like in claim_extractor_test.go#L556
:
oauth2-proxy/pkg/providers/util/claim_extractor_test.go
Lines 556 to 564 in 52ad317
func requiresAuthProfileHandler(rw http.ResponseWriter, req *http.Request) { | |
if !hasAuthorizedHeader(req.Header) { | |
rw.WriteHeader(403) | |
rw.Write([]byte("Unauthorized")) | |
return | |
} | |
rw.Write([]byte(basicProfileURLPayload)) | |
} |
This way we don't need to introduce a new dependency to objx and mock.Mock and we will not need to the assertion in line 485
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. The mock.Mock package is completely overkill here. Only need to test that a request to profileURL is sent or not.
Fixed in ceccfb2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@tuunit Is there anything else I need to do with this PR? Will it be included in the next release, and do you know approximately when the next release is planned? |
Code generation needs to be updated here |
Something I need to do? |
Please run |
Done and pushed |
* enhancement: Change base image from alpine to distroless (oauth2-proxy#2295) * Changed base image from alpine to distroless * chore: updated Makefile * fix: removed arm/v6 and ppc64le for distroless variant * Update Dockerfile * Update Makefile * docs: Add README-section, CHANGELOG-entry and --pull to prevent caching --------- Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk> * Add possibility to encode the state param as UrlEncodedBase64 (oauth2-proxy#2312) * Add possibility to encode the state param as UrlEncodedBase64 * Update CHANGELOG.md * Update oauthproxy.go Co-authored-by: Jan Larwig <jan@larwig.com> --------- Co-authored-by: Jan Larwig <jan@larwig.com> * NGINX return 403 for sign_in (oauth2-proxy#2322) (oauth2-proxy#2323) Co-authored-by: Sven Ertel <sven.ertel@bayernwerk.de> * chore: Create sha256sum for tar instead of binary (oauth2-proxy#2343) * Create sha256sum for tar instead of binary * chore: Add checksum for binary * chore: Updated changelog --------- Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk> * Log error details when failed loading CSRF cookie (oauth2-proxy#2345) * Log error details when failed loading CSRF cookie * Add a record about this PR to CHANGELOG.md --------- Co-authored-by: Ondrej Charvat <ondrej.charvat@yunextraffic.com> Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk> * Feature - Add env variable support for alpha struct (oauth2-proxy#2375) * added envsubstring package and added simple test cases.imple tests. * added documentation * added changelog entry * added documentation to wrong file . * changed tests to ginkgo format * update project to use better maintained library * use defer to clear test variable after tests finished * updated docs for the new package documentation and fixed bad english * refactored function to "reduce" complexity. * updated changelog for new version updated readme * minor formatting --------- Co-authored-by: Haydn Evans <h.evans@douglas.de> Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk> * remove nsswitch workaround (oauth2-proxy#2371) Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk> * feat: Added renovate configuration (oauth2-proxy#2377) * Feature/add option to skip loading claims from profile url (oauth2-proxy#2329) * add new flag skip-claims-from-profile-url * skip passing profile URL if SkipClaimsFromProfileURL * docs for --skip-claims-from-profile-url flag * update flag comment * update docs * update CHANGELOG.md * Update providers/provider_data.go Co-authored-by: Jan Larwig <jan@larwig.com> * Add tests for SkipClaimsFromProfileURL * simplify tests for SkipClaimsFromProfileURL * generate alpha_config.md --------- Co-authored-by: Jan Larwig <jan@larwig.com> * Add ability to configure username for Redis cluster connections (oauth2-proxy#2381) * Initial attempt. * Add CHANGELOG entry. * Drop commented-out Sentinel test. --------- Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk> * chore(deps): update module golang.org/x/crypto to v0.17.0 [security] (oauth2-proxy#2400) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update github.com/ghodss/yaml digest to d8423dc (oauth2-proxy#2401) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Improved dev environment (oauth2-proxy#2211) * Improved dev env setup * Cleanup duplicate checks * Applied PR feedback * Updated go.mod/go.sum * go mod tidy * Update .devcontainer/devcontainer.json * Update pkg/http/server_test.go Co-authored-by: Jan Larwig <jan@larwig.com> * Create launch.json * Update .devcontainer/Dockerfile * Apply suggestions from code review --------- Co-authored-by: Jan Larwig <jan@larwig.com> * feature: add release automation workflows (oauth2-proxy#2224) * feature: add release automation workflows * deactivate provenancee because of behaviour change with buildx v0.10.0 * add changelog section extraction for github release notes * fix registry path; fix EOF * use correct version of golangci-lint; add additional workflow step for fetching all dependencies * chore(deps): update module github.com/bsm/redislock to v0.9.4 (oauth2-proxy#2406) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * initial commit for docusaurus 3 upgrade * fix mdx errors * fix mdx issues * fix routing issues * update docs generation workflow * fix version * fix permissions * move slack to header * remove background color and minify * Update docs/docs/configuration/providers/openid_connect.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> * Update docs/docs/configuration/providers/openid_connect.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> * Update docs/docs/configuration/providers/openid_connect.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> * Update docs/docs/configuration/providers/gitlab.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> * Update docs/docs/configuration/providers/gitlab.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> * Update docs/docs/configuration/providers/github.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> * Update docs/docs/configuration/providers/github.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> * Update docs/docs/configuration/providers/github.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> * Update docs/docs/configuration/providers/github.md Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> --------- Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk> Co-authored-by: Jan Brezina <brezinajn@users.noreply.github.com> Co-authored-by: WhiteRabbit-Code <sven@ertel-net.de> Co-authored-by: Sven Ertel <sven.ertel@bayernwerk.de> Co-authored-by: charvadzo <120425386+charvadzo@users.noreply.github.com> Co-authored-by: Ondrej Charvat <ondrej.charvat@yunextraffic.com> Co-authored-by: Haydn Evans <h.evans@douglas.de> Co-authored-by: Nils Gustav Stråbø <65334626+nilsgstrabo@users.noreply.github.com> Co-authored-by: Ross Golder <ross@golder.org> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Description
Added a new flag
skip-claims-from-profile-url
that controls if ProviderData will provide ClaimExtractor with the ProfileURL (resolved from OIDC metadata or manually set). If set to true, ProfileURL is not provided, and ClaimExtractor will not call the profile URL endpoint to resolve claims missing in the id_token.The default value is
false
, and should therefore not break default behavior.Motivation and Context
When using login.microsoftonline.com as OIDC issuer (e.g. https://login.microsoftonline.com/common/v2.0) and you define a scope (e.g. openid profile offline_access 6dae42f8-4368-4678-94ff-3960e28e3630/user.read) with a custom API resource, the access_token received from the
token
endpoint cannot be used as a bearer token with the userinfo (profile URL) endpoint; Theaud
claim is wrong. When ClaimExtractor calls the userinfo endpoint a 401 is returned, which in turn cause oauth2-proxy to return 500 to the client.The new flag
skip-claims-from-profile-url
instructs the ProviderData to not pass the ProfileURL to ClaimExtractor, thereby preventing a request to the ProfileUR and a subsequent 401 error. The flag is only required when a custom API resource is defined in the scope.The change proposed in this PR should solve #1666 and #2314
How Has This Been Tested?
As mentioned, when using oauth2-proxy without defining a custom resources in scope, everything works fine, for example:
But if I add a custom resource to the scope it fails:
with the following log entries from the oauth2-proxy
because the access_token has a
aud
claim not intended for the userinfo endpoint.If I use my own image built with the new option, everything works as intended (at least for me)
If I set
OAUTH2_PROXY_SKIP_CLAIMS_FROM_PROFILE_URL=false
, or omit it, it falls back do default behavior and fails the same way as v7.5.1 does.Checklist:
Not sure what tests to update. Existing tests in
options
package seems very limited, at least when I look for tests for other options.I could add tests to ClaimExtractor if I pass the SkipClaimsFromProfileURL as an argument, and let ClaimExtractor decided if it should call the provided profileURL or not. The way is works now is that ProviderData passes nil as profileUrl if
skip-claims-from-profile-url
is true.