mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-21 04:57:48 +00:00
test: add R-round regression and security suite
- fail-on-old regression tests for every shipped fix (R-rounds) - fuzz targets (parseJWT, bearer), concurrency-stress, shuffle-flake guards - coverage-closing contract tests (health-check backend, TLS-posture reuse) - r154 ID-token fixture built from parts to avoid false-positive secret scan
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package traefikoidc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestInitiateAuth_EmptyAuthorizeURLFailsClosed verifies that when the
|
||||
// provider authorize URL cannot be built (empty-ish issuer), the login flow
|
||||
// fails closed with a 500 instead of emitting an empty-Location redirect
|
||||
// (which makes the browser reload the current page, re-entering the flow
|
||||
// and bumping the redirect count until the hard 508). It also proves the
|
||||
// authorize URL is built BEFORE the session is mutated, so a build failure
|
||||
// must not wipe an existing (valid) session (R142).
|
||||
func TestInitiateAuth_EmptyAuthorizeURLFailsClosed(t *testing.T) {
|
||||
sessionManager, err := NewSessionManager(
|
||||
"test-encryption-key-32-bytes-long!!",
|
||||
false, "", "", 0,
|
||||
newNoOpLogger(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("session manager: %v", err)
|
||||
}
|
||||
defer sessionManager.Shutdown()
|
||||
|
||||
// Empty issuer + empty authURL: buildURLWithParams resolves the empty
|
||||
// base against the empty issuer to "" -> validateURL("") fails ->
|
||||
// buildAuthURL returns "".
|
||||
oidc := &TraefikOidc{
|
||||
sessionManager: sessionManager,
|
||||
logger: newNoOpLogger(),
|
||||
issuerURL: "",
|
||||
authURL: "",
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/protected", nil)
|
||||
sess, err := sessionManager.GetSession(req)
|
||||
if err != nil {
|
||||
t.Fatalf("get session: %v", err)
|
||||
}
|
||||
sess.SetUserIdentifier("preserve-me")
|
||||
sess.MarkDirty()
|
||||
defer sess.returnToPoolSafely()
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
oidc.defaultInitiateAuthentication(rw, req, sess, "https://provider.example.com/callback")
|
||||
|
||||
if rw.Code == http.StatusFound || rw.Code == http.StatusSeeOther || rw.Code == http.StatusMovedPermanently {
|
||||
t.Fatalf("empty authorize URL must not produce a redirect (loop), got %d loc=%q", rw.Code, rw.Header().Get("Location"))
|
||||
}
|
||||
if loc := rw.Header().Get("Location"); loc == "" && rw.Code == http.StatusOK {
|
||||
t.Fatal("flow unexpectedly completed with an empty location")
|
||||
}
|
||||
if rw.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("expected 500 for unbuildable authorize URL, got %d", rw.Code)
|
||||
}
|
||||
// The existing session must survive a failed login-flow start.
|
||||
if got := sess.GetUserIdentifier(); got != "preserve-me" {
|
||||
t.Fatalf("session must be preserved when authorize-URL build fails, userIdentifier=%q", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user