fix(auth): preserve shared signed-session challenge identity

This commit is contained in:
zarzet
2026-09-06 02:33:42 +07:00
parent 2ef2beb621
commit fdb4a0eaa5
2 changed files with 62 additions and 18 deletions
+10 -18
View File
@@ -180,15 +180,17 @@ func (c *signedSessionCoordinator) clearChallenge() {
c.pendingExtensionIDs = nil
}
func (c *signedSessionCoordinator) rememberChallenge(extensionID, authURL, callbackURL, callbackState string) {
func (c *signedSessionCoordinator) rememberChallenge(request *PendingAuthRequest) {
if c.pendingExtensionIDs == nil {
c.pendingExtensionIDs = make(map[string]struct{})
}
c.authURL = authURL
c.callbackURL = callbackURL
c.callbackState = callbackState
c.challengeCreatedAt = time.Now()
c.pendingExtensionIDs[extensionID] = struct{}{}
c.authURL = request.AuthURL
c.callbackURL = request.CallbackURL
c.callbackState = request.State
// Reusers must register the exact same challenge identity, including its
// original timestamp. A fresh time both breaks nonce sharing and extends TTL.
c.challengeCreatedAt = request.CreatedAt
c.pendingExtensionIDs[request.ExtensionID] = struct{}{}
}
func (c *signedSessionCoordinator) activeChallenge() bool {
@@ -1285,12 +1287,7 @@ func (r *extensionRuntime) startSignedSessionVerificationLocked(
if pending := GetPendingAuthRequest(r.extensionID); pending != nil {
if time.Since(pending.CreatedAt) < pendingAuthRequestTTL &&
strings.TrimSpace(pending.AuthURL) != "" {
coordinator.rememberChallenge(
r.extensionID,
pending.AuthURL,
pending.CallbackURL,
pending.State,
)
coordinator.rememberChallenge(pending)
return pending.AuthURL, nil
}
ClearPendingAuthRequest(r.extensionID)
@@ -1367,12 +1364,7 @@ func (r *extensionRuntime) startSignedSessionVerificationLocked(
if registerErr := registerPendingAuthRequest(request); registerErr != nil {
finalErr = registerErr
} else {
coordinator.rememberChallenge(
r.extensionID,
bootstrap.AuthURL,
bootstrap.CallbackURL,
bootstrap.CallbackState,
)
coordinator.rememberChallenge(request)
authURL = bootstrap.AuthURL
}
}
@@ -437,6 +437,58 @@ func TestParallelSignedSessionPreflightSharesOneBootstrap(t *testing.T) {
if got := calls.Load(); got != 1 {
t.Fatalf("parallel preflight bootstrap calls = %d, want 1", got)
}
pendingA := GetPendingAuthRequest("provider-a")
pendingB := GetPendingAuthRequest("provider-b")
if pendingA == nil || pendingB == nil || pendingA.State != pendingB.State ||
!pendingA.CreatedAt.Equal(pendingB.CreatedAt) {
t.Fatal("shared bootstrap must preserve the same nonce and creation time")
}
if _, err := ConsumeExtensionCallbackState(pendingA.State); err != nil {
t.Fatalf("shared callback cannot be consumed: %v", err)
}
if GetPendingAuthRequest("provider-a") != nil || GetPendingAuthRequest("provider-b") != nil {
t.Fatal("consuming a shared callback must clear every alias")
}
if _, err := ConsumeExtensionCallbackState(pendingA.State); err == nil {
t.Fatal("shared callback replay was accepted")
}
}
func TestRememberSignedSessionChallengePreservesOriginalLifetime(t *testing.T) {
request := &PendingAuthRequest{
ExtensionID: "remember-original", AuthURL: "https://auth.example.com/challenge",
CallbackURL: "spotiflac://callback", State: "remember-original-state",
CreatedAt: time.Now().Add(-2 * time.Minute),
}
if err := registerPendingAuthRequest(request); err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
ClearPendingAuthRequest("remember-original")
ClearPendingAuthRequest("remember-shared")
})
coordinator := &signedSessionCoordinator{}
coordinator.rememberChallenge(request)
if !coordinator.challengeCreatedAt.Equal(request.CreatedAt) {
t.Fatal("remembering an existing challenge reset its TTL")
}
runtime := &extensionRuntime{extensionID: "remember-shared"}
coordinator.mu.Lock()
_, err := runtime.startSignedSessionVerificationLocked(SignedSessionConfig{}, coordinator, "test")
coordinator.mu.Unlock()
if err != nil {
t.Fatalf("reusing a remembered challenge: %v", err)
}
shared := GetPendingAuthRequest("remember-shared")
if shared == nil || !shared.CreatedAt.Equal(request.CreatedAt) {
t.Fatal("shared request lost the original challenge timestamp")
}
expired := *request
expired.CreatedAt = time.Now().Add(-pendingAuthRequestTTL - time.Second)
coordinator.rememberChallenge(&expired)
if coordinator.activeChallenge() {
t.Fatal("remembering an expired challenge made it active again")
}
}
func TestParallelSignedSessionPreflightSharesBootstrapFailure(t *testing.T) {