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.
		
		
		
		
		
			
		
			
				
					
					
						
							520 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							520 lines
						
					
					
						
							15 KiB
						
					
					
				
								package s3api
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"context"
							 | 
						|
									"net/http"
							 | 
						|
									"net/http/httptest"
							 | 
						|
									"testing"
							 | 
						|
									"time"
							 | 
						|
								
							 | 
						|
									"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"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								// 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)
							 | 
						|
								
							 | 
						|
									// 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:seaweed: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:seaweed: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)
							 | 
						|
								
							 | 
						|
											// Assume role to get JWT
							 | 
						|
											response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{
							 | 
						|
												RoleArn:          tt.roleArn,
							 | 
						|
												WebIdentityToken: "valid-oidc-token",
							 | 
						|
												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)
							 | 
						|
									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)
							 | 
						|
									ctx := context.Background()
							 | 
						|
								
							 | 
						|
									// Set up IP-restricted role
							 | 
						|
									setupTestIPRestrictedRole(ctx, iamManager)
							 | 
						|
								
							 | 
						|
									// Assume role
							 | 
						|
									response, err := iamManager.AssumeRoleWithWebIdentity(ctx, &sts.AssumeRoleWithWebIdentityRequest{
							 | 
						|
										RoleArn:          "arn:seaweed:iam::role/S3IPRestrictedRole",
							 | 
						|
										WebIdentityToken: "valid-oidc-token",
							 | 
						|
										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:    time.Hour,
							 | 
						|
											MaxSessionLength: time.Hour * 12,
							 | 
						|
											Issuer:           "test-sts",
							 | 
						|
											SigningKey:       []byte("test-signing-key-32-characters-long"),
							 | 
						|
										},
							 | 
						|
										Policy: &policy.PolicyEngineConfig{
							 | 
						|
											DefaultEffect: "Deny",
							 | 
						|
											StoreType:     "memory",
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									err := manager.Initialize(config)
							 | 
						|
									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")
							 | 
						|
									ldapConfig := &ldap.LDAPConfig{
							 | 
						|
										Server: "ldap://test-server:389",
							 | 
						|
										BaseDN: "DC=test,DC=com",
							 | 
						|
									}
							 | 
						|
									err = ldapProvider.Initialize(ldapConfig)
							 | 
						|
									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:seaweed:s3:::*",
							 | 
						|
													"arn:seaweed:s3:::*/*",
							 | 
						|
												},
							 | 
						|
											},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									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": "test-oidc",
							 | 
						|
													},
							 | 
						|
													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": "test-oidc",
							 | 
						|
													},
							 | 
						|
													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:seaweed:s3:::*",
							 | 
						|
													"arn:seaweed:s3:::*/*",
							 | 
						|
												},
							 | 
						|
											},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									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": "test-oidc",
							 | 
						|
													},
							 | 
						|
													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": "test-oidc",
							 | 
						|
													},
							 | 
						|
													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:seaweed:s3:::*",
							 | 
						|
													"arn:seaweed:s3:::*/*",
							 | 
						|
												},
							 | 
						|
												Condition: map[string]map[string]interface{}{
							 | 
						|
													"IpAddress": {
							 | 
						|
														"seaweed: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": "test-oidc",
							 | 
						|
													},
							 | 
						|
													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:seaweed: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
							 | 
						|
								}
							 |