You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
503 lines
20 KiB
503 lines
20 KiB
package sts
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"github.com/seaweedfs/seaweedfs/weed/iam/oidc"
|
|
"github.com/seaweedfs/seaweedfs/weed/iam/providers"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// Test-only constants for mock providers
|
|
const (
|
|
ProviderTypeMock = "mock"
|
|
)
|
|
|
|
// createMockOIDCProvider creates a mock OIDC provider for testing
|
|
// This is only available in test builds
|
|
func createMockOIDCProvider(name string, config map[string]interface{}) (providers.IdentityProvider, error) {
|
|
// Convert config to OIDC format
|
|
factory := NewProviderFactory()
|
|
oidcConfig, err := factory.convertToOIDCConfig(config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set default values for mock provider if not provided
|
|
if oidcConfig.Issuer == "" {
|
|
oidcConfig.Issuer = "http://localhost:9999"
|
|
}
|
|
|
|
provider := oidc.NewMockOIDCProvider(name)
|
|
if err := provider.Initialize(oidcConfig); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set up default test data for the mock provider
|
|
provider.SetupDefaultTestData()
|
|
|
|
return provider, nil
|
|
}
|
|
|
|
// createMockJWT creates a test JWT token with the specified issuer for mock provider testing
|
|
func createMockJWT(t *testing.T, issuer, subject string) string {
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
"iss": issuer,
|
|
"sub": subject,
|
|
"aud": "test-client",
|
|
"exp": time.Now().Add(time.Hour).Unix(),
|
|
"iat": time.Now().Unix(),
|
|
})
|
|
|
|
tokenString, err := token.SignedString([]byte("test-signing-key"))
|
|
require.NoError(t, err)
|
|
return tokenString
|
|
}
|
|
|
|
// TestCrossInstanceTokenUsage verifies that tokens generated by one STS instance
|
|
// can be used and validated by other STS instances in a distributed environment
|
|
func TestCrossInstanceTokenUsage(t *testing.T) {
|
|
ctx := context.Background()
|
|
// Dummy filer address for testing
|
|
|
|
// Common configuration that would be shared across all instances in production
|
|
sharedConfig := &STSConfig{
|
|
TokenDuration: FlexibleDuration{time.Hour},
|
|
MaxSessionLength: FlexibleDuration{12 * time.Hour},
|
|
Issuer: "distributed-sts-cluster", // SAME across all instances
|
|
SigningKey: []byte(TestSigningKey32Chars), // SAME across all instances
|
|
Providers: []*ProviderConfig{
|
|
{
|
|
Name: "company-oidc",
|
|
Type: ProviderTypeOIDC,
|
|
Enabled: true,
|
|
Config: map[string]interface{}{
|
|
ConfigFieldIssuer: "https://sso.company.com/realms/production",
|
|
ConfigFieldClientID: "seaweedfs-cluster",
|
|
ConfigFieldJWKSUri: "https://sso.company.com/realms/production/protocol/openid-connect/certs",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Create multiple STS instances simulating different S3 gateway instances
|
|
instanceA := NewSTSService() // e.g., s3-gateway-1
|
|
instanceB := NewSTSService() // e.g., s3-gateway-2
|
|
instanceC := NewSTSService() // e.g., s3-gateway-3
|
|
|
|
// Initialize all instances with IDENTICAL configuration
|
|
err := instanceA.Initialize(sharedConfig)
|
|
require.NoError(t, err, "Instance A should initialize")
|
|
|
|
err = instanceB.Initialize(sharedConfig)
|
|
require.NoError(t, err, "Instance B should initialize")
|
|
|
|
err = instanceC.Initialize(sharedConfig)
|
|
require.NoError(t, err, "Instance C should initialize")
|
|
|
|
// Set up mock trust policy validator for all instances (required for STS testing)
|
|
mockValidator := &MockTrustPolicyValidator{}
|
|
instanceA.SetTrustPolicyValidator(mockValidator)
|
|
instanceB.SetTrustPolicyValidator(mockValidator)
|
|
instanceC.SetTrustPolicyValidator(mockValidator)
|
|
|
|
// Manually register mock provider for testing (not available in production)
|
|
mockProviderConfig := map[string]interface{}{
|
|
ConfigFieldIssuer: "http://test-mock:9999",
|
|
ConfigFieldClientID: TestClientID,
|
|
}
|
|
mockProviderA, err := createMockOIDCProvider("test-mock", mockProviderConfig)
|
|
require.NoError(t, err)
|
|
mockProviderB, err := createMockOIDCProvider("test-mock", mockProviderConfig)
|
|
require.NoError(t, err)
|
|
mockProviderC, err := createMockOIDCProvider("test-mock", mockProviderConfig)
|
|
require.NoError(t, err)
|
|
|
|
instanceA.RegisterProvider(mockProviderA)
|
|
instanceB.RegisterProvider(mockProviderB)
|
|
instanceC.RegisterProvider(mockProviderC)
|
|
|
|
// Test 1: Token generated on Instance A can be validated on Instance B & C
|
|
t.Run("cross_instance_token_validation", func(t *testing.T) {
|
|
// Generate session token on Instance A
|
|
sessionId := TestSessionID
|
|
expiresAt := time.Now().Add(time.Hour)
|
|
|
|
tokenFromA, err := instanceA.tokenGenerator.GenerateSessionToken(sessionId, expiresAt)
|
|
require.NoError(t, err, "Instance A should generate token")
|
|
|
|
// Validate token on Instance B
|
|
claimsFromB, err := instanceB.tokenGenerator.ValidateSessionToken(tokenFromA)
|
|
require.NoError(t, err, "Instance B should validate token from Instance A")
|
|
assert.Equal(t, sessionId, claimsFromB.SessionId, "Session ID should match")
|
|
|
|
// Validate same token on Instance C
|
|
claimsFromC, err := instanceC.tokenGenerator.ValidateSessionToken(tokenFromA)
|
|
require.NoError(t, err, "Instance C should validate token from Instance A")
|
|
assert.Equal(t, sessionId, claimsFromC.SessionId, "Session ID should match")
|
|
|
|
// All instances should extract identical claims
|
|
assert.Equal(t, claimsFromB.SessionId, claimsFromC.SessionId)
|
|
assert.Equal(t, claimsFromB.ExpiresAt.Unix(), claimsFromC.ExpiresAt.Unix())
|
|
assert.Equal(t, claimsFromB.IssuedAt.Unix(), claimsFromC.IssuedAt.Unix())
|
|
})
|
|
|
|
// Test 2: Complete assume role flow across instances
|
|
t.Run("cross_instance_assume_role_flow", func(t *testing.T) {
|
|
// Step 1: User authenticates and assumes role on Instance A
|
|
// Create a valid JWT token for the mock provider
|
|
mockToken := createMockJWT(t, "http://test-mock:9999", "test-user")
|
|
|
|
assumeRequest := &AssumeRoleWithWebIdentityRequest{
|
|
RoleArn: "arn:seaweed:iam::role/CrossInstanceTestRole",
|
|
WebIdentityToken: mockToken, // JWT token for mock provider
|
|
RoleSessionName: "cross-instance-test-session",
|
|
DurationSeconds: int64ToPtr(3600),
|
|
}
|
|
|
|
// Instance A processes assume role request
|
|
responseFromA, err := instanceA.AssumeRoleWithWebIdentity(ctx, assumeRequest)
|
|
require.NoError(t, err, "Instance A should process assume role")
|
|
|
|
sessionToken := responseFromA.Credentials.SessionToken
|
|
accessKeyId := responseFromA.Credentials.AccessKeyId
|
|
secretAccessKey := responseFromA.Credentials.SecretAccessKey
|
|
|
|
// Verify response structure
|
|
assert.NotEmpty(t, sessionToken, "Should have session token")
|
|
assert.NotEmpty(t, accessKeyId, "Should have access key ID")
|
|
assert.NotEmpty(t, secretAccessKey, "Should have secret access key")
|
|
assert.NotNil(t, responseFromA.AssumedRoleUser, "Should have assumed role user")
|
|
|
|
// Step 2: Use session token on Instance B (different instance)
|
|
sessionInfoFromB, err := instanceB.ValidateSessionToken(ctx, sessionToken)
|
|
require.NoError(t, err, "Instance B should validate session token from Instance A")
|
|
|
|
assert.Equal(t, assumeRequest.RoleSessionName, sessionInfoFromB.SessionName)
|
|
assert.Equal(t, assumeRequest.RoleArn, sessionInfoFromB.RoleArn)
|
|
|
|
// Step 3: Use same session token on Instance C (yet another instance)
|
|
sessionInfoFromC, err := instanceC.ValidateSessionToken(ctx, sessionToken)
|
|
require.NoError(t, err, "Instance C should validate session token from Instance A")
|
|
|
|
// All instances should return identical session information
|
|
assert.Equal(t, sessionInfoFromB.SessionId, sessionInfoFromC.SessionId)
|
|
assert.Equal(t, sessionInfoFromB.SessionName, sessionInfoFromC.SessionName)
|
|
assert.Equal(t, sessionInfoFromB.RoleArn, sessionInfoFromC.RoleArn)
|
|
assert.Equal(t, sessionInfoFromB.Subject, sessionInfoFromC.Subject)
|
|
assert.Equal(t, sessionInfoFromB.Provider, sessionInfoFromC.Provider)
|
|
})
|
|
|
|
// Test 3: Session revocation across instances
|
|
t.Run("cross_instance_session_revocation", func(t *testing.T) {
|
|
// Create session on Instance A
|
|
mockToken := createMockJWT(t, "http://test-mock:9999", "test-user")
|
|
|
|
assumeRequest := &AssumeRoleWithWebIdentityRequest{
|
|
RoleArn: "arn:seaweed:iam::role/RevocationTestRole",
|
|
WebIdentityToken: mockToken,
|
|
RoleSessionName: "revocation-test-session",
|
|
}
|
|
|
|
response, err := instanceA.AssumeRoleWithWebIdentity(ctx, assumeRequest)
|
|
require.NoError(t, err)
|
|
sessionToken := response.Credentials.SessionToken
|
|
|
|
// Verify token works on Instance B
|
|
_, err = instanceB.ValidateSessionToken(ctx, sessionToken)
|
|
require.NoError(t, err, "Token should be valid on Instance B initially")
|
|
|
|
// Validate session on Instance C to verify cross-instance token compatibility
|
|
_, err = instanceC.ValidateSessionToken(ctx, sessionToken)
|
|
require.NoError(t, err, "Instance C should be able to validate session token")
|
|
|
|
// In a stateless JWT system, tokens remain valid on all instances since they're self-contained
|
|
// No revocation is possible without breaking the stateless architecture
|
|
_, err = instanceA.ValidateSessionToken(ctx, sessionToken)
|
|
assert.NoError(t, err, "Token should still be valid on Instance A (stateless system)")
|
|
|
|
// Verify token is still valid on Instance B
|
|
_, err = instanceB.ValidateSessionToken(ctx, sessionToken)
|
|
assert.NoError(t, err, "Token should still be valid on Instance B (stateless system)")
|
|
})
|
|
|
|
// Test 4: Provider consistency across instances
|
|
t.Run("provider_consistency_affects_token_generation", func(t *testing.T) {
|
|
// All instances should have same providers and be able to process same OIDC tokens
|
|
providerNamesA := instanceA.getProviderNames()
|
|
providerNamesB := instanceB.getProviderNames()
|
|
providerNamesC := instanceC.getProviderNames()
|
|
|
|
assert.ElementsMatch(t, providerNamesA, providerNamesB, "Instance A and B should have same providers")
|
|
assert.ElementsMatch(t, providerNamesB, providerNamesC, "Instance B and C should have same providers")
|
|
|
|
// All instances should be able to process same web identity token
|
|
testToken := createMockJWT(t, "http://test-mock:9999", "test-user")
|
|
|
|
// Try to assume role with same token on different instances
|
|
assumeRequest := &AssumeRoleWithWebIdentityRequest{
|
|
RoleArn: "arn:seaweed:iam::role/ProviderTestRole",
|
|
WebIdentityToken: testToken,
|
|
RoleSessionName: "provider-consistency-test",
|
|
}
|
|
|
|
// Should work on any instance
|
|
responseA, errA := instanceA.AssumeRoleWithWebIdentity(ctx, assumeRequest)
|
|
responseB, errB := instanceB.AssumeRoleWithWebIdentity(ctx, assumeRequest)
|
|
responseC, errC := instanceC.AssumeRoleWithWebIdentity(ctx, assumeRequest)
|
|
|
|
require.NoError(t, errA, "Instance A should process OIDC token")
|
|
require.NoError(t, errB, "Instance B should process OIDC token")
|
|
require.NoError(t, errC, "Instance C should process OIDC token")
|
|
|
|
// All should return valid responses (sessions will have different IDs but same structure)
|
|
assert.NotEmpty(t, responseA.Credentials.SessionToken)
|
|
assert.NotEmpty(t, responseB.Credentials.SessionToken)
|
|
assert.NotEmpty(t, responseC.Credentials.SessionToken)
|
|
})
|
|
}
|
|
|
|
// TestSTSDistributedConfigurationRequirements tests the configuration requirements
|
|
// for cross-instance token compatibility
|
|
func TestSTSDistributedConfigurationRequirements(t *testing.T) {
|
|
_ = "localhost:8888" // Dummy filer address for testing (not used in these tests)
|
|
|
|
t.Run("same_signing_key_required", func(t *testing.T) {
|
|
// Instance A with signing key 1
|
|
configA := &STSConfig{
|
|
TokenDuration: FlexibleDuration{time.Hour},
|
|
MaxSessionLength: FlexibleDuration{12 * time.Hour},
|
|
Issuer: "test-sts",
|
|
SigningKey: []byte("signing-key-1-32-characters-long"),
|
|
}
|
|
|
|
// Instance B with different signing key
|
|
configB := &STSConfig{
|
|
TokenDuration: FlexibleDuration{time.Hour},
|
|
MaxSessionLength: FlexibleDuration{12 * time.Hour},
|
|
Issuer: "test-sts",
|
|
SigningKey: []byte("signing-key-2-32-characters-long"), // DIFFERENT!
|
|
}
|
|
|
|
instanceA := NewSTSService()
|
|
instanceB := NewSTSService()
|
|
|
|
err := instanceA.Initialize(configA)
|
|
require.NoError(t, err)
|
|
|
|
err = instanceB.Initialize(configB)
|
|
require.NoError(t, err)
|
|
|
|
// Generate token on Instance A
|
|
sessionId := "test-session"
|
|
expiresAt := time.Now().Add(time.Hour)
|
|
tokenFromA, err := instanceA.tokenGenerator.GenerateSessionToken(sessionId, expiresAt)
|
|
require.NoError(t, err)
|
|
|
|
// Instance A should validate its own token
|
|
_, err = instanceA.tokenGenerator.ValidateSessionToken(tokenFromA)
|
|
assert.NoError(t, err, "Instance A should validate own token")
|
|
|
|
// Instance B should REJECT token due to different signing key
|
|
_, err = instanceB.tokenGenerator.ValidateSessionToken(tokenFromA)
|
|
assert.Error(t, err, "Instance B should reject token with different signing key")
|
|
assert.Contains(t, err.Error(), "invalid token", "Should be signature validation error")
|
|
})
|
|
|
|
t.Run("same_issuer_required", func(t *testing.T) {
|
|
sharedSigningKey := []byte("shared-signing-key-32-characters-lo")
|
|
|
|
// Instance A with issuer 1
|
|
configA := &STSConfig{
|
|
TokenDuration: FlexibleDuration{time.Hour},
|
|
MaxSessionLength: FlexibleDuration{12 * time.Hour},
|
|
Issuer: "sts-cluster-1",
|
|
SigningKey: sharedSigningKey,
|
|
}
|
|
|
|
// Instance B with different issuer
|
|
configB := &STSConfig{
|
|
TokenDuration: FlexibleDuration{time.Hour},
|
|
MaxSessionLength: FlexibleDuration{12 * time.Hour},
|
|
Issuer: "sts-cluster-2", // DIFFERENT!
|
|
SigningKey: sharedSigningKey,
|
|
}
|
|
|
|
instanceA := NewSTSService()
|
|
instanceB := NewSTSService()
|
|
|
|
err := instanceA.Initialize(configA)
|
|
require.NoError(t, err)
|
|
|
|
err = instanceB.Initialize(configB)
|
|
require.NoError(t, err)
|
|
|
|
// Generate token on Instance A
|
|
sessionId := "test-session"
|
|
expiresAt := time.Now().Add(time.Hour)
|
|
tokenFromA, err := instanceA.tokenGenerator.GenerateSessionToken(sessionId, expiresAt)
|
|
require.NoError(t, err)
|
|
|
|
// Instance B should REJECT token due to different issuer
|
|
_, err = instanceB.tokenGenerator.ValidateSessionToken(tokenFromA)
|
|
assert.Error(t, err, "Instance B should reject token with different issuer")
|
|
assert.Contains(t, err.Error(), "invalid issuer", "Should be issuer validation error")
|
|
})
|
|
|
|
t.Run("identical_configuration_required", func(t *testing.T) {
|
|
// Identical configuration
|
|
identicalConfig := &STSConfig{
|
|
TokenDuration: FlexibleDuration{time.Hour},
|
|
MaxSessionLength: FlexibleDuration{12 * time.Hour},
|
|
Issuer: "production-sts-cluster",
|
|
SigningKey: []byte("production-signing-key-32-chars-l"),
|
|
}
|
|
|
|
// Create multiple instances with identical config
|
|
instances := make([]*STSService, 5)
|
|
for i := 0; i < 5; i++ {
|
|
instances[i] = NewSTSService()
|
|
err := instances[i].Initialize(identicalConfig)
|
|
require.NoError(t, err, "Instance %d should initialize", i)
|
|
}
|
|
|
|
// Generate token on Instance 0
|
|
sessionId := "multi-instance-test"
|
|
expiresAt := time.Now().Add(time.Hour)
|
|
token, err := instances[0].tokenGenerator.GenerateSessionToken(sessionId, expiresAt)
|
|
require.NoError(t, err)
|
|
|
|
// All other instances should validate the token
|
|
for i := 1; i < 5; i++ {
|
|
claims, err := instances[i].tokenGenerator.ValidateSessionToken(token)
|
|
require.NoError(t, err, "Instance %d should validate token", i)
|
|
assert.Equal(t, sessionId, claims.SessionId, "Instance %d should extract correct session ID", i)
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestSTSRealWorldDistributedScenarios tests realistic distributed deployment scenarios
|
|
func TestSTSRealWorldDistributedScenarios(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("load_balanced_s3_gateway_scenario", func(t *testing.T) {
|
|
// Simulate real production scenario:
|
|
// 1. User authenticates with OIDC provider
|
|
// 2. User calls AssumeRoleWithWebIdentity on S3 Gateway 1
|
|
// 3. User makes S3 requests that hit S3 Gateway 2 & 3 via load balancer
|
|
// 4. All instances should handle the session token correctly
|
|
|
|
productionConfig := &STSConfig{
|
|
TokenDuration: FlexibleDuration{2 * time.Hour},
|
|
MaxSessionLength: FlexibleDuration{24 * time.Hour},
|
|
Issuer: "seaweedfs-production-sts",
|
|
SigningKey: []byte("prod-signing-key-32-characters-lon"),
|
|
|
|
Providers: []*ProviderConfig{
|
|
{
|
|
Name: "corporate-oidc",
|
|
Type: "oidc",
|
|
Enabled: true,
|
|
Config: map[string]interface{}{
|
|
"issuer": "https://sso.company.com/realms/production",
|
|
"clientId": "seaweedfs-prod-cluster",
|
|
"clientSecret": "supersecret-prod-key",
|
|
"scopes": []string{"openid", "profile", "email", "groups"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
// Create 3 S3 Gateway instances behind load balancer
|
|
gateway1 := NewSTSService()
|
|
gateway2 := NewSTSService()
|
|
gateway3 := NewSTSService()
|
|
|
|
err := gateway1.Initialize(productionConfig)
|
|
require.NoError(t, err)
|
|
|
|
err = gateway2.Initialize(productionConfig)
|
|
require.NoError(t, err)
|
|
|
|
err = gateway3.Initialize(productionConfig)
|
|
require.NoError(t, err)
|
|
|
|
// Set up mock trust policy validator for all gateway instances
|
|
mockValidator := &MockTrustPolicyValidator{}
|
|
gateway1.SetTrustPolicyValidator(mockValidator)
|
|
gateway2.SetTrustPolicyValidator(mockValidator)
|
|
gateway3.SetTrustPolicyValidator(mockValidator)
|
|
|
|
// Manually register mock provider for testing (not available in production)
|
|
mockProviderConfig := map[string]interface{}{
|
|
ConfigFieldIssuer: "http://test-mock:9999",
|
|
ConfigFieldClientID: "test-client-id",
|
|
}
|
|
mockProvider1, err := createMockOIDCProvider("test-mock", mockProviderConfig)
|
|
require.NoError(t, err)
|
|
mockProvider2, err := createMockOIDCProvider("test-mock", mockProviderConfig)
|
|
require.NoError(t, err)
|
|
mockProvider3, err := createMockOIDCProvider("test-mock", mockProviderConfig)
|
|
require.NoError(t, err)
|
|
|
|
gateway1.RegisterProvider(mockProvider1)
|
|
gateway2.RegisterProvider(mockProvider2)
|
|
gateway3.RegisterProvider(mockProvider3)
|
|
|
|
// Step 1: User authenticates and hits Gateway 1 for AssumeRole
|
|
mockToken := createMockJWT(t, "http://test-mock:9999", "production-user")
|
|
|
|
assumeRequest := &AssumeRoleWithWebIdentityRequest{
|
|
RoleArn: "arn:seaweed:iam::role/ProductionS3User",
|
|
WebIdentityToken: mockToken, // JWT token from mock provider
|
|
RoleSessionName: "user-production-session",
|
|
DurationSeconds: int64ToPtr(7200), // 2 hours
|
|
}
|
|
|
|
stsResponse, err := gateway1.AssumeRoleWithWebIdentity(ctx, assumeRequest)
|
|
require.NoError(t, err, "Gateway 1 should handle AssumeRole")
|
|
|
|
sessionToken := stsResponse.Credentials.SessionToken
|
|
accessKey := stsResponse.Credentials.AccessKeyId
|
|
secretKey := stsResponse.Credentials.SecretAccessKey
|
|
|
|
// Step 2: User makes S3 requests that hit different gateways via load balancer
|
|
// Simulate S3 request validation on Gateway 2
|
|
sessionInfo2, err := gateway2.ValidateSessionToken(ctx, sessionToken)
|
|
require.NoError(t, err, "Gateway 2 should validate session from Gateway 1")
|
|
assert.Equal(t, "user-production-session", sessionInfo2.SessionName)
|
|
assert.Equal(t, "arn:seaweed:iam::role/ProductionS3User", sessionInfo2.RoleArn)
|
|
|
|
// Simulate S3 request validation on Gateway 3
|
|
sessionInfo3, err := gateway3.ValidateSessionToken(ctx, sessionToken)
|
|
require.NoError(t, err, "Gateway 3 should validate session from Gateway 1")
|
|
assert.Equal(t, sessionInfo2.SessionId, sessionInfo3.SessionId, "Should be same session")
|
|
|
|
// Step 3: Verify credentials are consistent
|
|
assert.Equal(t, accessKey, stsResponse.Credentials.AccessKeyId, "Access key should be consistent")
|
|
assert.Equal(t, secretKey, stsResponse.Credentials.SecretAccessKey, "Secret key should be consistent")
|
|
|
|
// Step 4: Session expiration should be honored across all instances
|
|
assert.True(t, sessionInfo2.ExpiresAt.After(time.Now()), "Session should not be expired")
|
|
assert.True(t, sessionInfo3.ExpiresAt.After(time.Now()), "Session should not be expired")
|
|
|
|
// Step 5: Token should be identical when parsed
|
|
claims2, err := gateway2.tokenGenerator.ValidateSessionToken(sessionToken)
|
|
require.NoError(t, err)
|
|
|
|
claims3, err := gateway3.tokenGenerator.ValidateSessionToken(sessionToken)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, claims2.SessionId, claims3.SessionId, "Session IDs should match")
|
|
assert.Equal(t, claims2.ExpiresAt.Unix(), claims3.ExpiresAt.Unix(), "Expiration should match")
|
|
})
|
|
}
|
|
|
|
// Helper function to convert int64 to pointer
|
|
func int64ToPtr(i int64) *int64 {
|
|
return &i
|
|
}
|