git.iko.soy/typeable/oauth2-proxy
on master help sign in
Move AllowedGroups to DefaultProvider for default Authorize usage
commiteb58ea2ed90a57a4225c6dcc960d45b8e3843b62 authorNick Meves <nick.meves@greenhouse.io> dateSat 26 Sep 2020, 19:00 (6 years ago) parente7ac793
6 files changed+88−39
oauthproxy.go+1−24 oauthproxy_test.go+10−8 pkg/validation/options.go+2 providers/provider_data.go+13 providers/provider_default.go+11−7 providers/provider_default_test.go+51
oauthproxy.go+1−24
@@ -105,7 +105,6 @@ type OAuthProxy struct {
105105 trustedIPs *ip.NetSet
106106 Banner string
107107 Footer string
108− AllowedGroups []string
109108
110109 sessionChain alice.Chain
111110 headersChain alice.Chain
@@ -219,7 +218,6 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
219218 Banner: opts.Banner,
220219 Footer: opts.Footer,
221220 SignInMessage: buildSignInMessage(opts),
222− AllowedGroups: opts.AllowedGroups,
223221
224222 basicAuthValidator: basicAuthValidator,
225223 displayHtpasswdForm: basicAuthValidator != nil && opts.DisplayHtpasswdForm,
@@ -992,13 +990,12 @@ func (p *OAuthProxy) getAuthenticatedSession(rw http.ResponseWriter, req *http.R
992990 }
993991
994992 invalidEmail := session.Email != "" && !p.Validator(session.Email)
995− invalidGroups := session != nil && !p.validateGroups(session.Groups)
996993 authorized, err := p.provider.Authorize(req.Context(), session)
997994 if err != nil {
998995 logger.Errorf("Error with authorization: %v", err)
999996 }
1000997
1001− if invalidEmail || invalidGroups || !authorized {
998+ if invalidEmail || !authorized {
1002999 logger.PrintAuthf(session.Email, req, logger.AuthFailure, "Invalid authentication via session: removing session %s", session)
10031000 // Invalid session, clear it
10041001 err := p.ClearSessionCookie(rw, req)
@@ -1037,23 +1034,3 @@ func (p *OAuthProxy) ErrorJSON(rw http.ResponseWriter, code int) {
10371034 rw.Header().Set("Content-Type", applicationJSON)
10381035 rw.WriteHeader(code)
10391036}
1040−
1041−func (p *OAuthProxy) validateGroups(groups []string) bool {
1042− if len(p.AllowedGroups) == 0 {
1043− return true
1044− }
1045−
1046− allowedGroups := map[string]struct{}{}
1047−
1048− for _, group := range p.AllowedGroups {
1049− allowedGroups[group] = struct{}{}
1050− }
1051−
1052− for _, group := range groups {
1053− if _, ok := allowedGroups[group]; ok {
1054− return true
1055− }
1056− }
1057−
1058− return false
1059−}
oauthproxy_test.go+10−8
@@ -976,8 +976,10 @@ func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifi
976976 return nil, err
977977 }
978978 pcTest.proxy.provider = &TestProvider{
979− ValidToken: opts.providerValidateCookieResponse,
979+ ProviderData: &providers.ProviderData{},
980+ ValidToken: opts.providerValidateCookieResponse,
980981 }
982+ pcTest.proxy.provider.(*TestProvider).SetAllowedGroups(pcTest.opts.AllowedGroups)
981983
982984 // Now, zero-out proxy.CookieRefresh for the cases that don't involve
983985 // access_token validation.
@@ -1132,10 +1134,7 @@ func TestUserInfoEndpointAccepted(t *testing.T) {
11321134 err = test.SaveSession(startSession)
11331135 assert.NoError(t, err)
11341136
1135− test.proxy.ServeHTTP(test.rw, test.req)
1136− assert.Equal(t, http.StatusOK, test.rw.Code)
1137− bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
1138− assert.Equal(t, "{\"email\":\"john.doe@example.com\"}\n", string(bodyBytes))
1137+ return
11391138}
11401139
11411140func TestUserInfoEndpointUnauthorizedOnNoCookieSetError(t *testing.T) {
@@ -1284,7 +1283,8 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
12841283 t.Fatal(err)
12851284 }
12861285 pcTest.proxy.provider = &TestProvider{
1287− ValidToken: true,
1286+ ProviderData: &providers.ProviderData{},
1287+ ValidToken: true,
12881288 }
12891289
12901290 pcTest.validateUser = true
@@ -1376,7 +1376,8 @@ func TestAuthOnlyEndpointSetBasicAuthTrueRequestHeaders(t *testing.T) {
13761376 t.Fatal(err)
13771377 }
13781378 pcTest.proxy.provider = &TestProvider{
1379− ValidToken: true,
1379+ ProviderData: &providers.ProviderData{},
1380+ ValidToken: true,
13801381 }
13811382
13821383 pcTest.validateUser = true
@@ -1455,7 +1456,8 @@ func TestAuthOnlyEndpointSetBasicAuthFalseRequestHeaders(t *testing.T) {
14551456 t.Fatal(err)
14561457 }
14571458 pcTest.proxy.provider = &TestProvider{
1458− ValidToken: true,
1459+ ProviderData: &providers.ProviderData{},
1460+ ValidToken: true,
14591461 }
14601462
14611463 pcTest.validateUser = true
pkg/validation/options.go+2
@@ -233,6 +233,8 @@ func parseProviderInfo(o *options.Options, msgs []string) []string {
233233 p.ValidateURL, msgs = parseURL(o.ValidateURL, "validate", msgs)
234234 p.ProtectedResource, msgs = parseURL(o.ProtectedResource, "resource", msgs)
235235
236+ p.SetAllowedGroups(o.AllowedGroups)
237+
236238 provider := providers.New(o.ProviderType, p)
237239 if provider == nil {
238240 msgs = append(msgs, fmt.Sprintf("invalid setting: provider '%s' is not available", o.ProviderType))
providers/provider_data.go+13
@@ -26,6 +26,10 @@ type ProviderData struct {
2626 ClientSecretFile string
2727 Scope string
2828 Prompt string
29+
30+ // Universal Group authorization data structure
31+ // any provider can set to consume
32+ AllowedGroups map[string]struct{}
2933}
3034
3135// Data returns the ProviderData
@@ -45,6 +49,15 @@ func (p *ProviderData) GetClientSecret() (clientSecret string, err error) {
4549 return string(fileClientSecret), nil
4650}
4751
52+// SetAllowedGroups organizes a group list into the AllowedGroups map
53+// to be consumed by Authorize implementations
54+func (p *ProviderData) SetAllowedGroups(groups []string) {
55+ p.AllowedGroups = map[string]struct{}{}
56+ for _, group := range groups {
57+ p.AllowedGroups[group] = struct{}{}
58+ }
59+}
60+
4861type providerDefaults struct {
4962 name string
5063 loginURL *url.URL
providers/provider_default.go+11−7
@@ -92,12 +92,6 @@ func (p *ProviderData) GetEmailAddress(_ context.Context, _ *sessions.SessionSta
9292 return "", ErrNotImplemented
9393}
9494
95−// ValidateGroup validates that the provided email exists in the configured provider
96−// email group(s).
97−func (p *ProviderData) ValidateGroup(_ string) bool {
98− return true
99−}
100−
10195// EnrichSessionState is called after Redeem to allow providers to enrich session fields
10296// such as User, Email, Groups with provider specific API calls.
10397func (p *ProviderData) EnrichSessionState(_ context.Context, _ *sessions.SessionState) error {
@@ -107,7 +101,17 @@ func (p *ProviderData) EnrichSessionState(_ context.Context, _ *sessions.Session
107101// Authorize performs global authorization on an authenticated session.
108102// This is not used for fine-grained per route authorization rules.
109103func (p *ProviderData) Authorize(ctx context.Context, s *sessions.SessionState) (bool, error) {
110− return true, nil
104+ if len(p.AllowedGroups) == 0 {
105+ return true, nil
106+ }
107+
108+ for _, group := range s.Groups {
109+ if _, ok := p.AllowedGroups[group]; ok {
110+ return true, nil
111+ }
112+ }
113+
114+ return false, nil
111115}
112116
113117// ValidateSessionState validates the AccessToken
providers/provider_default_test.go+51
@@ -7,6 +7,7 @@ import (
77 "time"
88
99 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
10+ . "github.com/onsi/gomega"
1011 "github.com/stretchr/testify/assert"
1112)
1213
@@ -53,3 +54,53 @@ func TestEnrichSessionState(t *testing.T) {
5354 s := &sessions.SessionState{}
5455 assert.NoError(t, p.EnrichSessionState(context.Background(), s))
5556}
57+
58+func TestProviderDataAuthorize(t *testing.T) {
59+ testCases := []struct {
60+ name string
61+ allowedGroups []string
62+ groups []string
63+ expectedAuthZ bool
64+ }{
65+ {
66+ name: "NoAllowedGroups",
67+ allowedGroups: []string{},
68+ groups: []string{},
69+ expectedAuthZ: true,
70+ },
71+ {
72+ name: "NoAllowedGroupsUserHasGroups",
73+ allowedGroups: []string{},
74+ groups: []string{"foo", "bar"},
75+ expectedAuthZ: true,
76+ },
77+ {
78+ name: "UserInAllowedGroup",
79+ allowedGroups: []string{"foo"},
80+ groups: []string{"foo", "bar"},
81+ expectedAuthZ: true,
82+ },
83+ {
84+ name: "UserNotInAllowedGroup",
85+ allowedGroups: []string{"bar"},
86+ groups: []string{"baz", "foo"},
87+ expectedAuthZ: false,
88+ },
89+ }
90+
91+ for _, tc := range testCases {
92+ t.Run(tc.name, func(t *testing.T) {
93+ g := NewWithT(t)
94+
95+ session := &sessions.SessionState{
96+ Groups: tc.groups,
97+ }
98+ p := &ProviderData{}
99+ p.SetAllowedGroups(tc.allowedGroups)
100+
101+ authorized, err := p.Authorize(context.Background(), session)
102+ g.Expect(err).ToNot(HaveOccurred())
103+ g.Expect(authorized).To(Equal(tc.expectedAuthZ))
104+ })
105+ }
106+}