@@ -592,6 +592,37 @@ func TestPassUserHeadersWithEmail(t *testing.T) {
592592 }
593593}
594594
595+func TestPassGroupsHeadersWithGroups(t *testing.T) {
596+ opts := baseTestOptions()
597+ err := validation.Validate(opts)
598+ assert.NoError(t, err)
599+
600+ const emailAddress = "john.doe@example.com"
601+ const userName = "9fcab5c9b889a557"
602+
603+ groups := []string{"a", "b"}
604+ created := time.Now()
605+ session := &sessions.SessionState{
606+ User: userName,
607+ Groups: groups,
608+ Email: emailAddress,
609+ AccessToken: "oauth_token",
610+ CreatedAt: &created,
611+ }
612+ {
613+ rw := httptest.NewRecorder()
614+ req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase0", nil)
615+ proxy, err := NewOAuthProxy(opts, func(email string) bool {
616+ return email == emailAddress
617+ })
618+ if err != nil {
619+ t.Fatal(err)
620+ }
621+ proxy.addHeadersForProxying(rw, req, session)
622+ assert.Equal(t, groups, req.Header["X-Forwarded-Groups"])
623+ }
624+}
625+
595626func TestStripAuthHeaders(t *testing.T) {
596627 testCases := map[string]struct {
597628 SkipAuthStripHeaders bool
@@ -609,6 +640,7 @@ func TestStripAuthHeaders(t *testing.T) {
609640 PassAuthorization: false,
610641 StrippedHeaders: map[string]bool{
611642 "X-Forwarded-User": true,
643+ "X-Forwared-Groups": true,
612644 "X-Forwarded-Email": true,
613645 "X-Forwarded-Preferred-Username": true,
614646 "X-Forwarded-Access-Token": false,
@@ -623,6 +655,7 @@ func TestStripAuthHeaders(t *testing.T) {
623655 PassAuthorization: false,
624656 StrippedHeaders: map[string]bool{
625657 "X-Forwarded-User": true,
658+ "X-Forwared-Groups": true,
626659 "X-Forwarded-Email": true,
627660 "X-Forwarded-Preferred-Username": true,
628661 "X-Forwarded-Access-Token": true,
@@ -637,6 +670,7 @@ func TestStripAuthHeaders(t *testing.T) {
637670 PassAuthorization: false,
638671 StrippedHeaders: map[string]bool{
639672 "X-Forwarded-User": true,
673+ "X-Forwared-Groups": true,
640674 "X-Forwarded-Email": true,
641675 "X-Forwarded-Preferred-Username": true,
642676 "X-Forwarded-Access-Token": true,
@@ -651,6 +685,7 @@ func TestStripAuthHeaders(t *testing.T) {
651685 PassAuthorization: true,
652686 StrippedHeaders: map[string]bool{
653687 "X-Forwarded-User": false,
688+ "X-Forwared-Groups": false,
654689 "X-Forwarded-Email": false,
655690 "X-Forwarded-Preferred-Username": false,
656691 "X-Forwarded-Access-Token": false,
@@ -665,6 +700,7 @@ func TestStripAuthHeaders(t *testing.T) {
665700 PassAuthorization: false,
666701 StrippedHeaders: map[string]bool{
667702 "X-Forwarded-User": false,
703+ "X-Forwared-Groups": false,
668704 "X-Forwarded-Email": false,
669705 "X-Forwarded-Preferred-Username": false,
670706 "X-Forwarded-Access-Token": false,
@@ -679,6 +715,7 @@ func TestStripAuthHeaders(t *testing.T) {
679715 PassAuthorization: false,
680716 StrippedHeaders: map[string]bool{
681717 "X-Forwarded-User": false,
718+ "X-Forwared-Groups": false,
682719 "X-Forwarded-Email": false,
683720 "X-Forwarded-Preferred-Username": false,
684721 "X-Forwarded-Access-Token": false,
@@ -690,6 +727,7 @@ func TestStripAuthHeaders(t *testing.T) {
690727 initialHeaders := map[string]string{
691728 "X-Forwarded-User": "9fcab5c9b889a557",
692729 "X-Forwarded-Email": "john.doe@example.com",
730+ "X-Forwarded-Groups": "a,b,c",
693731 "X-Forwarded-Preferred-Username": "john.doe",
694732 "X-Forwarded-Access-Token": "AccessToken",
695733 "Authorization": "bearer IDToken",
@@ -1333,6 +1371,7 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
13331371
13341372 pcTest.opts = baseTestOptions()
13351373 pcTest.opts.SetXAuthRequest = true
1374+ pcTest.opts.AllowedGroups = []string{"oauth_groups"}
13361375 err := validation.Validate(pcTest.opts)
13371376 assert.NoError(t, err)
13381377
@@ -1354,13 +1393,14 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
13541393
13551394 created := time.Now()
13561395 startSession := &sessions.SessionState{
1357− User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token", CreatedAt: &created}
1396+ User: "oauth_user", Groups: []string{"oauth_groups"}, Email: "oauth_user@example.com", AccessToken: "oauth_token", CreatedAt: &created}
13581397 err = pcTest.SaveSession(startSession)
13591398 assert.NoError(t, err)
13601399
13611400 pcTest.proxy.ServeHTTP(pcTest.rw, pcTest.req)
13621401 assert.Equal(t, http.StatusAccepted, pcTest.rw.Code)
13631402 assert.Equal(t, "oauth_user", pcTest.rw.Header().Get("X-Auth-Request-User"))
1403+ assert.Equal(t, startSession.Groups, pcTest.rw.Header().Values("X-Auth-Request-Groups"))
13641404 assert.Equal(t, "oauth_user@example.com", pcTest.rw.Header().Get("X-Auth-Request-Email"))
13651405}
13661406
@@ -2199,3 +2239,108 @@ func TestTrustedIPs(t *testing.T) {
21992239 })
22002240 }
22012241}
2242+
2243+func TestProxyAllowedGroups(t *testing.T) {
2244+ tests := []struct {
2245+ name string
2246+ allowedGroups []string
2247+ groups []string
2248+ expectUnauthorized bool
2249+ }{
2250+ {"NoAllowedGroups", []string{}, []string{}, false},
2251+ {"NoAllowedGroupsUserHasGroups", []string{}, []string{"a", "b"}, false},
2252+ {"UserInAllowedGroup", []string{"a"}, []string{"a", "b"}, false},
2253+ {"UserNotInAllowedGroup", []string{"a"}, []string{"c"}, true},
2254+ }
2255+
2256+ for _, tt := range tests {
2257+ t.Run(tt.name, func(t *testing.T) {
2258+ emailAddress := "test"
2259+ created := time.Now()
2260+
2261+ session := &sessions.SessionState{
2262+ Groups: tt.groups,
2263+ Email: emailAddress,
2264+ AccessToken: "oauth_token",
2265+ CreatedAt: &created,
2266+ }
2267+
2268+ upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2269+ w.WriteHeader(200)
2270+ }))
2271+ t.Cleanup(upstream.Close)
2272+
2273+ test, err := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
2274+ opts.AllowedGroups = tt.allowedGroups
2275+ opts.UpstreamServers = options.Upstreams{
2276+ {
2277+ ID: upstream.URL,
2278+ Path: "/",
2279+ URI: upstream.URL,
2280+ },
2281+ }
2282+ })
2283+ if err != nil {
2284+ t.Fatal(err)
2285+ }
2286+
2287+ test.req, _ = http.NewRequest("GET", "/", nil)
2288+
2289+ test.req.Header.Add("accept", applicationJSON)
2290+ test.SaveSession(session)
2291+ test.proxy.ServeHTTP(test.rw, test.req)
2292+
2293+ if tt.expectUnauthorized {
2294+ assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
2295+ } else {
2296+ assert.Equal(t, http.StatusOK, test.rw.Code)
2297+ }
2298+ })
2299+ }
2300+}
2301+
2302+func TestAuthOnlyAllowedGroups(t *testing.T) {
2303+ tests := []struct {
2304+ name string
2305+ allowedGroups []string
2306+ groups []string
2307+ expectUnauthorized bool
2308+ }{
2309+ {"NoAllowedGroups", []string{}, []string{}, false},
2310+ {"NoAllowedGroupsUserHasGroups", []string{}, []string{"a", "b"}, false},
2311+ {"UserInAllowedGroup", []string{"a"}, []string{"a", "b"}, false},
2312+ {"UserNotInAllowedGroup", []string{"a"}, []string{"c"}, true},
2313+ }
2314+
2315+ for _, tt := range tests {
2316+ t.Run(tt.name, func(t *testing.T) {
2317+ emailAddress := "test"
2318+ created := time.Now()
2319+
2320+ session := &sessions.SessionState{
2321+ Groups: tt.groups,
2322+ Email: emailAddress,
2323+ AccessToken: "oauth_token",
2324+ CreatedAt: &created,
2325+ }
2326+
2327+ test, err := NewAuthOnlyEndpointTest(func(opts *options.Options) {
2328+ opts.AllowedGroups = tt.allowedGroups
2329+ })
2330+ if err != nil {
2331+ t.Fatal(err)
2332+ }
2333+
2334+ err = test.SaveSession(session)
2335+ assert.NoError(t, err)
2336+
2337+ test.proxy.ServeHTTP(test.rw, test.req)
2338+
2339+ if tt.expectUnauthorized {
2340+ assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
2341+ } else {
2342+ assert.Equal(t, http.StatusAccepted, test.rw.Code)
2343+ }
2344+ })
2345+ }
2346+}