Download internal/auth/admin_security_test.go from a3216/ds2api: direct link, hf CLI and curl.
- Browser
- Download file 7.59 kB
-
https://huggingface.co/spaces/a3216/ds2api/resolve/ce5a019598af8a3a8fa70d3880098df3e850ecd7/internal/auth/admin_security_test.go
- Command line
-
hf download hf://spaces/a3216/ds2api@ce5a019598af8a3a8fa70d3880098df3e850ecd7/internal/auth/admin_security_test.go
-
curl -L -o admin_security_test.go https://huggingface.co/spaces/a3216/ds2api/resolve/ce5a019598af8a3a8fa70d3880098df3e850ecd7/internal/auth/admin_security_test.go
7.59 kB
| package auth | |
| import ( | |
| "crypto/hmac" | |
| "crypto/sha256" | |
| "encoding/json" | |
| "net/http" | |
| "net/http/httptest" | |
| "os" | |
| "strings" | |
| "testing" | |
| "ds2api/internal/config" | |
| ) | |
| // stubStore implements AdminConfigReader for testing without pulling in the | |
| // full config store. We intentionally use a struct (not a mock) so the test | |
| // exercises the real auth code paths. | |
| type stubStore struct { | |
| passwordHash string | |
| expireHours int | |
| validAfter int64 | |
| } | |
| func (s stubStore) AdminPasswordHash() string { return s.passwordHash } | |
| func (s stubStore) AdminJWTExpireHours() int { return s.expireHours } | |
| func (s stubStore) AdminJWTValidAfterUnix() int64 { return s.validAfter } | |
| func TestEffectiveAdminKeyNeverReturnsHardcodedDefault(t *testing.T) { | |
| // Security: ensure the historical "admin" default is gone. If this test | |
| // ever fails, it means a regression reintroduced a publicly-known default | |
| // credential that would let anyone log in to deployments without | |
| // DS2API_ADMIN_KEY set. | |
| t.Setenv("DS2API_ADMIN_KEY", "") | |
| t.Setenv("DS2API_CONFIG_JSON", "") | |
| stub := stubStore{} | |
| if got := effectiveAdminKey(stub); got != "" { | |
| t.Fatalf("effectiveAdminKey with no env and no password hash must be empty, got %q", got) | |
| } | |
| if got := AdminKey(); got != "" { | |
| t.Fatalf("AdminKey() with no env must be empty, got %q", got) | |
| } | |
| } | |
| func TestVerifyAdminCredentialRejectsEmptyAndDefaultAdmin(t *testing.T) { | |
| // Security: with no admin key configured and no password hash, login | |
| // MUST be impossible — even if an attacker tries "admin" or empty string. | |
| t.Setenv("DS2API_ADMIN_KEY", "") | |
| t.Setenv("DS2API_CONFIG_JSON", "") | |
| stub := stubStore{} | |
| for _, candidate := range []string{"", "admin", "password", "123456", "default"} { | |
| if VerifyAdminCredential(candidate, stub) { | |
| t.Fatalf("VerifyAdminCredential must reject %q when no credentials configured", candidate) | |
| } | |
| } | |
| } | |
| func TestVerifyAdminCredentialRejectsKnownDefaultAdminWithEnvSet(t *testing.T) { | |
| // Security: when DS2API_ADMIN_KEY is set to a strong value, the literal | |
| // "admin" must NOT authenticate. | |
| t.Setenv("DS2API_ADMIN_KEY", "a-strong-and-random-key-12345") | |
| t.Setenv("DS2API_CONFIG_JSON", "") | |
| stub := stubStore{} | |
| if VerifyAdminCredential("admin", stub) { | |
| t.Fatal("VerifyAdminCredential must reject literal \"admin\" when env key is set to something else") | |
| } | |
| if !VerifyAdminCredential("a-strong-and-random-key-12345", stub) { | |
| t.Fatal("VerifyAdminCredential must accept the configured env key") | |
| } | |
| } | |
| func TestJWTSecretNotHardcodedAdminWhenUnconfigured(t *testing.T) { | |
| // Security: when no DS2API_JWT_SECRET, no password hash, and no | |
| // DS2API_ADMIN_KEY are configured, the JWT signing secret must NOT be | |
| // the historical hardcoded "admin". A process-local random secret is | |
| // used instead so attackers cannot forge tokens. | |
| t.Setenv("DS2API_ADMIN_KEY", "") | |
| t.Setenv("DS2API_JWT_SECRET", "") | |
| t.Setenv("DS2API_CONFIG_JSON", "") | |
| secret := jwtSecret(nil) | |
| if secret == "admin" { | |
| t.Fatal("jwtSecret must not fall back to hardcoded \"admin\"") | |
| } | |
| if secret == "" { | |
| t.Fatal("jwtSecret must be non-empty so token signing is non-trivial") | |
| } | |
| // The fallback secret must be process-stable (same value across calls). | |
| if secret != jwtSecret(nil) { | |
| t.Fatal("jwtSecret fallback must be process-stable so minted tokens verify") | |
| } | |
| } | |
| func TestJWTForgedWithAdminSecretFailsVerification(t *testing.T) { | |
| // Security: an attacker who knows the historical default "admin" cannot | |
| // forge a token that verifies when no credentials are configured, because | |
| // the actual signing secret is a process-local random value. | |
| t.Setenv("DS2API_ADMIN_KEY", "") | |
| t.Setenv("DS2API_JWT_SECRET", "") | |
| // Forge a token signed with the historical "admin" secret. | |
| header := map[string]any{"alg": "HS256", "typ": "JWT"} | |
| payload := map[string]any{ | |
| "iat": 0, | |
| "exp": 9999999999, | |
| "role": "admin", | |
| } | |
| h, _ := json.Marshal(header) | |
| p, _ := json.Marshal(payload) | |
| msg := rawB64Encode(h) + "." + rawB64Encode(p) | |
| mac := hmac.New(sha256.New, []byte("admin")) | |
| _, _ = mac.Write([]byte(msg)) | |
| forgedSig := mac.Sum(nil) | |
| forged := msg + "." + rawB64Encode(forgedSig) | |
| if _, err := VerifyJWT(forged); err == nil { | |
| t.Fatal("forged token signed with hardcoded \"admin\" secret must NOT verify") | |
| } | |
| } | |
| func TestAdminLoginDisabledWithoutCredentials(t *testing.T) { | |
| // Security: end-to-end check that VerifyAdminRequestWithStore rejects | |
| // Bearer tokens when no credentials are configured, regardless of what | |
| // string the attacker supplies. | |
| t.Setenv("DS2API_ADMIN_KEY", "") | |
| t.Setenv("DS2API_CONFIG_JSON", "") | |
| stub := stubStore{} | |
| for _, token := range []string{"admin", "", "Bearer admin", "anything"} { | |
| req := httptest.NewRequest(http.MethodGet, "/admin/config", nil) | |
| req.Header.Set("Authorization", "Bearer "+token) | |
| if err := VerifyAdminRequestWithStore(req, stub); err == nil { | |
| t.Fatalf("VerifyAdminRequestWithStore must reject token %q when no credentials configured", token) | |
| } | |
| } | |
| } | |
| func TestAdminLoginWithConfiguredPasswordHash(t *testing.T) { | |
| // Regression: ensure password-hash based login still works after the | |
| // default-removal change. | |
| t.Setenv("DS2API_ADMIN_KEY", "") | |
| t.Setenv("DS2API_JWT_SECRET", "") | |
| stub := stubStore{passwordHash: HashAdminPassword("super-secret-pw")} | |
| if !VerifyAdminCredential("super-secret-pw", stub) { | |
| t.Fatal("VerifyAdminCredential must accept the configured password") | |
| } | |
| if VerifyAdminCredential("wrong-password", stub) { | |
| t.Fatal("VerifyAdminCredential must reject wrong password") | |
| } | |
| // JWT secret must derive from the password hash, not the empty admin key. | |
| secret := jwtSecret(stub) | |
| if secret != strings.TrimSpace(stub.passwordHash) { | |
| t.Fatalf("jwtSecret must be the password hash when no env secret set, got %q", secret) | |
| } | |
| } | |
| func TestAdminLoginWithEnvKey(t *testing.T) { | |
| // Regression: ensure env-key based login still works after the change. | |
| t.Setenv("DS2API_ADMIN_KEY", "env-key-12345") | |
| t.Setenv("DS2API_JWT_SECRET", "") | |
| stub := stubStore{} | |
| if !VerifyAdminCredential("env-key-12345", stub) { | |
| t.Fatal("VerifyAdminCredential must accept the configured env key") | |
| } | |
| if VerifyAdminCredential("env-key-99999", stub) { | |
| t.Fatal("VerifyAdminCredential must reject wrong env key") | |
| } | |
| } | |
| func TestAdminLoginWithJWTSecretEnv(t *testing.T) { | |
| // Regression: ensure an explicit JWT secret takes precedence and works | |
| // for both signing and verifying. | |
| t.Setenv("DS2API_ADMIN_KEY", "env-key-12345") | |
| t.Setenv("DS2API_JWT_SECRET", "explicit-jwt-secret") | |
| stub := stubStore{} | |
| if jwtSecret(stub) != "explicit-jwt-secret" { | |
| t.Fatalf("jwtSecret must use explicit env value, got %q", jwtSecret(stub)) | |
| } | |
| token, err := CreateJWTWithStore(1, stub) | |
| if err != nil { | |
| t.Fatalf("CreateJWTWithStore failed: %v", err) | |
| } | |
| if _, err := VerifyJWTWithStore(token, stub); err != nil { | |
| t.Fatalf("VerifyJWTWithStore failed: %v", err) | |
| } | |
| } | |
| // usingRealStoreHelper wraps a minimal config.Store so we exercise the same | |
| // store code paths used in production. We avoid pulling in the full server. | |
| func TestUsingRealStoreNoCredentials(t *testing.T) { | |
| if os.Getenv("DS2API_RUN_REAL_STORE_TEST") == "" { | |
| t.Skip("skipping real-store test; set DS2API_RUN_REAL_STORE_TEST=1 to run") | |
| } | |
| t.Setenv("DS2API_ADMIN_KEY", "") | |
| t.Setenv("DS2API_JWT_SECRET", "") | |
| t.Setenv("DS2API_CONFIG_JSON", "{}") | |
| store := config.LoadStore() | |
| if !UsingDefaultAdminKey(store) { | |
| t.Fatal("UsingDefaultAdminKey must be true when nothing is configured") | |
| } | |
| if VerifyAdminCredential("admin", store) { | |
| t.Fatal("VerifyAdminCredential must reject \"admin\" with no credentials configured") | |
| } | |
| } | |