Files
seaweedFS/weed/s3api/s3_jwt_auth_test.go
Chris Lu d75162370c Fix trust policy wildcard principal handling (#7970)
* Fix trust policy wildcard principal handling

This change fixes the trust policy validation to properly support
AWS-standard wildcard principals like {"Federated": "*"}.

Previously, the evaluatePrincipalValue() function would check for
context existence before evaluating wildcards, causing wildcard
principals to fail when the context key didn't exist. This forced
users to use the plain "*" workaround instead of the more specific
{"Federated": "*"} format.

Changes:
- Modified evaluatePrincipalValue() to check for "*" FIRST before
  validating against context
- Added support for wildcards in principal arrays
- Added comprehensive tests for wildcard principal handling
- All existing tests continue to pass (no regressions)

This matches AWS IAM behavior where "*" in a principal field means
"allow any value" without requiring context validation.

Fixes: https://github.com/seaweedfs/seaweedfs/issues/7917

* Refactor: Move Principal matching to PolicyEngine

This refactoring consolidates all policy evaluation logic into the
PolicyEngine, improving code organization and eliminating duplication.

Changes:
- Added matchesPrincipal() and evaluatePrincipalValue() to PolicyEngine
- Added EvaluateTrustPolicy() method for direct trust policy evaluation
- Updated statementMatches() to check Principal field when present
- Made resource matching optional (trust policies don't have Resources)
- Simplified evaluateTrustPolicy() in iam_manager.go to delegate to PolicyEngine
- Removed ~170 lines of duplicate code from iam_manager.go

Benefits:
- Single source of truth for all policy evaluation
- Better code reusability and maintainability
- Consistent evaluation rules for all policy types
- Easier to test and debug

All tests pass with no regressions.

* Make PolicyEngine AWS-compatible and add unit tests

Changes:
1. AWS-Compatible Context Keys:
   - Changed "seaweed:FederatedProvider" -> "aws:FederatedProvider"
   - Changed "seaweed:AWSPrincipal" -> "aws:PrincipalArn"
   - Changed "seaweed:ServicePrincipal" -> "aws:PrincipalServiceName"
   - This ensures 100% AWS compatibility for trust policies

2. Added Comprehensive Unit Tests:
   - TestPrincipalMatching: 8 test cases for Principal matching
   - TestEvaluatePrincipalValue: 7 test cases for value evaluation
   - TestTrustPolicyEvaluation: 6 test cases for trust policy evaluation
   - TestGetPrincipalContextKey: 4 test cases for context key mapping
   - Total: 25 new unit tests for PolicyEngine

All tests pass:
- Policy engine tests: 54 passed
- Integration tests: 9 passed
- Total: 63 tests passing

* Update context keys to standard AWS/OIDC formats

Replaced remaining seaweed: context keys with standard AWS and OIDC
keys to ensure 100% compatibility with AWS IAM policies.

Mappings:
- seaweed:TokenIssuer -> oidc:iss
- seaweed:Issuer -> oidc:iss
- seaweed:Subject -> oidc:sub
- seaweed:SourceIP -> aws:SourceIp

Also updated unit tests to reflect these changes.

All 63 tests pass successfully.

* Add advanced policy tests for variable substitution and conditions

Added comprehensive tests inspired by AWS IAM patterns:
- TestPolicyVariableSubstitution: Tests ${oidc:sub} variable in resources
- TestConditionWithNumericComparison: Tests sts:DurationSeconds condition
- TestMultipleConditionOperators: Tests combining StringEquals and StringLike

Results:
- TestMultipleConditionOperators:  All 3 subtests pass
- Other tests reveal need for sts:DurationSeconds context population

These tests validate the PolicyEngine's ability to handle complex
AWS-compatible policy scenarios.

* Fix federated provider context and add DurationSeconds support

Changes:
- Use iss claim as aws:FederatedProvider (AWS standard)
- Add sts:DurationSeconds to trust policy evaluation context
- TestPolicyVariableSubstitution now passes 

Remaining work:
- TestConditionWithNumericComparison partially works (1/3 pass)
- Need to investigate NumericLessThanEquals evaluation

* Update trust policies to use issuer URL for AWS compatibility

Changed trust policy from using provider name ("test-oidc") to
using the issuer URL ("https://test-issuer.com") to match AWS
standard behavior where aws:FederatedProvider contains the OIDC
issuer URL.

Test Results:
- 10/12 test suites passing
- TestFullOIDCWorkflow:  All subtests pass
- TestPolicyEnforcement:  All subtests pass
- TestSessionExpiration:  Pass
- TestPolicyVariableSubstitution:  Pass
- TestMultipleConditionOperators:  All subtests pass

Remaining work:
- TestConditionWithNumericComparison needs investigation
- One subtest in TestTrustPolicyValidation needs fix

* Fix S3 API tests for AWS compatibility

Updated all S3 API tests to use AWS-compatible context keys and
trust policy principals:

Changes:
- seaweed:SourceIP → aws:SourceIp (IP-based conditions)
- Federated: "test-oidc" → "https://test-issuer.com" (trust policies)

Test Results:
- TestS3EndToEndWithJWT:  All 13 subtests pass
- TestIPBasedPolicyEnforcement:  All 3 subtests pass

This ensures policies are 100% AWS-compatible and portable.

* Fix ValidateTrustPolicy for AWS compatibility

Updated ValidateTrustPolicy method to check for:
- OIDC: issuer URL ("https://test-issuer.com")
- LDAP: provider name ("test-ldap")
- Wildcard: "*"

Test Results:
- TestTrustPolicyValidation:  All 3 subtests pass

This ensures trust policy validation uses the same AWS-compatible
principals as the PolicyEngine.

* Fix multipart and presigned URL tests for AWS compatibility

Updated trust policies in:
- s3_multipart_iam_test.go
- s3_presigned_url_iam_test.go

Changed "Federated": "test-oidc" → "https://test-issuer.com"

Test Results:
- TestMultipartIAMValidation:  All 7 subtests pass
- TestPresignedURLIAMValidation:  All 4 subtests pass
- TestPresignedURLGeneration:  All 4 subtests pass
- TestPresignedURLExpiration:  All 4 subtests pass
- TestPresignedURLSecurityPolicy:  All 4 subtests pass

All S3 API tests now use AWS-compatible trust policies.

* Fix numeric condition evaluation and trust policy validation interface

Major updates to ensure robust AWS-compatible policy evaluation:
1.  **Policy Engine**: Added support for `int` and `int64` types in `evaluateNumericCondition`, fixing issues where raw numbers in policy documents caused evaluation failures.
2.  **Trust Policy Validation**: Updated `TrustPolicyValidator` interface and `STSService` to propagate `DurationSeconds` correctly during the double-validation flow (Validation -> STS -> Validation callback).
3.  **IAM Manager**: Updated implementation to match the new interface and correctly pass `sts:DurationSeconds` context key.

Test Results:
- TestConditionWithNumericComparison:  All 3 subtests pass
- All IAM and S3 integration tests pass (100%)

This resolves the final edge case with DurationSeconds numeric conditions.

* Fix MockTrustPolicyValidator interface and unreachable code warnings

Updates:
1. Updated MockTrustPolicyValidator.ValidateTrustPolicyForWebIdentity to match new interface signature with durationSeconds parameter
2. Removed unreachable code after infinite loops in filer_backup.go and filer_meta_backup.go to satisfy linter

Test Results:
- All STS tests pass 
- Build warnings resolved 

* Refactor matchesPrincipal to consolidate array handling logic

Consolidated duplicated logic for []interface{} and []string types by converting them to a unified []interface{} upfront.

* Fix malformed AWS docs URL in iam_manager.go comment

* dup

* Enhance IAM integration tests with negative cases and interface array support

Added test cases to TestTrustPolicyWildcardPrincipal to:
1. Verify rejection of roles when principal context does not match (negative test)
2. Verify support for principal arrays as []interface{} (simulating JSON unmarshaled roles)

* Fix syntax errors in filer_backup and filer_meta_backup

Restored missing closing braces for for-loops and re-added return statements.
The previous attempt to remove unreachable code accidentally broke the function structure.
Build now passes successfully.
2026-01-05 15:55:24 -08:00

558 lines
16 KiB
Go

package s3api
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/seaweedfs/seaweedfs/weed/iam/integration"
"github.com/seaweedfs/seaweedfs/weed/iam/ldap"
"github.com/seaweedfs/seaweedfs/weed/iam/oidc"
"github.com/seaweedfs/seaweedfs/weed/iam/policy"
"github.com/seaweedfs/seaweedfs/weed/iam/sts"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// createTestJWTAuth creates a test JWT token with the specified issuer, subject and signing key
func createTestJWTAuth(t *testing.T, issuer, subject, signingKey string) string {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"iss": issuer,
"sub": subject,
"aud": "test-client-id",
"exp": time.Now().Add(time.Hour).Unix(),
"iat": time.Now().Unix(),
// Add claims that trust policy validation expects
"idp": "test-oidc", // Identity provider claim for trust policy matching
})
tokenString, err := token.SignedString([]byte(signingKey))
require.NoError(t, err)
return tokenString
}
// TestJWTAuthenticationFlow tests the JWT authentication flow without full S3 server
func TestJWTAuthenticationFlow(t *testing.T) {
// Set up IAM system
iamManager := setupTestIAMManager(t)
// Create IAM integration
s3iam := NewS3IAMIntegration(iamManager, "localhost:8888")
// Create IAM server with integration
iamServer := setupIAMWithIntegration(t, iamManager, s3iam)
// Test scenarios
tests := []struct {
name string
roleArn string
setupRole func(ctx context.Context, mgr *integration.IAMManager)
testOperations []JWTTestOperation
}{
{
name: "Read-Only JWT Authentication",
roleArn: "arn:aws:iam::role/S3ReadOnlyRole",
setupRole: setupTestReadOnlyRole,
testOperations: []JWTTestOperation{
{Action: s3_constants.ACTION_READ, Bucket: "test-bucket", Object: "test-file.txt", ExpectedAllow: true},
{Action: s3_constants.ACTION_WRITE, Bucket: "test-bucket", Object: "new-file.txt", ExpectedAllow: false},
{Action: s3_constants.ACTION_LIST, Bucket: "test-bucket", Object: "", ExpectedAllow: true},
},
},
{
name: "Admin JWT Authentication",
roleArn: "arn:aws:iam::role/S3AdminRole",
setupRole: setupTestAdminRole,
testOperations: []JWTTestOperation{
{Action: s3_constants.ACTION_READ, Bucket: "admin-bucket", Object: "admin-file.txt", ExpectedAllow: true},
{Action: s3_constants.ACTION_WRITE, Bucket: "admin-bucket", Object: "new-admin-file.txt", ExpectedAllow: true},
{Action: s3_constants.ACTION_DELETE_BUCKET, Bucket: "admin-bucket", Object: "", ExpectedAllow: true},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
// Set up role
tt.setupRole(ctx, iamManager)
// Create a valid JWT token for testing
validJWTToken := createTestJWTAuth(t, "https://test-issuer.com", "test-user-123", "test-signing-key")
// Assume role to get JWT
response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{
RoleArn: tt.roleArn,
WebIdentityToken: validJWTToken,
RoleSessionName: "jwt-auth-test",
})
require.NoError(t, err)
jwtToken := response.Credentials.SessionToken
// Test each operation
for _, op := range tt.testOperations {
t.Run(string(op.Action), func(t *testing.T) {
// Test JWT authentication
identity, errCode := testJWTAuthentication(t, iamServer, jwtToken)
require.Equal(t, s3err.ErrNone, errCode, "JWT authentication should succeed")
require.NotNil(t, identity)
// Test authorization with appropriate role based on test case
var testRoleName string
if tt.name == "Read-Only JWT Authentication" {
testRoleName = "TestReadRole"
} else {
testRoleName = "TestAdminRole"
}
allowed := testJWTAuthorizationWithRole(t, iamServer, identity, op.Action, op.Bucket, op.Object, jwtToken, testRoleName)
assert.Equal(t, op.ExpectedAllow, allowed, "Operation %s should have expected result", op.Action)
})
}
})
}
}
// TestJWTTokenValidation tests JWT token validation edge cases
func TestJWTTokenValidation(t *testing.T) {
iamManager := setupTestIAMManager(t)
s3iam := NewS3IAMIntegration(iamManager, "localhost:8888")
iamServer := setupIAMWithIntegration(t, iamManager, s3iam)
tests := []struct {
name string
token string
expectedErr s3err.ErrorCode
}{
{
name: "Empty token",
token: "",
expectedErr: s3err.ErrAccessDenied,
},
{
name: "Invalid token format",
token: "invalid-token",
expectedErr: s3err.ErrAccessDenied,
},
{
name: "Expired token",
token: "expired-session-token",
expectedErr: s3err.ErrAccessDenied,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
identity, errCode := testJWTAuthentication(t, iamServer, tt.token)
assert.Equal(t, tt.expectedErr, errCode)
assert.Nil(t, identity)
})
}
}
// TestRequestContextExtraction tests context extraction for policy conditions
func TestRequestContextExtraction(t *testing.T) {
tests := []struct {
name string
setupRequest func() *http.Request
expectedIP string
expectedUA string
}{
{
name: "Standard request with IP",
setupRequest: func() *http.Request {
req := httptest.NewRequest("GET", "/test-bucket/test-file.txt", http.NoBody)
req.Header.Set("X-Forwarded-For", "192.168.1.100")
req.Header.Set("User-Agent", "aws-sdk-go/1.0")
return req
},
expectedIP: "192.168.1.100",
expectedUA: "aws-sdk-go/1.0",
},
{
name: "Request with X-Real-IP",
setupRequest: func() *http.Request {
req := httptest.NewRequest("GET", "/test-bucket/test-file.txt", http.NoBody)
req.Header.Set("X-Real-IP", "10.0.0.1")
req.Header.Set("User-Agent", "boto3/1.0")
return req
},
expectedIP: "10.0.0.1",
expectedUA: "boto3/1.0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := tt.setupRequest()
// Extract request context
context := extractRequestContext(req)
if tt.expectedIP != "" {
assert.Equal(t, tt.expectedIP, context["sourceIP"])
}
if tt.expectedUA != "" {
assert.Equal(t, tt.expectedUA, context["userAgent"])
}
})
}
}
// TestIPBasedPolicyEnforcement tests IP-based conditional policies
func TestIPBasedPolicyEnforcement(t *testing.T) {
iamManager := setupTestIAMManager(t)
s3iam := NewS3IAMIntegration(iamManager, "localhost:8888")
ctx := context.Background()
// Set up IP-restricted role
setupTestIPRestrictedRole(ctx, iamManager)
// Create a valid JWT token for testing
validJWTToken := createTestJWTAuth(t, "https://test-issuer.com", "test-user-123", "test-signing-key")
// Assume role
response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{
RoleArn: "arn:aws:iam::role/S3IPRestrictedRole",
WebIdentityToken: validJWTToken,
RoleSessionName: "ip-test-session",
})
require.NoError(t, err)
tests := []struct {
name string
sourceIP string
shouldAllow bool
}{
{
name: "Allow from office IP",
sourceIP: "192.168.1.100",
shouldAllow: true,
},
{
name: "Block from external IP",
sourceIP: "8.8.8.8",
shouldAllow: false,
},
{
name: "Allow from internal range",
sourceIP: "10.0.0.1",
shouldAllow: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create request with specific IP
req := httptest.NewRequest("GET", "/restricted-bucket/file.txt", http.NoBody)
req.Header.Set("Authorization", "Bearer "+response.Credentials.SessionToken)
req.Header.Set("X-Forwarded-For", tt.sourceIP)
// Create IAM identity for testing
identity := &IAMIdentity{
Name: "test-user",
Principal: response.AssumedRoleUser.Arn,
SessionToken: response.Credentials.SessionToken,
}
// Test authorization with IP condition
errCode := s3iam.AuthorizeAction(ctx, identity, s3_constants.ACTION_READ, "restricted-bucket", "file.txt", req)
if tt.shouldAllow {
assert.Equal(t, s3err.ErrNone, errCode, "Should allow access from IP %s", tt.sourceIP)
} else {
assert.Equal(t, s3err.ErrAccessDenied, errCode, "Should deny access from IP %s", tt.sourceIP)
}
})
}
}
// JWTTestOperation represents a test operation for JWT testing
type JWTTestOperation struct {
Action Action
Bucket string
Object string
ExpectedAllow bool
}
// Helper functions
func setupTestIAMManager(t *testing.T) *integration.IAMManager {
// Create IAM manager
manager := integration.NewIAMManager()
// Initialize with test configuration
config := &integration.IAMConfig{
STS: &sts.STSConfig{
TokenDuration: sts.FlexibleDuration{Duration: time.Hour},
MaxSessionLength: sts.FlexibleDuration{Duration: time.Hour * 12},
Issuer: "test-sts",
SigningKey: []byte("test-signing-key-32-characters-long"),
},
Policy: &policy.PolicyEngineConfig{
DefaultEffect: "Deny",
StoreType: "memory",
},
Roles: &integration.RoleStoreConfig{
StoreType: "memory",
},
}
err := manager.Initialize(config, func() string {
return "localhost:8888" // Mock filer address for testing
})
require.NoError(t, err)
// Set up test identity providers
setupTestIdentityProviders(t, manager)
return manager
}
func setupTestIdentityProviders(t *testing.T, manager *integration.IAMManager) {
// Set up OIDC provider
oidcProvider := oidc.NewMockOIDCProvider("test-oidc")
oidcConfig := &oidc.OIDCConfig{
Issuer: "https://test-issuer.com",
ClientID: "test-client-id",
}
err := oidcProvider.Initialize(oidcConfig)
require.NoError(t, err)
oidcProvider.SetupDefaultTestData()
// Set up LDAP provider
ldapProvider := ldap.NewMockLDAPProvider("test-ldap")
err = ldapProvider.Initialize(nil) // Mock doesn't need real config
require.NoError(t, err)
ldapProvider.SetupDefaultTestData()
// Register providers
err = manager.RegisterIdentityProvider(oidcProvider)
require.NoError(t, err)
err = manager.RegisterIdentityProvider(ldapProvider)
require.NoError(t, err)
}
func setupIAMWithIntegration(t *testing.T, iamManager *integration.IAMManager, s3iam *S3IAMIntegration) *IdentityAccessManagement {
// Create a minimal IdentityAccessManagement for testing
iam := &IdentityAccessManagement{
isAuthEnabled: true,
}
// Set IAM integration
iam.SetIAMIntegration(s3iam)
return iam
}
func setupTestReadOnlyRole(ctx context.Context, manager *integration.IAMManager) {
// Create read-only policy
readPolicy := &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Sid: "AllowS3Read",
Effect: "Allow",
Action: []string{"s3:GetObject", "s3:ListBucket"},
Resource: []string{
"arn:aws:s3:::*",
"arn:aws:s3:::*/*",
},
},
{
Sid: "AllowSTSSessionValidation",
Effect: "Allow",
Action: []string{"sts:ValidateSession"},
Resource: []string{"*"},
},
},
}
manager.CreatePolicy(ctx, "", "S3ReadOnlyPolicy", readPolicy)
// Create role
manager.CreateRole(ctx, "", "S3ReadOnlyRole", &integration.RoleDefinition{
RoleName: "S3ReadOnlyRole",
TrustPolicy: &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Effect: "Allow",
Principal: map[string]interface{}{
"Federated": "https://test-issuer.com",
},
Action: []string{"sts:AssumeRoleWithWebIdentity"},
},
},
},
AttachedPolicies: []string{"S3ReadOnlyPolicy"},
})
// Also create a TestReadRole for read-only authorization testing
manager.CreateRole(ctx, "", "TestReadRole", &integration.RoleDefinition{
RoleName: "TestReadRole",
TrustPolicy: &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Effect: "Allow",
Principal: map[string]interface{}{
"Federated": "https://test-issuer.com",
},
Action: []string{"sts:AssumeRoleWithWebIdentity"},
},
},
},
AttachedPolicies: []string{"S3ReadOnlyPolicy"},
})
}
func setupTestAdminRole(ctx context.Context, manager *integration.IAMManager) {
// Create admin policy
adminPolicy := &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Sid: "AllowAllS3",
Effect: "Allow",
Action: []string{"s3:*"},
Resource: []string{
"arn:aws:s3:::*",
"arn:aws:s3:::*/*",
},
},
{
Sid: "AllowSTSSessionValidation",
Effect: "Allow",
Action: []string{"sts:ValidateSession"},
Resource: []string{"*"},
},
},
}
manager.CreatePolicy(ctx, "", "S3AdminPolicy", adminPolicy)
// Create role
manager.CreateRole(ctx, "", "S3AdminRole", &integration.RoleDefinition{
RoleName: "S3AdminRole",
TrustPolicy: &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Effect: "Allow",
Principal: map[string]interface{}{
"Federated": "https://test-issuer.com",
},
Action: []string{"sts:AssumeRoleWithWebIdentity"},
},
},
},
AttachedPolicies: []string{"S3AdminPolicy"},
})
// Also create a TestAdminRole with admin policy for authorization testing
manager.CreateRole(ctx, "", "TestAdminRole", &integration.RoleDefinition{
RoleName: "TestAdminRole",
TrustPolicy: &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Effect: "Allow",
Principal: map[string]interface{}{
"Federated": "https://test-issuer.com",
},
Action: []string{"sts:AssumeRoleWithWebIdentity"},
},
},
},
AttachedPolicies: []string{"S3AdminPolicy"}, // Admin gets full access
})
}
func setupTestIPRestrictedRole(ctx context.Context, manager *integration.IAMManager) {
// Create IP-restricted policy
restrictedPolicy := &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Sid: "AllowFromOffice",
Effect: "Allow",
Action: []string{"s3:GetObject", "s3:ListBucket"},
Resource: []string{
"arn:aws:s3:::*",
"arn:aws:s3:::*/*",
},
Condition: map[string]map[string]interface{}{
"IpAddress": {
"aws:SourceIp": []string{"192.168.1.0/24", "10.0.0.0/8"},
},
},
},
},
}
manager.CreatePolicy(ctx, "", "S3IPRestrictedPolicy", restrictedPolicy)
// Create role
manager.CreateRole(ctx, "", "S3IPRestrictedRole", &integration.RoleDefinition{
RoleName: "S3IPRestrictedRole",
TrustPolicy: &policy.PolicyDocument{
Version: "2012-10-17",
Statement: []policy.Statement{
{
Effect: "Allow",
Principal: map[string]interface{}{
"Federated": "https://test-issuer.com",
},
Action: []string{"sts:AssumeRoleWithWebIdentity"},
},
},
},
AttachedPolicies: []string{"S3IPRestrictedPolicy"},
})
}
func testJWTAuthentication(t *testing.T, iam *IdentityAccessManagement, token string) (*Identity, s3err.ErrorCode) {
// Create test request with JWT
req := httptest.NewRequest("GET", "/test-bucket/test-object", http.NoBody)
req.Header.Set("Authorization", "Bearer "+token)
// Test authentication
if iam.iamIntegration == nil {
return nil, s3err.ErrNotImplemented
}
return iam.authenticateJWTWithIAM(req)
}
func testJWTAuthorization(t *testing.T, iam *IdentityAccessManagement, identity *Identity, action Action, bucket, object, token string) bool {
return testJWTAuthorizationWithRole(t, iam, identity, action, bucket, object, token, "TestRole")
}
func testJWTAuthorizationWithRole(t *testing.T, iam *IdentityAccessManagement, identity *Identity, action Action, bucket, object, token, roleName string) bool {
// Create test request
req := httptest.NewRequest("GET", "/"+bucket+"/"+object, http.NoBody)
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("X-SeaweedFS-Session-Token", token)
// Use a proper principal ARN format that matches what STS would generate
principalArn := "arn:aws:sts::assumed-role/" + roleName + "/test-session"
req.Header.Set("X-SeaweedFS-Principal", principalArn)
// Test authorization
if iam.iamIntegration == nil {
return false
}
errCode := iam.authorizeWithIAM(req, identity, action, bucket, object)
return errCode == s3err.ErrNone
}