package auth import ( "net/http" "net/http/httptest" "strings" "testing" ) func TestPermit(t *testing.T) { m := New("X-Forwarded-Groups", []string{"akP-mediamark-user", "akR-admins"}) cases := []struct { name string values []string want bool }{ {"no header", nil, false}, {"empty header", []string{""}, false}, {"exact match", []string{"akP-mediamark-user"}, true}, {"comma list containing match", []string{"akP-other,akP-mediamark-user,akP-x"}, true}, {"space separated", []string{"akP-other akR-admins"}, true}, {"padded", []string{" akP-mediamark-user "}, true}, {"repeated header lines", []string{"akP-nope", "akR-admins"}, true}, {"unrelated groups only", []string{"akP-arrstack-kids,akP-nope"}, false}, {"prefix lookalike", []string{"akP-mediamark-users"}, false}, {"substring lookalike", []string{"xakP-mediamark-user"}, false}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/api/library/movies", nil) for _, v := range c.values { r.Header.Add("X-Forwarded-Groups", v) } if got := m.Permit(r); got != c.want { t.Fatalf("Permit = %v, want %v", got, c.want) } }) } } func TestEmptyAllowListDeniesEverything(t *testing.T) { m := New("X-Forwarded-Groups", nil) r := httptest.NewRequest(http.MethodGet, "/", nil) r.Header.Set("X-Forwarded-Groups", "anything") if m.Permit(r) { t.Fatal("empty allow-list permitted a request") } } func TestWrapBlocksAndPasses(t *testing.T) { m := New("X-Grp", []string{"good"}) called := false h := m.Wrap(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { called = true w.WriteHeader(http.StatusTeapot) })) rec := httptest.NewRecorder() req := httptest.NewRequest(http.MethodPost, "/api/library/movies/x/mark", nil) req.Header.Set("X-Grp", "bad,worse") h.ServeHTTP(rec, req) if rec.Code != http.StatusForbidden { t.Fatalf("status = %d, want 403", rec.Code) } if called { t.Fatal("handler ran despite a forbidden request") } // The rejection must not echo the submitted groups back. if strings.Contains(rec.Body.String(), "worse") { t.Fatalf("403 body echoed submitted groups: %q", rec.Body.String()) } rec = httptest.NewRecorder() req = httptest.NewRequest(http.MethodPost, "/api/library/movies/x/mark", nil) req.Header.Set("X-Grp", "good") h.ServeHTTP(rec, req) if rec.Code != http.StatusTeapot || !called { t.Fatalf("allowed request not passed through: status %d called %v", rec.Code, called) } } // The configured header is the only one trusted; a client-forged alternative // must not grant access. func TestOnlyConfiguredHeaderIsRead(t *testing.T) { m := New("X-Auth-Request-Groups", []string{"good"}) r := httptest.NewRequest(http.MethodGet, "/", nil) r.Header.Set("X-Forwarded-Groups", "good") if m.Permit(r) { t.Fatal("a non-configured header granted access") } }