-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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 allowed_email_domains on auth_request endpoint #1286
Add allowed_email_domains on auth_request endpoint #1286
Conversation
oauthproxy.go
Outdated
@@ -961,15 +961,57 @@ func (p *OAuthProxy) getAuthenticatedSession(rw http.ResponseWriter, req *http.R | |||
// | |||
//nolint:gosimple |
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.
We can remove this nolint
& TODO above now that you are adding more functionality 👍
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.
Removed
oauthproxy.go
Outdated
return false | ||
} | ||
|
||
func extractAllowedEmailDomains(req *http.Request) map[string]struct{} { |
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.
This and extractAllowedGroups
are nearly identical -- maybe we should generalize it and use the querystring param as an extra argument (appears to be the only difference)?
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.
Refactored
oauthproxy.go
Outdated
return false | ||
} | ||
|
||
if _, ok := allowedEmailDomains[emailSplited[1]]; ok { |
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.
Throughout the rest of the codebase, there's support for broad subdomains (.example.com
would allow foo.example.com
and bar.example.com
). I think that support should be extended here too.
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 believe there's common helper methods for this logic since it is an error-prone implementation that leads to security vulnerabilities; hopefully we can use those here?
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.
It support now broad subdomains starting with .
and *.
and sharing the same code base through an util.
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 but I didn't find out something relevant as a trusted common helper method. Do you have something in mind?
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 for the PR! I think this will be a worthwhile addition.
I've left some notes on areas to align it more with the rest of the codebase.
This needs a CHANGELOG entry as well.
10e6c24
to
16dd3fb
Compare
Hi @NickMeves, WDYT about the change? Should I add something else? |
oauthproxy.go
Outdated
for _, group := range strings.Split(allowedGroups, ",") { | ||
if group != "" { | ||
groups[group] = struct{}{} | ||
for _, group := range s.Groups { |
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.
What's the reasoning for moving away from Loop + Set (with O(NlogN)
time complexity) to double looping to find matches (O(N^2)
time complexity?
I know in small cases (< 10), double looping is fine and potentially faster. But since we don't know how large our worst case users will be using this feature -- we leaned toward O(NlogN)
Loop + Set in the initial implementation.
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 recommend switching the extractAllowedEntities
implementation to return a map[string]struct{}
instead of []string
and doing a set membership check in your checker methods.
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.
Yes you right, I fixed it with the recommended implementation.
pkg/util/util.go
Outdated
@@ -23,3 +25,82 @@ func GetCertPool(paths []string) (*x509.CertPool, error) { | |||
} | |||
return pool, nil | |||
} | |||
|
|||
func IsEndpointAllowed(endpoint *url.URL, allowedDomains []string) bool { |
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.
This is a great refactor! Thanks!
Let's slide it to a more specific utils
area though.
Can we move this to here: https://github.com/oauth2-proxy/oauth2-proxy/blob/master/pkg/validation/utils.go
Since this is all validation related?
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.
Yes sure, done.
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.
@NickMeves For the group authentication, didn't we have some requirement about having to have the allowed_group be defined on the config first to be allowed to be added in the query params?
oauthproxy.go
Outdated
} | ||
|
||
return true | ||
} | ||
|
||
func extractAllowedEntities(req *http.Request, field string) map[string]struct{} { |
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 was a bit confused about what we were trying to achieve here, can we add a comment that explains what the inputs and outputs are at a minimum
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 added a comment based on @NickMeves recommendations.
See #1286 (comment)
oauthproxy.go
Outdated
return true | ||
} | ||
|
||
emailSplited := strings.Split(s.Email, "@") |
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.
Splitted is a bit jarring to me, what about
emailSplited := strings.Split(s.Email, "@") | |
splitEmail := strings.Split(s.Email, "@") |
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.
Fixed
pkg/app/redirect/validator_test.go
Outdated
Entry("Valid Wildcard Subdomain", "foo.wildcard.bar/redirect", true), | ||
Entry("Valid Wildcard Subdomain Root", "wildcard.bar/redirect", true), | ||
Entry("Valid Wildcard Subdomain anyport", "foo.wildcard.sub.anyport.bar:4242/redirect", true), | ||
Entry("Valid Wildcard Subdomain Anyport Root", "wildcard.sub.anyport.bar:4242/redirect", true), | ||
Entry("Valid Wildcard Subdomain Defined Port", "foo.wildcard.sub.port.bar:8080/redirect", true), | ||
Entry("Valid Wildcard Subdomain Defined Port Root", "wildcard.sub.port.bar:8080/redirect", true), | ||
Entry("Invalid HTTP subdomain", "foo.bar/redirect", false), | ||
Entry("Invalid HTTP subdomain", "proxy.foo.bar/redirect", false), |
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.
Are we sure about this? I don't think redirects are allowed without a scheme prefixing them currently, this could lead to open redirects which I really would like to avoid
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, forget to commit the fix.
Done.
pkg/validation/utils.go
Outdated
@@ -9,3 +16,45 @@ func prefixValues(prefix string, values ...string) []string { | |||
} | |||
return msgs | |||
} | |||
|
|||
func IsEndpointAllowed(endpoint *url.URL, allowedDomains []string) bool { |
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.
Please add a doc string for this function
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.
added
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 actually don't think this is the right place to put this function, the validation package is all about configuration validation rather than runtime validation like this. Can we move it to pkg/utils
until we find a better home please
pkg/validation/utils.go
Outdated
return false | ||
} | ||
|
||
func isHostnameBelongsToAllowedHost(hostname, allowedHost string) bool { |
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 think this could be simpler
func isHostnameBelongsToAllowedHost(hostname, allowedHost string) bool { | |
func isHostnameAllowed(hostname, allowedHost string) bool { |
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.
fixed
@JoelSpeed I don't recall this being a requirement -- The architecture I built this for was a central Authentication Proxy (BeyondCorp style) where all the consuming applications (nginx, k8s ingress) could specificy any groups they cared about for AuthZ |
f60ec03
to
eda65c6
Compare
@JoelSpeed @NickMeves I normally solved the required fixes/changes + solved conflicts by rebasing to master. |
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.
Few more comments, otherwise I think I'm happy for this to merge
CHANGELOG.md
Outdated
- [#1210](https://github.com/oauth2-proxy/oauth2-proxy/pull/1210) A new `keycloak-oidc` provider has been added with support for role based authentication. The existing keycloak auth provider will eventually be deprecated and removed. Please switch to the new provider `keycloak-oidc`. | ||
- [#1286](https://github.com/oauth2-proxy/oauth2-proxy/pull/1286) Add the `allowed_email_domains` and the `allowed_groups` on the `auth_request` endpoint to restrict access per ingress + support standard wildcard char for validation with sub-domain. (@w3st3ry @armandpicard) |
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.
This should be moved into the changes since v7.1.3 section and typically should just be the PR title, we can leave this here if you add the extra one to the changes since section
pkg/validation/utils.go
Outdated
@@ -9,3 +16,45 @@ func prefixValues(prefix string, values ...string) []string { | |||
} | |||
return msgs | |||
} | |||
|
|||
func IsEndpointAllowed(endpoint *url.URL, allowedDomains []string) bool { |
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 actually don't think this is the right place to put this function, the validation package is all about configuration validation rather than runtime validation like this. Can we move it to pkg/utils
until we find a better home please
pkg/validation/utils.go
Outdated
// if the whitelisted domain's port is '*', allow all ports | ||
// if the whitelisted domain contains a specific port, only allow that port | ||
// if the whitelisted domain doesn't contain a port at all, only allow empty redirect ports ie http and https |
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.
We are trying to move away from this term when we touch code that uses it
// if the whitelisted domain's port is '*', allow all ports | |
// if the whitelisted domain contains a specific port, only allow that port | |
// if the whitelisted domain doesn't contain a port at all, only allow empty redirect ports ie http and https | |
// if the allowed domain's port is '*', allow all ports | |
// if the allowed domain contains a specific port, only allow that port | |
// if the allowed domain doesn't contain a port at all, only allow empty redirect ports ie http and https |
170cb53
to
b7bd0c1
Compare
b7bd0c1
to
22b70d8
Compare
@JoelSpeed @NickMeves I pushed the latest requested changes + rebased to master/fixed conflicts. |
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.
Changes look great, I think there's a conflict in the changelog now though. We are planning to do a bug release in the next couple of weeks, if you don't mind holding until we've done that release, then rebasing this to fix the changelog, that would be appreciated. Then we can get you merged as soon as we are open for features
22b70d8
to
b6454c9
Compare
This pull request has been inactive for 60 days. If the pull request is still relevant please comment to re-activate the pull request. If no action is taken within 7 days, the pull request will be marked closed. |
Apologies for letting this get stale, are you able to resolve the conflicts and we can get this merged? |
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.
Looks good, apologies for the delay, lets get this merged
@armandpicard GitHub seems to think there are conflicts on this branch, do you think you could try rebasing it? |
b6454c9
to
299e51c
Compare
@JoelSpeed conflicts are now fixed + branch rebased. |
CHANGELOG.md
Outdated
@@ -37,6 +37,7 @@ N/A | |||
- [#1444](https://github.com/oauth2-proxy/oauth2-proxy/pull/1444) Update LinkedIn provider validate URL (@jkandasa) | |||
- [#1471](https://github.com/oauth2-proxy/oauth2-proxy/pull/1471) Update alpine to 3.15 (@AlexanderBabel) | |||
- [#1479](https://github.com/oauth2-proxy/oauth2-proxy/pull/1479) Update to Go 1.17 (@polarctos) | |||
- [#1286](https://github.com/oauth2-proxy/oauth2-proxy/pull/1286) Add the `allowed_email_domains` and the `allowed_groups` on the `auth_request` + support standard wildcard char for validation with sub-domain and email-domain. (@w3st3ry @armandpicard) |
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.
Sorry, this should be moved up to the Changes since v7.2.1
section now, closer to line 9
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.
@JoelSpeed my bad, fixed!
…est endpoint + support standard wildcard char for validation with sub-domain and email-domain. Signed-off-by: Valentin Pichard <github@w3st.fr>
299e51c
to
2b4c8a9
Compare
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, thanks
Description
Add the allowed_email_domains on the auth_request endpoint to restrict access per ingress.
Motivation and Context
Some users may want to have one oauth2 proxy with multiple allowed email domains but restrict access to some ressource to only one or multiple of these emails domains
How Has This Been Tested?
Unit Tests and test on Kubernees with an Nginx ingress.
Checklist: