From 3d63c5cf106597965f3505d5ea6ea55228e8e4e4 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Fri, 2 Jan 2026 21:13:54 -0800 Subject: [PATCH] test(sts): add comprehensive secret key determinism test coverage Updated tests to verify that secret access keys are now deterministic: 1. Updated TestSTSSessionClaimsToSessionInfoCredentialGeneration: - Changed comment from 'NOT deterministic' to 'NOW deterministic' - Added assertion that same sessionId produces identical secret key - Explains why this is critical for signature verification 2. Added TestSecretAccessKeyDeterminism (new dedicated test): - Verifies secret key is identical across multiple calls with same sessionId - Verifies access key ID and session token are also identical - Verifies different sessionIds produce different credentials - Includes detailed comments explaining why determinism is critical These tests ensure that the STS implementation correctly regenerates deterministic credentials during signature verification. Without determinism, signature verification would always fail because the server would use different secret keys than the client used to sign. --- weed/iam/sts/session_claims_test.go | 66 +++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/weed/iam/sts/session_claims_test.go b/weed/iam/sts/session_claims_test.go index fffe54a64..7408ef5dd 100644 --- a/weed/iam/sts/session_claims_test.go +++ b/weed/iam/sts/session_claims_test.go @@ -71,13 +71,15 @@ func TestSTSSessionClaimsToSessionInfoCredentialGeneration(t *testing.T) { assert.Equal(t, sessionInfo1.Credentials.SessionToken, sessionInfo2.Credentials.SessionToken, "same session ID should produce identical session token (deterministic hash-based generation)") + // Secret access key is NOW deterministic (hash-based on session ID, not random!) + // This is critical for signature verification: the same session ID must regenerate + // the same secret key so that signature verification succeeds. + assert.Equal(t, sessionInfo1.Credentials.SecretAccessKey, sessionInfo2.Credentials.SecretAccessKey, + "same session ID should produce identical secret access key (deterministic hash-based generation)") + // Expiration should match assert.WithinDuration(t, sessionInfo1.Credentials.Expiration, sessionInfo2.Credentials.Expiration, 1*time.Second, "credentials expiration should match") - - // Secret access key is NOT deterministic (uses random.Read), so we just verify it exists - assert.NotEmpty(t, sessionInfo1.Credentials.SecretAccessKey, "secret access key should be generated") - assert.NotEmpty(t, sessionInfo2.Credentials.SecretAccessKey, "secret access key should be generated") } // TestSTSSessionClaimsToSessionInfoPreservesAllFields tests that all fields are preserved @@ -222,3 +224,59 @@ func TestSessionInfoIntegration(t *testing.T) { assert.True(t, sessionInfo.ExpiresAt.After(time.Now()), "session should not be expired") assert.False(t, sessionInfo.Credentials.Expiration.Before(time.Now()), "credentials should not be expired") } + +// TestSecretAccessKeyDeterminism verifies that secret access keys are deterministically +// generated from the session ID. This is CRITICAL for STS signature verification: +// The client generates a secret key and signs the request. When the server receives +// the request, it must regenerate the exact same secret key from the JWT claims +// to verify the signature. If the secret key is random, verification will always fail. +func TestSecretAccessKeyDeterminism(t *testing.T) { + sessionId := "critical-determinism-test" + expiration := time.Now().Add(time.Hour) + + // Generate credentials multiple times with the same session ID + credGen := NewCredentialGenerator() + + cred1, err := credGen.GenerateTemporaryCredentials(sessionId, expiration) + assert.NoError(t, err) + assert.NotNil(t, cred1) + + cred2, err := credGen.GenerateTemporaryCredentials(sessionId, expiration) + assert.NoError(t, err) + assert.NotNil(t, cred2) + + cred3, err := credGen.GenerateTemporaryCredentials(sessionId, expiration) + assert.NoError(t, err) + assert.NotNil(t, cred3) + + // All three should have IDENTICAL secret access keys + assert.Equal(t, cred1.SecretAccessKey, cred2.SecretAccessKey, + "same sessionId must produce identical secret key on first and second call") + assert.Equal(t, cred2.SecretAccessKey, cred3.SecretAccessKey, + "same sessionId must produce identical secret key on second and third call") + + // All three should have IDENTICAL access key IDs + assert.Equal(t, cred1.AccessKeyId, cred2.AccessKeyId, + "same sessionId must produce identical access key ID") + assert.Equal(t, cred2.AccessKeyId, cred3.AccessKeyId, + "same sessionId must produce identical access key ID") + + // All three should have IDENTICAL session tokens + assert.Equal(t, cred1.SessionToken, cred2.SessionToken, + "same sessionId must produce identical session token") + assert.Equal(t, cred2.SessionToken, cred3.SessionToken, + "same sessionId must produce identical session token") + + // Different session IDs should produce different secrets + otherSessionId := "different-session" + credOther, err := credGen.GenerateTemporaryCredentials(otherSessionId, expiration) + assert.NoError(t, err) + assert.NotNil(t, credOther) + + assert.NotEqual(t, cred1.SecretAccessKey, credOther.SecretAccessKey, + "different session IDs must produce different secret keys") + assert.NotEqual(t, cred1.AccessKeyId, credOther.AccessKeyId, + "different session IDs must produce different access key IDs") + assert.NotEqual(t, cred1.SessionToken, credOther.SessionToken, + "different session IDs must produce different session tokens") +}