| 1 | package calls |
| 2 | |
| 3 | import ( |
| 4 | "net/http" |
| 5 | "net/http/httptest" |
| 6 | "strings" |
| 7 | "testing" |
| 8 | |
| 9 | "amadan.net/rastrillo/rastrillo" |
| 10 | ) |
| 11 | |
| 12 | // TestHomeCSPPreservesPinnedFrameworkDirectives: with Home configured, |
| 13 | // connect's middleware sends homeFormPolicy on every page in the group, |
| 14 | // which is rastrillo's default policy (inline styles refused) with only |
| 15 | // the issuer added to form-action, so Home mode is no looser than |
| 16 | // standalone. |
| 17 | func TestHomeCSPPreservesPinnedFrameworkDirectives(t *testing.T) { |
| 18 | mux := http.NewServeMux() |
| 19 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) }) |
| 20 | baselineHandler, closeBaseline, err := rastrillo.Handler(rastrillo.Options{Mux: mux}) |
| 21 | if err != nil { |
| 22 | t.Fatal(err) |
| 23 | } |
| 24 | if closeBaseline != nil { |
| 25 | defer closeBaseline() |
| 26 | } |
| 27 | rec := httptest.NewRecorder() |
| 28 | baselineHandler.ServeHTTP(rec, httptest.NewRequest("GET", homeTestOrigin+"/", nil)) |
| 29 | baseline := rec.Header().Get("Content-Security-Policy") |
| 30 | // homeFormPolicy starts from frameworkCSP, rastrillo's default spelled |
| 31 | // out; a bump that changes the default must change it too. |
| 32 | if baseline != frameworkCSP { |
| 33 | t.Fatalf("rastrillo's default CSP is now %q; frameworkCSP still says %q", baseline, frameworkCSP) |
| 34 | } |
| 35 | want := strings.Replace(baseline, "form-action 'self'", "form-action 'self' "+homeTestIssuer, 1) |
| 36 | if want == baseline { |
| 37 | t.Fatal("framework form-action changed") |
| 38 | } |
| 39 | f := newHomeRouterFixture(t) |
| 40 | wrapped, done, err := rastrillo.Handler(rastrillo.Options{Mux: f.handler.(*http.ServeMux)}) |
| 41 | if err != nil { |
| 42 | t.Fatal(err) |
| 43 | } |
| 44 | if done != nil { |
| 45 | defer done() |
| 46 | } |
| 47 | for _, path := range []string{"/signin/local", "/auth/start", "/account/home", "/signed-out", "/auth/verify?token=x"} { |
| 48 | rec := httptest.NewRecorder() |
| 49 | wrapped.ServeHTTP(rec, httptest.NewRequest("GET", homeTestOrigin+path, nil)) |
| 50 | if got := rec.Header().Get("Content-Security-Policy"); got != want { |
| 51 | t.Fatalf("policy drift at %s: %q", path, got) |
| 52 | } |
| 53 | } |
| 54 | } |
| 55 | func TestHomeMutationOriginsAndDuplicateCookies(t *testing.T) { |
| 56 | f := newHomeRouterFixture(t) |
| 57 | f.local(t) |
| 58 | for _, path := range []string{"/signin", "/auth/verify", "/account/home", "/account/home/confirm", "/signout", "/meetings"} { |
| 59 | r := httptest.NewRequest("POST", homeTestOrigin+path, strings.NewReader("address=alice%40example.test")) |
| 60 | r.Header.Set("Origin", "https://other.example.test") |
| 61 | for _, c := range f.cookies { |
| 62 | r.AddCookie(c) |
| 63 | } |
| 64 | w := httptest.NewRecorder() |
| 65 | f.handler.ServeHTTP(w, r) |
| 66 | if w.Code != 403 { |
| 67 | t.Fatal("cross-origin accepted", path, w.Code) |
| 68 | } |
| 69 | } |
| 70 | r := httptest.NewRequest("GET", homeTestOrigin+"/account/home", nil) |
| 71 | for _, c := range f.cookies { |
| 72 | r.AddCookie(c) |
| 73 | r.AddCookie(c) |
| 74 | } |
| 75 | w := httptest.NewRecorder() |
| 76 | f.handler.ServeHTTP(w, r) |
| 77 | if w.Code != 400 { |
| 78 | t.Fatal("duplicate cookies accepted", w.Code) |
| 79 | } |
| 80 | } |
| 81 | func TestHomeCredentialsFailClosedWhenPartial(t *testing.T) { |
| 82 | f := newHomeRouterFixture(t) |
| 83 | cfg := f.app.cfg.Config |
| 84 | for _, name := range []string{"issuer", "consumer", "keys", "dek"} { |
| 85 | broken := *cfg.Home |
| 86 | switch name { |
| 87 | case "issuer": |
| 88 | broken.Issuer = "" |
| 89 | case "consumer": |
| 90 | broken.ConsumerID = "" |
| 91 | case "keys": |
| 92 | broken.KeysBase64 = "" |
| 93 | case "dek": |
| 94 | broken.DEKBase64 = "" |
| 95 | } |
| 96 | cfg.Home = &broken |
| 97 | if _, err := resolve(cfg); err == nil { |
| 98 | t.Fatal("partial accepted", name) |
| 99 | } |
| 100 | cfg = f.app.cfg.Config |
| 101 | } |
| 102 | } |
| 103 | |