mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-05-23 18:21:28 +00:00
test: Add comprehensive STS session claims validation tests
- TestSTSSessionClaimsToSessionInfo: Validates basic claims conversion - TestSTSSessionClaimsToSessionInfoCredentialGeneration: Verifies credential generation - TestSTSSessionClaimsToSessionInfoPreservesAllFields: Ensures all fields are preserved - TestSTSSessionClaimsToSessionInfoEmptyFields: Tests handling of empty/nil fields - TestSTSSessionClaimsToSessionInfoCredentialExpiration: Validates expiration handling All tests pass with proper timing tolerance for credential generation.
This commit is contained in:
211
weed/iam/sts/session_claims_test.go
Normal file
211
weed/iam/sts/session_claims_test.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package sts
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestSTSSessionClaimsToSessionInfo tests the ToSessionInfo conversion
|
||||
func TestSTSSessionClaimsToSessionInfo(t *testing.T) {
|
||||
sessionId := "test-session-123"
|
||||
issuer := "test-issuer"
|
||||
expiresAt := time.Now().Add(time.Hour)
|
||||
|
||||
claims := NewSTSSessionClaims(sessionId, issuer, expiresAt).
|
||||
WithSessionName("test-session-name").
|
||||
WithRoleInfo(
|
||||
"arn:aws:iam::123456789012:role/test-role",
|
||||
"arn:aws:iam::123456789012:assumed-role/test-role/session",
|
||||
"arn:aws:iam::123456789012:assumed-role/test-role/session",
|
||||
).
|
||||
WithIdentityProvider("oidc", "user-123", "https://issuer.example.com").
|
||||
WithMaxDuration(time.Hour)
|
||||
|
||||
sessionInfo := claims.ToSessionInfo()
|
||||
|
||||
// Verify basic claims are converted
|
||||
assert.Equal(t, sessionId, sessionInfo.SessionId)
|
||||
assert.Equal(t, "test-session-name", sessionInfo.SessionName)
|
||||
assert.Equal(t, "arn:aws:iam::123456789012:role/test-role", sessionInfo.RoleArn)
|
||||
assert.Equal(t, "arn:aws:iam::123456789012:assumed-role/test-role/session", sessionInfo.AssumedRoleUser)
|
||||
assert.Equal(t, "oidc", sessionInfo.IdentityProvider)
|
||||
assert.Equal(t, "user-123", sessionInfo.ExternalUserId)
|
||||
|
||||
// Verify credentials are generated
|
||||
assert.NotNil(t, sessionInfo.Credentials, "credentials should be populated")
|
||||
assert.NotEmpty(t, sessionInfo.Credentials.AccessKeyId, "access key should be generated")
|
||||
assert.NotEmpty(t, sessionInfo.Credentials.SecretAccessKey, "secret key should be generated")
|
||||
// Credential expiration may have sub-second differences, so just check they're close
|
||||
assert.True(t, sessionInfo.Credentials.Expiration.Sub(expiresAt) < time.Second, "credential expiration should match session expiration")
|
||||
|
||||
// Verify expiration is preserved (within 1 second tolerance for timing differences)
|
||||
assert.WithinDuration(t, expiresAt, sessionInfo.ExpiresAt, 1*time.Second)
|
||||
}
|
||||
|
||||
// TestSTSSessionClaimsToSessionInfoCredentialGeneration tests that credentials are properly generated
|
||||
func TestSTSSessionClaimsToSessionInfoCredentialGeneration(t *testing.T) {
|
||||
sessionId := "deterministic-session-id"
|
||||
issuer := "test-issuer"
|
||||
expiresAt := time.Now().Add(time.Hour)
|
||||
|
||||
claims1 := NewSTSSessionClaims(sessionId, issuer, expiresAt)
|
||||
sessionInfo1 := claims1.ToSessionInfo()
|
||||
|
||||
// Create another claims object with the same session ID
|
||||
claims2 := NewSTSSessionClaims(sessionId, issuer, expiresAt)
|
||||
sessionInfo2 := claims2.ToSessionInfo()
|
||||
|
||||
// Verify that both have valid credentials (may not be the same due to randomness, but same structure)
|
||||
assert.NotNil(t, sessionInfo1.Credentials, "credentials should be populated")
|
||||
assert.NotNil(t, sessionInfo2.Credentials, "credentials should be populated")
|
||||
|
||||
// Both should have the same access key and secret key patterns
|
||||
assert.NotEmpty(t, sessionInfo1.Credentials.AccessKeyId)
|
||||
assert.NotEmpty(t, sessionInfo1.Credentials.SecretAccessKey)
|
||||
assert.NotEmpty(t, sessionInfo2.Credentials.AccessKeyId)
|
||||
assert.NotEmpty(t, sessionInfo2.Credentials.SecretAccessKey)
|
||||
}
|
||||
|
||||
// TestSTSSessionClaimsToSessionInfoPreservesAllFields tests that all fields are preserved
|
||||
func TestSTSSessionClaimsToSessionInfoPreservesAllFields(t *testing.T) {
|
||||
sessionId := "test-session-id"
|
||||
issuer := "test-issuer"
|
||||
expiresAt := time.Now().Add(2 * time.Hour)
|
||||
|
||||
policies := []string{"policy1", "policy2"}
|
||||
requestContext := map[string]interface{}{
|
||||
"sourceIp": "192.168.1.1",
|
||||
"userAgent": "test-agent",
|
||||
}
|
||||
|
||||
claims := NewSTSSessionClaims(sessionId, issuer, expiresAt).
|
||||
WithSessionName("session-name").
|
||||
WithRoleInfo("role-arn", "assumed-role", "principal").
|
||||
WithIdentityProvider("provider", "external-id", "issuer").
|
||||
WithPolicies(policies).
|
||||
WithRequestContext(requestContext).
|
||||
WithMaxDuration(2 * time.Hour)
|
||||
|
||||
sessionInfo := claims.ToSessionInfo()
|
||||
|
||||
// Verify all fields are preserved
|
||||
assert.Equal(t, sessionId, sessionInfo.SessionId)
|
||||
assert.Equal(t, "session-name", sessionInfo.SessionName)
|
||||
assert.Equal(t, "role-arn", sessionInfo.RoleArn)
|
||||
assert.Equal(t, "assumed-role", sessionInfo.AssumedRoleUser)
|
||||
assert.Equal(t, "principal", sessionInfo.Principal)
|
||||
assert.Equal(t, "provider", sessionInfo.IdentityProvider)
|
||||
assert.Equal(t, "external-id", sessionInfo.ExternalUserId)
|
||||
assert.Equal(t, "issuer", sessionInfo.ProviderIssuer)
|
||||
assert.Equal(t, policies, sessionInfo.Policies)
|
||||
assert.Equal(t, requestContext, sessionInfo.RequestContext)
|
||||
assert.WithinDuration(t, expiresAt, sessionInfo.ExpiresAt, 1*time.Second)
|
||||
}
|
||||
|
||||
// TestSTSSessionClaimsToSessionInfoEmptyFields tests handling of empty/nil fields
|
||||
func TestSTSSessionClaimsToSessionInfoEmptyFields(t *testing.T) {
|
||||
sessionId := "minimal-session"
|
||||
issuer := "issuer"
|
||||
expiresAt := time.Now().Add(time.Hour)
|
||||
|
||||
// Create claims with minimal fields
|
||||
claims := NewSTSSessionClaims(sessionId, issuer, expiresAt)
|
||||
|
||||
sessionInfo := claims.ToSessionInfo()
|
||||
|
||||
// Verify basic fields are preserved
|
||||
assert.Equal(t, sessionId, sessionInfo.SessionId)
|
||||
assert.Empty(t, sessionInfo.SessionName)
|
||||
assert.Empty(t, sessionInfo.RoleArn)
|
||||
|
||||
// Verify credentials are still generated even with minimal fields
|
||||
assert.NotNil(t, sessionInfo.Credentials)
|
||||
assert.NotEmpty(t, sessionInfo.Credentials.AccessKeyId)
|
||||
assert.NotEmpty(t, sessionInfo.Credentials.SecretAccessKey)
|
||||
}
|
||||
|
||||
// TestSTSSessionClaimsToSessionInfoCredentialExpiration tests credential expiration
|
||||
func TestSTSSessionClaimsToSessionInfoCredentialExpiration(t *testing.T) {
|
||||
sessionId := "test-session"
|
||||
issuer := "issuer"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expiresAt time.Time
|
||||
expectNotExpired bool
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "future_expiration",
|
||||
expiresAt: time.Now().Add(time.Hour),
|
||||
expectNotExpired: true,
|
||||
description: "Credentials should not be expired if ExpiresAt is in the future",
|
||||
},
|
||||
{
|
||||
name: "past_expiration",
|
||||
expiresAt: time.Now().Add(-time.Hour),
|
||||
expectNotExpired: false,
|
||||
description: "Credentials should be expired if ExpiresAt is in the past",
|
||||
},
|
||||
{
|
||||
name: "near_future_expiration",
|
||||
expiresAt: time.Now().Add(time.Minute),
|
||||
expectNotExpired: true,
|
||||
description: "Credentials should not be expired even if close to expiration",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
claims := NewSTSSessionClaims(sessionId, issuer, tc.expiresAt)
|
||||
sessionInfo := claims.ToSessionInfo()
|
||||
|
||||
assert.NotNil(t, sessionInfo.Credentials)
|
||||
// Check expiration within 1 second due to timing precision
|
||||
assert.True(t, sessionInfo.Credentials.Expiration.Sub(tc.expiresAt) < time.Second)
|
||||
|
||||
if tc.expectNotExpired {
|
||||
assert.False(t, time.Now().After(tc.expiresAt), tc.description)
|
||||
} else {
|
||||
assert.True(t, time.Now().After(tc.expiresAt), tc.description)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSessionInfoIntegration tests the full integration of session info flow
|
||||
func TestSessionInfoIntegration(t *testing.T) {
|
||||
// Create a session claim
|
||||
sessionId, err := GenerateSessionId()
|
||||
require.NoError(t, err)
|
||||
|
||||
expiresAt := time.Now().Add(time.Hour)
|
||||
claims := NewSTSSessionClaims(sessionId, "test-issuer", expiresAt).
|
||||
WithSessionName("integration-test").
|
||||
WithRoleInfo(
|
||||
"arn:aws:iam::123456789012:role/integration",
|
||||
"arn:aws:iam::123456789012:assumed-role/integration/test",
|
||||
"arn:aws:iam::123456789012:assumed-role/integration/test",
|
||||
).
|
||||
WithIdentityProvider("test-provider", "user-id", "https://test.example.com")
|
||||
|
||||
// Convert to SessionInfo
|
||||
sessionInfo := claims.ToSessionInfo()
|
||||
|
||||
// Verify the session info has valid credentials
|
||||
assert.NotNil(t, sessionInfo.Credentials)
|
||||
assert.NotEmpty(t, sessionInfo.Credentials.AccessKeyId)
|
||||
assert.NotEmpty(t, sessionInfo.Credentials.SecretAccessKey)
|
||||
|
||||
// Verify basic session properties
|
||||
assert.Equal(t, sessionId, sessionInfo.SessionId)
|
||||
assert.Equal(t, "integration-test", sessionInfo.SessionName)
|
||||
assert.False(t, sessionInfo.ExpiresAt.IsZero())
|
||||
|
||||
// Verify that the session is valid
|
||||
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")
|
||||
}
|
||||
Reference in New Issue
Block a user