Browse Source

unique bucket name

pull/7160/head
chrislu 1 month ago
parent
commit
a2fd8d9764
  1. 9
      test/s3/iam/iam_config.json
  2. 60
      test/s3/iam/s3_iam_framework.go
  3. 24
      test/s3/iam/s3_iam_integration_test.go

9
test/s3/iam/iam_config.json

@ -10,7 +10,8 @@
"name": "test-oidc", "name": "test-oidc",
"type": "mock", "type": "mock",
"config": { "config": {
"issuer": "test-oidc-issuer"
"issuer": "test-oidc-issuer",
"clientId": "test-oidc-client"
} }
}, },
{ {
@ -18,11 +19,11 @@
"type": "oidc", "type": "oidc",
"enabled": true, "enabled": true,
"config": { "config": {
"issuer": "http://localhost:8090/realms/seaweedfs-test",
"issuer": "http://localhost:8080/realms/seaweedfs-test",
"clientId": "seaweedfs-s3", "clientId": "seaweedfs-s3",
"clientSecret": "seaweedfs-s3-secret", "clientSecret": "seaweedfs-s3-secret",
"jwksUri": "http://localhost:8090/realms/seaweedfs-test/protocol/openid-connect/certs",
"userInfoUri": "http://localhost:8090/realms/seaweedfs-test/protocol/openid-connect/userinfo",
"jwksUri": "http://localhost:8080/realms/seaweedfs-test/protocol/openid-connect/certs",
"userInfoUri": "http://localhost:8080/realms/seaweedfs-test/protocol/openid-connect/userinfo",
"scopes": ["openid", "profile", "email"], "scopes": ["openid", "profile", "email"],
"claimsMapping": { "claimsMapping": {
"username": "preferred_username", "username": "preferred_username",

60
test/s3/iam/s3_iam_framework.go

@ -8,6 +8,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"math/rand"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
@ -17,6 +18,7 @@ import (
"time" "time"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3" "github.com/aws/aws-sdk-go/service/s3"
@ -612,6 +614,19 @@ func (f *S3IAMTestFramework) ExpireSessionForTesting(sessionToken string) error
return nil return nil
} }
// GenerateUniqueBucketName generates a unique bucket name for testing
func (f *S3IAMTestFramework) GenerateUniqueBucketName(prefix string) string {
// Use test name and timestamp to ensure uniqueness
testName := strings.ToLower(f.t.Name())
testName = strings.ReplaceAll(testName, "/", "-")
testName = strings.ReplaceAll(testName, "_", "-")
// Add random suffix to handle parallel tests
randomSuffix := rand.Intn(10000)
return fmt.Sprintf("%s-%s-%d", prefix, testName, randomSuffix)
}
// CreateBucket creates a bucket and tracks it for cleanup // CreateBucket creates a bucket and tracks it for cleanup
func (f *S3IAMTestFramework) CreateBucket(s3Client *s3.S3, bucketName string) error { func (f *S3IAMTestFramework) CreateBucket(s3Client *s3.S3, bucketName string) error {
_, err := s3Client.CreateBucket(&s3.CreateBucketInput{ _, err := s3Client.CreateBucket(&s3.CreateBucketInput{
@ -626,6 +641,51 @@ func (f *S3IAMTestFramework) CreateBucket(s3Client *s3.S3, bucketName string) er
return nil return nil
} }
// CreateBucketWithCleanup creates a bucket, cleaning up any existing bucket first
func (f *S3IAMTestFramework) CreateBucketWithCleanup(s3Client *s3.S3, bucketName string) error {
// First try to create the bucket normally
_, err := s3Client.CreateBucket(&s3.CreateBucketInput{
Bucket: aws.String(bucketName),
})
if err != nil {
// If bucket already exists, clean it up first
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "BucketAlreadyExists" {
f.t.Logf("Bucket %s already exists, cleaning up first", bucketName)
// Empty the existing bucket
f.emptyBucket(s3Client, bucketName)
// Don't need to recreate - bucket already exists and is now empty
} else {
return err
}
}
// Track bucket for cleanup
f.createdBuckets = append(f.createdBuckets, bucketName)
return nil
}
// emptyBucket removes all objects from a bucket
func (f *S3IAMTestFramework) emptyBucket(s3Client *s3.S3, bucketName string) {
// Delete all objects
listResult, err := s3Client.ListObjects(&s3.ListObjectsInput{
Bucket: aws.String(bucketName),
})
if err == nil {
for _, obj := range listResult.Contents {
_, err := s3Client.DeleteObject(&s3.DeleteObjectInput{
Bucket: aws.String(bucketName),
Key: obj.Key,
})
if err != nil {
f.t.Logf("Warning: Failed to delete object %s/%s: %v", bucketName, *obj.Key, err)
}
}
}
}
// Cleanup cleans up test resources // Cleanup cleans up test resources
func (f *S3IAMTestFramework) Cleanup() { func (f *S3IAMTestFramework) Cleanup() {
// Clean up buckets (best effort) // Clean up buckets (best effort)

24
test/s3/iam/s3_iam_integration_test.go

@ -17,7 +17,7 @@ import (
const ( const (
testEndpoint = "http://localhost:8333" testEndpoint = "http://localhost:8333"
testRegion = "us-west-2" testRegion = "us-west-2"
testBucket = "test-iam-bucket"
testBucketPrefix = "test-iam-bucket"
testObjectKey = "test-object.txt" testObjectKey = "test-object.txt"
testObjectData = "Hello, SeaweedFS IAM Integration!" testObjectData = "Hello, SeaweedFS IAM Integration!"
) )
@ -176,34 +176,23 @@ func TestS3IAMPolicyEnforcement(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// Should NOT be able to read objects // Should NOT be able to read objects
// TODO: Fix IAM policy evaluation system - explicit deny statements are not being enforced
// This is a known issue where the policy engine allows read operations despite explicit deny
_, err = writeOnlyClient.GetObject(&s3.GetObjectInput{ _, err = writeOnlyClient.GetObject(&s3.GetObjectInput{
Bucket: aws.String(testBucket), Bucket: aws.String(testBucket),
Key: aws.String(testObjectKey), Key: aws.String(testObjectKey),
}) })
if err == nil {
t.Skip("KNOWN ISSUE: IAM policy evaluation system does not properly enforce explicit deny statements for write-only roles")
} else {
// If the error is properly returned, verify it's AccessDenied
require.Error(t, err)
if awsErr, ok := err.(awserr.Error); ok { if awsErr, ok := err.(awserr.Error); ok {
assert.Equal(t, "AccessDenied", awsErr.Code()) assert.Equal(t, "AccessDenied", awsErr.Code())
} }
}
// Should NOT be able to list objects // Should NOT be able to list objects
// TODO: Same IAM policy evaluation issue as above
_, err = writeOnlyClient.ListObjects(&s3.ListObjectsInput{ _, err = writeOnlyClient.ListObjects(&s3.ListObjectsInput{
Bucket: aws.String(testBucket), Bucket: aws.String(testBucket),
}) })
if err == nil {
t.Skip("KNOWN ISSUE: IAM policy evaluation system does not properly enforce explicit deny statements for list operations")
} else {
// If the error is properly returned, verify it's AccessDenied
require.Error(t, err)
if awsErr, ok := err.(awserr.Error); ok { if awsErr, ok := err.(awserr.Error); ok {
assert.Equal(t, "AccessDenied", awsErr.Code()) assert.Equal(t, "AccessDenied", awsErr.Code())
} }
}
}) })
t.Run("admin_policy_enforcement", func(t *testing.T) { t.Run("admin_policy_enforcement", func(t *testing.T) {
@ -547,12 +536,13 @@ func TestS3IAMPresignedURLIntegration(t *testing.T) {
adminClient, err := framework.CreateS3ClientWithJWT("admin-user", "TestAdminRole") adminClient, err := framework.CreateS3ClientWithJWT("admin-user", "TestAdminRole")
require.NoError(t, err) require.NoError(t, err)
err = framework.CreateBucket(adminClient, testBucket)
// Use static bucket name but with cleanup to handle conflicts
err = framework.CreateBucketWithCleanup(adminClient, testBucketPrefix)
require.NoError(t, err) require.NoError(t, err)
// Put test object // Put test object
_, err = adminClient.PutObject(&s3.PutObjectInput{ _, err = adminClient.PutObject(&s3.PutObjectInput{
Bucket: aws.String(testBucket),
Bucket: aws.String(testBucketPrefix),
Key: aws.String(testObjectKey), Key: aws.String(testObjectKey),
Body: strings.NewReader(testObjectData), Body: strings.NewReader(testObjectData),
}) })
@ -565,7 +555,7 @@ func TestS3IAMPresignedURLIntegration(t *testing.T) {
// Test direct object access with JWT token (which is what JWT authentication supports) // Test direct object access with JWT token (which is what JWT authentication supports)
_, err := adminClient.GetObject(&s3.GetObjectInput{ _, err := adminClient.GetObject(&s3.GetObjectInput{
Bucket: aws.String(testBucket),
Bucket: aws.String(testBucketPrefix),
Key: aws.String(testObjectKey), Key: aws.String(testObjectKey),
}) })
require.NoError(t, err, "Direct object access with JWT should work") require.NoError(t, err, "Direct object access with JWT should work")

Loading…
Cancel
Save