Migration This is my new public git source viewer. Source coming soon. Please contact with concerns/bugs. Contact me

internal/notices/handler_test.go

4bda28df3ab3dbfcc789dcbbb184cabc8cac9398 · 3.3 KB · 114 lines raw

1 package notices
2
3 import (
4 "log/slog"
5 "net/http"
6 "net/http/httptest"
7 "path/filepath"
8 "testing"
9 )
10
11 func testHandler(t *testing.T, cfg HandlerConfig) http.Handler {
12 t.Helper()
13 store, err := Open(filepath.Join(t.TempDir(), "notices.yaml"))
14 if err != nil {
15 t.Fatalf("Open: %v", err)
16 }
17 t.Cleanup(store.Close)
18 cfg.Store = store
19 if cfg.Logger == nil {
20 cfg.Logger = slog.Default()
21 }
22 h, err := NewHandler(cfg)
23 if err != nil {
24 t.Fatalf("NewHandler: %v", err)
25 }
26 return h
27 }
28
29 // Without RequiredGroup, the handler behaves exactly as it always did:
30 // reaching it at all is enough, regardless of any group header.
31 func TestHandlerNoGroupGateByDefault(t *testing.T) {
32 h := testHandler(t, HandlerConfig{})
33
34 req := httptest.NewRequest("GET", "/admin/notices", nil)
35 rec := httptest.NewRecorder()
36 h.ServeHTTP(rec, req)
37 if rec.Code != http.StatusOK {
38 t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
39 }
40 }
41
42 // With RequiredGroup set, a caller whose GroupHeader doesn't list it is
43 // refused before the handler does anything else -- no CSRF cookie, no page.
44 func TestHandlerRejectsMissingGroup(t *testing.T) {
45 h := testHandler(t, HandlerConfig{RequiredGroup: "gsg-admins"})
46
47 cases := []struct {
48 name string
49 groups string
50 }{
51 {"no header", ""},
52 {"different group", "some-other-group"},
53 {"prefix collision", "gsg-admins-extra"},
54 }
55 for _, tc := range cases {
56 t.Run(tc.name, func(t *testing.T) {
57 req := httptest.NewRequest("GET", "/admin/notices", nil)
58 if tc.groups != "" {
59 req.Header.Set("X-Authentik-Groups", tc.groups)
60 }
61 rec := httptest.NewRecorder()
62 h.ServeHTTP(rec, req)
63 if rec.Code != http.StatusForbidden {
64 t.Fatalf("status = %d, want %d", rec.Code, http.StatusForbidden)
65 }
66 if rec.Result().Cookies() != nil && len(rec.Result().Cookies()) != 0 {
67 t.Errorf("rejected request set cookies: %v", rec.Result().Cookies())
68 }
69 })
70 }
71 }
72
73 // A member -- anywhere in the "|"-delimited list, with incidental
74 // whitespace -- is let through.
75 func TestHandlerAllowsMemberGroup(t *testing.T) {
76 h := testHandler(t, HandlerConfig{RequiredGroup: "gsg-admins"})
77
78 cases := []string{
79 "gsg-admins",
80 "other-group|gsg-admins",
81 "gsg-admins|other-group",
82 "other-group| gsg-admins |another",
83 }
84 for _, groups := range cases {
85 req := httptest.NewRequest("GET", "/admin/notices", nil)
86 req.Header.Set("X-Authentik-Groups", groups)
87 rec := httptest.NewRecorder()
88 h.ServeHTTP(rec, req)
89 if rec.Code != http.StatusOK {
90 t.Errorf("groups=%q: status = %d, want %d", groups, rec.Code, http.StatusOK)
91 }
92 }
93 }
94
95 // A custom GroupHeader is honored instead of the Authentik default.
96 func TestHandlerCustomGroupHeader(t *testing.T) {
97 h := testHandler(t, HandlerConfig{RequiredGroup: "gsg-admins", GroupHeader: "X-Custom-Groups"})
98
99 req := httptest.NewRequest("GET", "/admin/notices", nil)
100 req.Header.Set("X-Authentik-Groups", "gsg-admins") // wrong header, should not count
101 rec := httptest.NewRecorder()
102 h.ServeHTTP(rec, req)
103 if rec.Code != http.StatusForbidden {
104 t.Fatalf("status = %d, want %d (wrong header should not authorize)", rec.Code, http.StatusForbidden)
105 }
106
107 req = httptest.NewRequest("GET", "/admin/notices", nil)
108 req.Header.Set("X-Custom-Groups", "gsg-admins")
109 rec = httptest.NewRecorder()
110 h.ServeHTTP(rec, req)
111 if rec.Code != http.StatusOK {
112 t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
113 }
114 }