git.iko.soy/typeable/oauth2-proxy
on master help sign in
Add allowed_emails option to the auth endpoint query string (#1595)

* Add allowed_emails option to the auth endpoint query string * Don't return true from checkAllowedEmailsOrDomains only because domains field was empty * Fix checkAllowedEmailsOrDomains logic * Added tests for allowed_emails query parameter * Updated CHANGELOG * Remove checkAllowedEmailsOrDomains Co-authored-by: Nick Meves <nicholas.meves@gmail.com>

commitb794248176310c0b33c6d6e4151f44921a9fb892 authorzv0n <tom.zvon@gmail.com> dateSun 24 Apr 2022, 03:11 (4 years ago) parent333e686
4 files changed+92−2
CHANGELOG.md+1 docs/docs/features/endpoints.md+2−1 oauthproxy.go+21 oauthproxy_test.go+68−1
CHANGELOG.md+1
@@ -18,6 +18,7 @@ If you are using an architecture specific tag (ex: v7.2.1-arm64) you should move
1818
1919## Changes since v7.2.1
2020
21+- [#1595](https://github.com/oauth2-proxy/oauth2-proxy/pull/1595) Add optional `allowed_emails` query parameter to the `auth_request`. (@zv0n)
2122- [#1478](https://github.com/oauth2-proxy/oauth2-proxy/pull/1478) Parameterise the runtime image (@omBratteng)
2223- [#1583](https://github.com/oauth2-proxy/oauth2-proxy/pull/1583) Add groups to session too when creating session from bearer token (@adriananeci)
2324- [#1418](https://github.com/oauth2-proxy/oauth2-proxy/pull/1418) Support for passing arbitrary query parameters through from `/oauth2/start` to the identity provider's login URL. Configuration settings control which parameters are passed by default and precisely which values can be overridden per-request (@ianroberts)
docs/docs/features/endpoints.md+2−1
@@ -41,4 +41,5 @@ This endpoint returns 202 Accepted response or a 401 Unauthorized response.
4141
4242It can be configured using the following query parameters query parameters:
4343- `allowed_groups`: comma separated list of allowed groups
44−- `allowed_email_domains`: comma separated list of allowed email domains
44+- `allowed_email_domains`: comma separated list of allowed email domains
45+- `allowed_emails`: comma separated list of allowed emails
oauthproxy.go+21
@@ -1021,6 +1021,7 @@ func authOnlyAuthorize(req *http.Request, s *sessionsapi.SessionState) bool {
10211021 constraints := []func(*http.Request, *sessionsapi.SessionState) bool{
10221022 checkAllowedGroups,
10231023 checkAllowedEmailDomains,
1024+ checkAllowedEmails,
10241025 }
10251026
10261027 for _, constraint := range constraints {
@@ -1091,6 +1092,26 @@ func checkAllowedGroups(req *http.Request, s *sessionsapi.SessionState) bool {
10911092 return false
10921093}
10931094
1095+// checkAllowedEmails allow email restrictions based on the `allowed_emails`
1096+// querystring parameter
1097+func checkAllowedEmails(req *http.Request, s *sessionsapi.SessionState) bool {
1098+ allowedEmails := extractAllowedEntities(req, "allowed_emails")
1099+ if len(allowedEmails) == 0 {
1100+ return true
1101+ }
1102+
1103+ allowed := false
1104+
1105+ for email := range allowedEmails {
1106+ if email == s.Email {
1107+ allowed = true
1108+ break
1109+ }
1110+ }
1111+
1112+ return allowed
1113+}
1114+
10941115// encodedState builds the OAuth state param out of our nonce and
10951116// original application redirect
10961117func encodeState(nonce string, redirect string) string {
oauthproxy_test.go+68−1
@@ -2725,7 +2725,7 @@ func TestAuthOnlyAllowedEmailDomains(t *testing.T) {
27252725 expectedStatusCode: http.StatusForbidden,
27262726 },
27272727 {
2728− name: "UserInAllowedEmailDomains",
2728+ name: "UserNotInAllowedEmailDomains",
27292729 email: "toto@example.com",
27302730 querystring: "?allowed_email_domains=a.example.com,b.example.com",
27312731 expectedStatusCode: http.StatusForbidden,
@@ -2789,3 +2789,70 @@ func TestAuthOnlyAllowedEmailDomains(t *testing.T) {
27892789 })
27902790 }
27912791}
2792+
2793+func TestAuthOnlyAllowedEmails(t *testing.T) {
2794+ testCases := []struct {
2795+ name string
2796+ email string
2797+ querystring string
2798+ expectedStatusCode int
2799+ }{
2800+ {
2801+ name: "NotEmailRestriction",
2802+ email: "toto@example.com",
2803+ querystring: "",
2804+ expectedStatusCode: http.StatusAccepted,
2805+ },
2806+ {
2807+ name: "UserInAllowedEmail",
2808+ email: "toto@example.com",
2809+ querystring: "?allowed_emails=toto@example.com",
2810+ expectedStatusCode: http.StatusAccepted,
2811+ },
2812+ {
2813+ name: "UserNotInAllowedEmail",
2814+ email: "toto@example.com",
2815+ querystring: "?allowed_emails=tete@example.com",
2816+ expectedStatusCode: http.StatusForbidden,
2817+ },
2818+ {
2819+ name: "UserNotInAllowedEmails",
2820+ email: "toto@example.com",
2821+ querystring: "?allowed_emails=tete@example.com,tutu@example.com",
2822+ expectedStatusCode: http.StatusForbidden,
2823+ },
2824+ {
2825+ name: "UserInAllowedEmails",
2826+ email: "toto@example.com",
2827+ querystring: "?allowed_emails=tete@example.com,toto@example.com",
2828+ expectedStatusCode: http.StatusAccepted,
2829+ },
2830+ }
2831+
2832+ for _, tc := range testCases {
2833+ t.Run(tc.name, func(t *testing.T) {
2834+ groups := []string{}
2835+
2836+ created := time.Now()
2837+
2838+ session := &sessions.SessionState{
2839+ Groups: groups,
2840+ Email: tc.email,
2841+ AccessToken: "oauth_token",
2842+ CreatedAt: &created,
2843+ }
2844+
2845+ test, err := NewAuthOnlyEndpointTest(tc.querystring, func(opts *options.Options) {})
2846+ if err != nil {
2847+ t.Fatal(err)
2848+ }
2849+
2850+ err = test.SaveSession(session)
2851+ assert.NoError(t, err)
2852+
2853+ test.proxy.ServeHTTP(test.rw, test.req)
2854+
2855+ assert.Equal(t, tc.expectedStatusCode, test.rw.Code)
2856+ })
2857+ }
2858+}