package wsauth import ( "testing" "time" ) func TestSHA256Vector(t *testing.T) { // Known vector — keeps us honest against accidental algorithm changes. got := ComputeSHA256("abc") want := "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" if got != want { t.Fatalf("SHA256(abc): got %s want %s", got, want) } } func TestLoginRoundTripAdminEmptySalt(t *testing.T) { a := New() a.AddAdminFromPlainPassword("admin", "hunter2") salt, ok := a.GetSalt("admin") if !ok || salt != "" { t.Fatalf("admin salt: ok=%v salt=%q", ok, salt) } // Simulate the browser: nonce = "abc123", response = SHA256(passwordHash + nonce) nonce := "abc123" passwordHash := ComputeSHA256("hunter2") response := ComputeSHA256(passwordHash + nonce) token, role, err := a.VerifyLogin("admin", response, nonce) if err != nil { t.Fatalf("VerifyLogin: %v", err) } if role != "admin" { t.Fatalf("role: got %q want admin", role) } if len(token) != 2*tokenBytes { t.Fatalf("token length: got %d want %d", len(token), 2*tokenBytes) } sess, err := a.ValidateToken(token) if err != nil { t.Fatalf("ValidateToken: %v", err) } if sess.Username != "admin" || sess.Role != "admin" { t.Fatalf("session: %+v", sess) } } func TestLoginRoundTripViewerWithSalt(t *testing.T) { a := New() salt, _ := NewSalt() a.AddUser(User{ Username: "alice", PasswordHash: HashPassword("p@ss", salt), Salt: salt, Role: "viewer", }) gotSalt, ok := a.GetSalt("alice") if !ok || gotSalt != salt { t.Fatalf("salt: ok=%v got=%q want=%q", ok, gotSalt, salt) } nonce, _ := NewNonce() response := ComputeSHA256(HashPassword("p@ss", salt) + nonce) _, role, err := a.VerifyLogin("alice", response, nonce) if err != nil || role != "viewer" { t.Fatalf("VerifyLogin: role=%q err=%v", role, err) } } func TestLoginRejectsWrongResponse(t *testing.T) { a := New() a.AddAdminFromPlainPassword("admin", "x") _, _, err := a.VerifyLogin("admin", "deadbeef", "nonce") if err == nil { t.Fatal("expected error for bad response") } _, _, err = a.VerifyLogin("ghost", "anything", "anything") if err == nil { t.Fatal("expected error for unknown user") } } func TestTokenExpiry(t *testing.T) { a := New() a.SetTokenExpire(50 * time.Millisecond) a.AddAdminFromPlainPassword("admin", "x") nonce, _ := NewNonce() response := ComputeSHA256(ComputeSHA256("x") + nonce) token, _, err := a.VerifyLogin("admin", response, nonce) if err != nil { t.Fatal(err) } if _, err := a.ValidateToken(token); err != nil { t.Fatalf("fresh token should validate: %v", err) } time.Sleep(80 * time.Millisecond) if _, err := a.ValidateToken(token); err == nil { t.Fatal("expired token should not validate") } } func TestRevoke(t *testing.T) { a := New() a.AddAdminFromPlainPassword("admin", "x") nonce, _ := NewNonce() response := ComputeSHA256(ComputeSHA256("x") + nonce) token, _, _ := a.VerifyLogin("admin", response, nonce) a.RevokeToken(token) if _, err := a.ValidateToken(token); err == nil { t.Fatal("revoked token should not validate") } }