package session import ( "net/http" "net/http/httptest" "testing" ) // TestSessionCookieAttributesAlwaysSecure verifies that every cookie // emitted by the session manager carries HttpOnly, Secure, and a // SameSite mode of Lax or stricter, regardless of how the manager was // constructed. Session cookies contain the authentication state and // must never be exposed to script (HttpOnly), sent over plaintext HTTP // (Secure), or attached to cross-site requests (SameSite). No // constructor argument may weaken these attributes. // // This covers both cookie-writing paths: CreateSession (the login // set-cookie path) and ClearSession (the logout delete-cookie path). func TestSessionCookieAttributesAlwaysSecure(t *testing.T) { for _, constructorBoolArg := range []bool{false, true} { mgr, err := NewManager("test-signing-key-12345", constructorBoolArg) if err != nil { t.Fatalf("NewManager() error = %v", err) } writePaths := []struct { name string setCookie func(t *testing.T, w http.ResponseWriter) }{ { name: "CreateSession", setCookie: func(t *testing.T, w http.ResponseWriter) { t.Helper() if err := mgr.CreateSession(w); err != nil { t.Fatalf("CreateSession() error = %v", err) } }, }, { name: "ClearSession", setCookie: func(t *testing.T, w http.ResponseWriter) { t.Helper() mgr.ClearSession(w) }, }, } for _, writePath := range writePaths { testName := writePath.name if constructorBoolArg { testName += "/constructorBoolArg=true" } else { testName += "/constructorBoolArg=false" } t.Run(testName, func(t *testing.T) { w := httptest.NewRecorder() writePath.setCookie(t, w) var sessionCookie *http.Cookie for _, c := range w.Result().Cookies() { if c.Name == CookieName { sessionCookie = c break } } if sessionCookie == nil { t.Fatalf("no cookie named %q was set", CookieName) } t.Logf("cookie attributes: HttpOnly=%v Secure=%v SameSite=%v", sessionCookie.HttpOnly, sessionCookie.Secure, sessionCookie.SameSite) if !sessionCookie.HttpOnly { t.Error("session cookie must have HttpOnly set") } if !sessionCookie.Secure { t.Error("session cookie must have Secure set") } if sessionCookie.SameSite != http.SameSiteLaxMode && sessionCookie.SameSite != http.SameSiteStrictMode { t.Errorf("session cookie SameSite = %v, want Lax (%v) or Strict (%v)", sessionCookie.SameSite, http.SameSiteLaxMode, http.SameSiteStrictMode) } }) } } }