diff options
Diffstat (limited to 'test/s3/iam')
| -rw-r--r-- | test/s3/iam/docker-compose-simple.yml | 2 | ||||
| -rw-r--r-- | test/s3/iam/docker-compose.test.yml | 2 | ||||
| -rw-r--r-- | test/s3/iam/docker-compose.yml | 2 | ||||
| -rwxr-xr-x | test/s3/iam/run_all_tests.sh | 14 | ||||
| -rwxr-xr-x | test/s3/iam/run_performance_tests.sh | 2 | ||||
| -rwxr-xr-x | test/s3/iam/run_stress_tests.sh | 2 | ||||
| -rw-r--r-- | test/s3/iam/s3_iam_distributed_test.go | 4 | ||||
| -rw-r--r-- | test/s3/iam/s3_iam_framework.go | 22 | ||||
| -rw-r--r-- | test/s3/iam/s3_iam_integration_test.go | 92 | ||||
| -rwxr-xr-x | test/s3/iam/setup_all_tests.sh | 32 | ||||
| -rwxr-xr-x | test/s3/iam/setup_keycloak.sh | 64 | ||||
| -rwxr-xr-x | test/s3/iam/setup_keycloak_docker.sh | 26 |
12 files changed, 130 insertions, 134 deletions
diff --git a/test/s3/iam/docker-compose-simple.yml b/test/s3/iam/docker-compose-simple.yml index 9e3b91e42..b52a158a3 100644 --- a/test/s3/iam/docker-compose-simple.yml +++ b/test/s3/iam/docker-compose-simple.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: # Keycloak Identity Provider keycloak: diff --git a/test/s3/iam/docker-compose.test.yml b/test/s3/iam/docker-compose.test.yml index e759f63dc..bb229cfc3 100644 --- a/test/s3/iam/docker-compose.test.yml +++ b/test/s3/iam/docker-compose.test.yml @@ -1,6 +1,4 @@ # Docker Compose for SeaweedFS S3 IAM Integration Tests -version: '3.8' - services: # SeaweedFS Master seaweedfs-master: diff --git a/test/s3/iam/docker-compose.yml b/test/s3/iam/docker-compose.yml index 9e9c00f6d..fd3e3039f 100644 --- a/test/s3/iam/docker-compose.yml +++ b/test/s3/iam/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: # Keycloak Identity Provider keycloak: diff --git a/test/s3/iam/run_all_tests.sh b/test/s3/iam/run_all_tests.sh index f5c2cea59..7bb8ba956 100755 --- a/test/s3/iam/run_all_tests.sh +++ b/test/s3/iam/run_all_tests.sh @@ -34,10 +34,10 @@ run_test_category() { echo -e "${YELLOW}๐งช Running $description...${NC}" if go test -v -timeout=$TEST_TIMEOUT -run "$test_pattern" ./...; then - echo -e "${GREEN}โ
$description completed successfully${NC}" + echo -e "${GREEN}[OK] $description completed successfully${NC}" return 0 else - echo -e "${RED}โ $description failed${NC}" + echo -e "${RED}[FAIL] $description failed${NC}" return 1 fi } @@ -83,10 +83,10 @@ fi echo -e "\n${BLUE}5. Benchmark Tests${NC}" TOTAL_CATEGORIES=$((TOTAL_CATEGORIES + 1)) if go test -bench=. -benchmem -timeout=$TEST_TIMEOUT ./...; then - echo -e "${GREEN}โ
Benchmark tests completed successfully${NC}" + echo -e "${GREEN}[OK] Benchmark tests completed successfully${NC}" PASSED_CATEGORIES=$((PASSED_CATEGORIES + 1)) else - echo -e "${RED}โ Benchmark tests failed${NC}" + echo -e "${RED}[FAIL] Benchmark tests failed${NC}" fi # 6. Versioning Stress Tests @@ -94,10 +94,10 @@ echo -e "\n${BLUE}6. S3 Versioning Stress Tests${NC}" TOTAL_CATEGORIES=$((TOTAL_CATEGORIES + 1)) if [ -f "../versioning/enable_stress_tests.sh" ]; then if (cd ../versioning && ./enable_stress_tests.sh); then - echo -e "${GREEN}โ
Versioning stress tests completed successfully${NC}" + echo -e "${GREEN}[OK] Versioning stress tests completed successfully${NC}" PASSED_CATEGORIES=$((PASSED_CATEGORIES + 1)) else - echo -e "${RED}โ Versioning stress tests failed${NC}" + echo -e "${RED}[FAIL] Versioning stress tests failed${NC}" fi else echo -e "${YELLOW}โ ๏ธ Versioning stress tests not available${NC}" @@ -114,6 +114,6 @@ if [ $PASSED_CATEGORIES -eq $TOTAL_CATEGORIES ]; then echo -e "\n${GREEN}๐ All test categories passed!${NC}" exit 0 else - echo -e "\n${RED}โ Some test categories failed${NC}" + echo -e "\n${RED}[FAIL] Some test categories failed${NC}" exit 1 fi diff --git a/test/s3/iam/run_performance_tests.sh b/test/s3/iam/run_performance_tests.sh index 293632b2c..e8e8983fb 100755 --- a/test/s3/iam/run_performance_tests.sh +++ b/test/s3/iam/run_performance_tests.sh @@ -23,4 +23,4 @@ go test -bench=. -benchmem -timeout=$TEST_TIMEOUT ./... echo -e "${YELLOW}๐งช Running performance test suite...${NC}" go test -v -timeout=$TEST_TIMEOUT -run "TestS3IAMPerformanceTests" ./... -echo -e "${GREEN}โ
Performance tests completed${NC}" +echo -e "${GREEN}[OK] Performance tests completed${NC}" diff --git a/test/s3/iam/run_stress_tests.sh b/test/s3/iam/run_stress_tests.sh index a302c4488..d7520012a 100755 --- a/test/s3/iam/run_stress_tests.sh +++ b/test/s3/iam/run_stress_tests.sh @@ -33,4 +33,4 @@ for i in $(seq 1 $STRESS_ITERATIONS); do sleep 2 done -echo -e "${GREEN}โ
All stress test iterations completed successfully${NC}" +echo -e "${GREEN}[OK] All stress test iterations completed successfully${NC}" diff --git a/test/s3/iam/s3_iam_distributed_test.go b/test/s3/iam/s3_iam_distributed_test.go index 545a56bcb..fbaf25e9d 100644 --- a/test/s3/iam/s3_iam_distributed_test.go +++ b/test/s3/iam/s3_iam_distributed_test.go @@ -243,7 +243,7 @@ func TestS3IAMDistributedTests(t *testing.T) { // Report results if len(errorList) == 0 { - t.Logf("๐ All %d concurrent operations completed successfully with retry mechanisms!", totalOperations) + t.Logf("All %d concurrent operations completed successfully with retry mechanisms!", totalOperations) } else { t.Logf("Concurrent operations summary:") t.Logf(" Total operations: %d", totalOperations) @@ -262,7 +262,7 @@ func TestS3IAMDistributedTests(t *testing.T) { // With proper retry mechanisms, we should expect near-zero failures // Any remaining errors likely indicate real concurrency issues or system problems if len(errorList) > 0 { - t.Errorf("โ %d operation(s) failed even after retry mechanisms (%.1f%% failure rate). This indicates potential system issues or race conditions that need investigation.", + t.Errorf("%d operation(s) failed even after retry mechanisms (%.1f%% failure rate). This indicates potential system issues or race conditions that need investigation.", len(errorList), float64(len(errorList))/float64(totalOperations)*100) } }) diff --git a/test/s3/iam/s3_iam_framework.go b/test/s3/iam/s3_iam_framework.go index aee70e4a1..92e880bdc 100644 --- a/test/s3/iam/s3_iam_framework.go +++ b/test/s3/iam/s3_iam_framework.go @@ -333,7 +333,7 @@ func (t *BearerTokenTransport) extractPrincipalFromJWT(tokenString string) strin // This is safe because the actual validation happens server-side return []byte("dummy-key"), nil }) - + // Even if parsing fails due to signature verification, we might still get claims if claims, ok := token.Claims.(jwt.MapClaims); ok { // Try multiple possible claim names for the principal ARN @@ -348,7 +348,7 @@ func (t *BearerTokenTransport) extractPrincipalFromJWT(tokenString string) strin } } } - + return "" } @@ -693,13 +693,25 @@ func (f *S3IAMTestFramework) CreateBucketWithCleanup(s3Client *s3.S3, bucketName if err != nil { // If bucket already exists, clean it up first - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "BucketAlreadyExists" { + if awsErr, ok := err.(awserr.Error); ok && (awsErr.Code() == "BucketAlreadyExists" || awsErr.Code() == "BucketAlreadyOwnedByYou") { f.t.Logf("Bucket %s already exists, cleaning up first", bucketName) - // Empty the existing bucket + // First try to delete the bucket completely f.emptyBucket(s3Client, bucketName) + _, deleteErr := s3Client.DeleteBucket(&s3.DeleteBucketInput{ + Bucket: aws.String(bucketName), + }) + if deleteErr != nil { + f.t.Logf("Warning: Failed to delete existing bucket %s: %v", bucketName, deleteErr) + } - // Don't need to recreate - bucket already exists and is now empty + // Now create it fresh + _, err = s3Client.CreateBucket(&s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + }) + if err != nil { + return fmt.Errorf("failed to recreate bucket after cleanup: %v", err) + } } else { return err } diff --git a/test/s3/iam/s3_iam_integration_test.go b/test/s3/iam/s3_iam_integration_test.go index 5c89bda6f..c7836c4bf 100644 --- a/test/s3/iam/s3_iam_integration_test.go +++ b/test/s3/iam/s3_iam_integration_test.go @@ -1,7 +1,6 @@ package iam import ( - "bytes" "fmt" "io" "strings" @@ -15,15 +14,11 @@ import ( ) const ( - testEndpoint = "http://localhost:8333" - testRegion = "us-west-2" - testBucketPrefix = "test-iam-bucket" - testObjectKey = "test-object.txt" - testObjectData = "Hello, SeaweedFS IAM Integration!" -) - -var ( - testBucket = testBucketPrefix + testEndpoint = "http://localhost:8333" + testRegion = "us-west-2" + testBucket = "test-iam-bucket" + testObjectKey = "test-object.txt" + testObjectData = "Hello, SeaweedFS IAM Integration!" ) // TestS3IAMAuthentication tests S3 API authentication with IAM JWT tokens @@ -98,12 +93,14 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { adminClient, err := framework.CreateS3ClientWithJWT("admin-user", "TestAdminRole") require.NoError(t, err) - err = framework.CreateBucket(adminClient, testBucket) + // Use unique bucket name to avoid collection conflicts + bucketName := framework.GenerateUniqueBucketName("test-iam-policy") + err = framework.CreateBucket(adminClient, bucketName) require.NoError(t, err) // Put test object with admin client _, err = adminClient.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testObjectKey), Body: strings.NewReader(testObjectData), }) @@ -116,7 +113,7 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should be able to read objects result, err := readOnlyClient.GetObject(&s3.GetObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testObjectKey), }) require.NoError(t, err) @@ -128,7 +125,7 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should be able to list objects listResult, err := readOnlyClient.ListObjects(&s3.ListObjectsInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), }) require.NoError(t, err) assert.Len(t, listResult.Contents, 1) @@ -136,7 +133,7 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should NOT be able to put objects _, err = readOnlyClient.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String("forbidden-object.txt"), Body: strings.NewReader("This should fail"), }) @@ -147,7 +144,7 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should NOT be able to delete objects _, err = readOnlyClient.DeleteObject(&s3.DeleteObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testObjectKey), }) require.Error(t, err) @@ -166,7 +163,7 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { testWriteData := "Write-only test data" _, err = writeOnlyClient.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testWriteKey), Body: strings.NewReader(testWriteData), }) @@ -174,14 +171,14 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should be able to delete objects _, err = writeOnlyClient.DeleteObject(&s3.DeleteObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testWriteKey), }) require.NoError(t, err) // Should NOT be able to read objects _, err = writeOnlyClient.GetObject(&s3.GetObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testObjectKey), }) require.Error(t, err) @@ -191,7 +188,7 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should NOT be able to list objects _, err = writeOnlyClient.ListObjects(&s3.ListObjectsInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), }) require.Error(t, err) if awsErr, ok := err.(awserr.Error); ok { @@ -206,7 +203,7 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should be able to put objects _, err = adminClient.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testAdminKey), Body: strings.NewReader(testAdminData), }) @@ -214,7 +211,7 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should be able to read objects result, err := adminClient.GetObject(&s3.GetObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testAdminKey), }) require.NoError(t, err) @@ -226,14 +223,14 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should be able to list objects listResult, err := adminClient.ListObjects(&s3.ListObjectsInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), }) require.NoError(t, err) assert.GreaterOrEqual(t, len(listResult.Contents), 1) // Should be able to delete objects _, err = adminClient.DeleteObject(&s3.DeleteObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testAdminKey), }) require.NoError(t, err) @@ -241,14 +238,14 @@ func TestS3IAMPolicyEnforcement(t *testing.T) { // Should be able to delete buckets // First delete remaining objects _, err = adminClient.DeleteObject(&s3.DeleteObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testObjectKey), }) require.NoError(t, err) // Then delete the bucket _, err = adminClient.DeleteBucket(&s3.DeleteBucketInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), }) require.NoError(t, err) }) @@ -398,7 +395,9 @@ func TestS3IAMBucketPolicyIntegration(t *testing.T) { adminClient, err := framework.CreateS3ClientWithJWT("admin-user", "TestAdminRole") require.NoError(t, err) - err = framework.CreateBucket(adminClient, testBucket) + // Use unique bucket name to avoid collection conflicts + bucketName := framework.GenerateUniqueBucketName("test-iam-bucket-policy") + err = framework.CreateBucket(adminClient, bucketName) require.NoError(t, err) t.Run("bucket_policy_allows_public_read", func(t *testing.T) { @@ -414,17 +413,17 @@ func TestS3IAMBucketPolicyIntegration(t *testing.T) { "Resource": ["arn:seaweed:s3:::%s/*"] } ] - }`, testBucket) + }`, bucketName) _, err = adminClient.PutBucketPolicy(&s3.PutBucketPolicyInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Policy: aws.String(bucketPolicy), }) require.NoError(t, err) // Put test object _, err = adminClient.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testObjectKey), Body: strings.NewReader(testObjectData), }) @@ -435,7 +434,7 @@ func TestS3IAMBucketPolicyIntegration(t *testing.T) { require.NoError(t, err) result, err := readOnlyClient.GetObject(&s3.GetObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testObjectKey), }) require.NoError(t, err) @@ -459,17 +458,17 @@ func TestS3IAMBucketPolicyIntegration(t *testing.T) { "Resource": ["arn:seaweed:s3:::%s/*"] } ] - }`, testBucket) + }`, bucketName) _, err = adminClient.PutBucketPolicy(&s3.PutBucketPolicyInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Policy: aws.String(bucketPolicy), }) require.NoError(t, err) // Verify that the bucket policy was stored successfully by retrieving it policyResult, err := adminClient.GetBucketPolicy(&s3.GetBucketPolicyInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), }) require.NoError(t, err) assert.Contains(t, *policyResult.Policy, "s3:DeleteObject") @@ -483,18 +482,18 @@ func TestS3IAMBucketPolicyIntegration(t *testing.T) { // Cleanup - delete bucket policy first, then objects and bucket _, err = adminClient.DeleteBucketPolicy(&s3.DeleteBucketPolicyInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), }) require.NoError(t, err) _, err = adminClient.DeleteObject(&s3.DeleteObjectInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), Key: aws.String(testObjectKey), }) require.NoError(t, err) _, err = adminClient.DeleteBucket(&s3.DeleteBucketInput{ - Bucket: aws.String(testBucket), + Bucket: aws.String(bucketName), }) require.NoError(t, err) } @@ -527,15 +526,6 @@ func TestS3IAMContextualPolicyEnforcement(t *testing.T) { }) } -// Helper function to create test content of specific size -func createTestContent(size int) *bytes.Reader { - content := make([]byte, size) - for i := range content { - content[i] = byte(i % 256) - } - return bytes.NewReader(content) -} - // TestS3IAMPresignedURLIntegration tests presigned URL generation with IAM func TestS3IAMPresignedURLIntegration(t *testing.T) { framework := NewS3IAMTestFramework(t) @@ -546,12 +536,12 @@ func TestS3IAMPresignedURLIntegration(t *testing.T) { require.NoError(t, err) // Use static bucket name but with cleanup to handle conflicts - err = framework.CreateBucketWithCleanup(adminClient, testBucketPrefix) + err = framework.CreateBucketWithCleanup(adminClient, testBucket) require.NoError(t, err) // Put test object _, err = adminClient.PutObject(&s3.PutObjectInput{ - Bucket: aws.String(testBucketPrefix), + Bucket: aws.String(testBucket), Key: aws.String(testObjectKey), Body: strings.NewReader(testObjectData), }) @@ -573,13 +563,13 @@ func TestS3IAMPresignedURLIntegration(t *testing.T) { // Test direct object access with JWT Bearer token (recommended approach) _, err := adminClient.GetObject(&s3.GetObjectInput{ - Bucket: aws.String(testBucketPrefix), + Bucket: aws.String(testBucket), Key: aws.String(testObjectKey), }) require.NoError(t, err, "Direct object access with JWT Bearer token works correctly") - t.Log("โ
JWT Bearer token authentication confirmed working for direct S3 API calls") - t.Log("โน๏ธ Note: Presigned URLs are not supported with JWT Bearer authentication by design") + t.Log("JWT Bearer token authentication confirmed working for direct S3 API calls") + t.Log("Note: Presigned URLs are not supported with JWT Bearer authentication by design") }) // Cleanup diff --git a/test/s3/iam/setup_all_tests.sh b/test/s3/iam/setup_all_tests.sh index 597d367aa..aaec54691 100755 --- a/test/s3/iam/setup_all_tests.sh +++ b/test/s3/iam/setup_all_tests.sh @@ -30,12 +30,12 @@ check_prerequisites() { done if [ ${#missing_tools[@]} -gt 0 ]; then - echo -e "${RED}โ Missing required tools: ${missing_tools[*]}${NC}" + echo -e "${RED}[FAIL] Missing required tools: ${missing_tools[*]}${NC}" echo -e "${YELLOW}Please install the missing tools and try again${NC}" exit 1 fi - echo -e "${GREEN}โ
All prerequisites met${NC}" + echo -e "${GREEN}[OK] All prerequisites met${NC}" } # Set up Keycloak for OIDC testing @@ -43,11 +43,11 @@ setup_keycloak() { echo -e "\n${BLUE}1. Setting up Keycloak for OIDC testing...${NC}" if ! "${SCRIPT_DIR}/setup_keycloak.sh"; then - echo -e "${RED}โ Failed to set up Keycloak${NC}" + echo -e "${RED}[FAIL] Failed to set up Keycloak${NC}" return 1 fi - echo -e "${GREEN}โ
Keycloak setup completed${NC}" + echo -e "${GREEN}[OK] Keycloak setup completed${NC}" } # Set up SeaweedFS test cluster @@ -58,7 +58,7 @@ setup_seaweedfs_cluster() { echo -e "${YELLOW}๐ง Building SeaweedFS binary...${NC}" cd "${SCRIPT_DIR}/../../../" # Go to seaweedfs root if ! make > /dev/null 2>&1; then - echo -e "${RED}โ Failed to build SeaweedFS binary${NC}" + echo -e "${RED}[FAIL] Failed to build SeaweedFS binary${NC}" return 1 fi @@ -68,7 +68,7 @@ setup_seaweedfs_cluster() { echo -e "${YELLOW}๐งน Cleaning up existing test data...${NC}" rm -rf test-volume-data/* 2>/dev/null || true - echo -e "${GREEN}โ
SeaweedFS cluster setup completed${NC}" + echo -e "${GREEN}[OK] SeaweedFS cluster setup completed${NC}" } # Set up test data and configurations @@ -79,18 +79,18 @@ setup_test_configurations() { if [ ! -f "${SCRIPT_DIR}/iam_config.json" ]; then echo -e "${YELLOW}โ ๏ธ IAM configuration not found, using default config${NC}" cp "${SCRIPT_DIR}/iam_config.local.json" "${SCRIPT_DIR}/iam_config.json" 2>/dev/null || { - echo -e "${RED}โ No IAM configuration files found${NC}" + echo -e "${RED}[FAIL] No IAM configuration files found${NC}" return 1 } fi # Validate configuration if ! jq . "${SCRIPT_DIR}/iam_config.json" >/dev/null; then - echo -e "${RED}โ Invalid IAM configuration JSON${NC}" + echo -e "${RED}[FAIL] Invalid IAM configuration JSON${NC}" return 1 fi - echo -e "${GREEN}โ
Test configurations set up${NC}" + echo -e "${GREEN}[OK] Test configurations set up${NC}" } # Verify services are ready @@ -113,13 +113,13 @@ verify_services() { done if [ "$keycloak_ready" = true ]; then - echo -e "${GREEN}โ
Keycloak is ready${NC}" + echo -e "${GREEN}[OK] Keycloak is ready${NC}" else echo -e "${YELLOW}โ ๏ธ Keycloak may not be fully ready yet${NC}" echo -e "${YELLOW}This is okay - tests will wait for Keycloak when needed${NC}" fi - echo -e "${GREEN}โ
Service verification completed${NC}" + echo -e "${GREEN}[OK] Service verification completed${NC}" } # Set up environment variables @@ -145,7 +145,7 @@ export TEST_TIMEOUT=60m export CGO_ENABLED=0 EOF - echo -e "${GREEN}โ
Environment variables set${NC}" + echo -e "${GREEN}[OK] Environment variables set${NC}" } # Display setup summary @@ -157,7 +157,7 @@ display_summary() { echo -e "Test Timeout: ${TEST_TIMEOUT:-60m}" echo -e "IAM Config: ${SCRIPT_DIR}/iam_config.json" echo -e "" - echo -e "${GREEN}โ
Complete test environment setup finished!${NC}" + echo -e "${GREEN}[OK] Complete test environment setup finished!${NC}" echo -e "${YELLOW}๐ก You can now run tests with: make run-all-tests${NC}" echo -e "${YELLOW}๐ก Or run specific tests with: go test -v -timeout=60m -run TestName${NC}" echo -e "${YELLOW}๐ก To stop Keycloak: docker stop keycloak-iam-test${NC}" @@ -173,21 +173,21 @@ main() { if setup_keycloak; then setup_steps+=("keycloak") else - echo -e "${RED}โ Failed to set up Keycloak${NC}" + echo -e "${RED}[FAIL] Failed to set up Keycloak${NC}" exit 1 fi if setup_seaweedfs_cluster; then setup_steps+=("seaweedfs") else - echo -e "${RED}โ Failed to set up SeaweedFS cluster${NC}" + echo -e "${RED}[FAIL] Failed to set up SeaweedFS cluster${NC}" exit 1 fi if setup_test_configurations; then setup_steps+=("config") else - echo -e "${RED}โ Failed to set up test configurations${NC}" + echo -e "${RED}[FAIL] Failed to set up test configurations${NC}" exit 1 fi diff --git a/test/s3/iam/setup_keycloak.sh b/test/s3/iam/setup_keycloak.sh index 5d3cc45d6..14fb08435 100755 --- a/test/s3/iam/setup_keycloak.sh +++ b/test/s3/iam/setup_keycloak.sh @@ -54,7 +54,7 @@ ensure_container() { if [[ -n "$extracted_port" ]]; then KEYCLOAK_PORT="$extracted_port" KEYCLOAK_URL="http://localhost:${KEYCLOAK_PORT}" - echo -e "${GREEN}โ
Using existing container '${CONTAINER_NAME}' on port ${KEYCLOAK_PORT}${NC}" + echo -e "${GREEN}[OK] Using existing container '${CONTAINER_NAME}' on port ${KEYCLOAK_PORT}${NC}" return 0 fi fi @@ -71,11 +71,11 @@ ensure_container() { KEYCLOAK_URL="http://localhost:${KEYCLOAK_PORT}" fi fi - echo -e "${GREEN}โ
Using existing container '${CONTAINER_NAME}' on port ${KEYCLOAK_PORT}${NC}" + echo -e "${GREEN}[OK] Using existing container '${CONTAINER_NAME}' on port ${KEYCLOAK_PORT}${NC}" return 0 fi if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then - echo -e "${GREEN}โ
Using existing container '${CONTAINER_NAME}'${NC}" + echo -e "${GREEN}[OK] Using existing container '${CONTAINER_NAME}'${NC}" return 0 fi echo -e "${YELLOW}๐ณ Starting Keycloak container (${KEYCLOAK_IMAGE})...${NC}" @@ -94,16 +94,16 @@ wait_ready() { echo -e "${YELLOW}โณ Waiting for Keycloak to be ready...${NC}" for i in $(seq 1 120); do if curl -sf "${KEYCLOAK_URL}/health/ready" >/dev/null; then - echo -e "${GREEN}โ
Keycloak health check passed${NC}" + echo -e "${GREEN}[OK] Keycloak health check passed${NC}" return 0 fi if curl -sf "${KEYCLOAK_URL}/realms/master" >/dev/null; then - echo -e "${GREEN}โ
Keycloak master realm accessible${NC}" + echo -e "${GREEN}[OK] Keycloak master realm accessible${NC}" return 0 fi sleep 2 done - echo -e "${RED}โ Keycloak did not become ready in time${NC}" + echo -e "${RED}[FAIL] Keycloak did not become ready in time${NC}" exit 1 } @@ -122,7 +122,7 @@ kcadm() { done if [[ "$auth_success" == false ]]; then - echo -e "${RED}โ Failed to authenticate with any known admin password${NC}" + echo -e "${RED}[FAIL] Failed to authenticate with any known admin password${NC}" return 1 fi @@ -136,17 +136,17 @@ admin_login() { ensure_realm() { if kcadm get realms | grep -q "${REALM_NAME}"; then - echo -e "${GREEN}โ
Realm '${REALM_NAME}' already exists${NC}" + echo -e "${GREEN}[OK] Realm '${REALM_NAME}' already exists${NC}" else echo -e "${YELLOW}๐ Creating realm '${REALM_NAME}'...${NC}" if kcadm create realms -s realm="${REALM_NAME}" -s enabled=true 2>/dev/null; then - echo -e "${GREEN}โ
Realm created${NC}" + echo -e "${GREEN}[OK] Realm created${NC}" else # Check if it exists now (might have been created by another process) if kcadm get realms | grep -q "${REALM_NAME}"; then - echo -e "${GREEN}โ
Realm '${REALM_NAME}' already exists (created concurrently)${NC}" + echo -e "${GREEN}[OK] Realm '${REALM_NAME}' already exists (created concurrently)${NC}" else - echo -e "${RED}โ Failed to create realm '${REALM_NAME}'${NC}" + echo -e "${RED}[FAIL] Failed to create realm '${REALM_NAME}'${NC}" return 1 fi fi @@ -157,7 +157,7 @@ ensure_client() { local id id=$(kcadm get clients -r "${REALM_NAME}" -q clientId="${CLIENT_ID}" | jq -r '.[0].id // empty') if [[ -n "${id}" ]]; then - echo -e "${GREEN}โ
Client '${CLIENT_ID}' already exists${NC}" + echo -e "${GREEN}[OK] Client '${CLIENT_ID}' already exists${NC}" else echo -e "${YELLOW}๐ Creating client '${CLIENT_ID}'...${NC}" kcadm create clients -r "${REALM_NAME}" \ @@ -169,7 +169,7 @@ ensure_client() { -s standardFlowEnabled=true \ -s implicitFlowEnabled=false \ -s secret="${CLIENT_SECRET}" >/dev/null - echo -e "${GREEN}โ
Client created${NC}" + echo -e "${GREEN}[OK] Client created${NC}" fi # Create and configure role mapper for the client @@ -179,7 +179,7 @@ ensure_client() { ensure_role() { local role="$1" if kcadm get roles -r "${REALM_NAME}" | jq -r '.[].name' | grep -qx "${role}"; then - echo -e "${GREEN}โ
Role '${role}' exists${NC}" + echo -e "${GREEN}[OK] Role '${role}' exists${NC}" else echo -e "${YELLOW}๐ Creating role '${role}'...${NC}" kcadm create roles -r "${REALM_NAME}" -s name="${role}" >/dev/null @@ -201,7 +201,7 @@ ensure_user() { -s lastName="User" \ -i) else - echo -e "${GREEN}โ
User '${username}' exists${NC}" + echo -e "${GREEN}[OK] User '${username}' exists${NC}" fi echo -e "${YELLOW}๐ Setting password for '${username}'...${NC}" kcadm set-password -r "${REALM_NAME}" --userid "${uid}" --new-password "${password}" --temporary=false >/dev/null @@ -214,7 +214,7 @@ assign_role() { rid=$(kcadm get roles -r "${REALM_NAME}" | jq -r ".[] | select(.name==\"${role}\") | .id") # Check if role already assigned if kcadm get "users/${uid}/role-mappings/realm" -r "${REALM_NAME}" | jq -r '.[].name' | grep -qx "${role}"; then - echo -e "${GREEN}โ
User '${username}' already has role '${role}'${NC}" + echo -e "${GREEN}[OK] User '${username}' already has role '${role}'${NC}" return 0 fi echo -e "${YELLOW}โ Assigning role '${role}' to '${username}'...${NC}" @@ -229,7 +229,7 @@ configure_role_mapper() { internal_id=$(kcadm get clients -r "${REALM_NAME}" -q clientId="${CLIENT_ID}" | jq -r '.[0].id // empty') if [[ -z "${internal_id}" ]]; then - echo -e "${RED}โ Could not find client ${client_id} to configure role mapper${NC}" + echo -e "${RED}[FAIL] Could not find client ${client_id} to configure role mapper${NC}" return 1 fi @@ -238,7 +238,7 @@ configure_role_mapper() { existing_mapper=$(kcadm get "clients/${internal_id}/protocol-mappers/models" -r "${REALM_NAME}" | jq -r '.[] | select(.name=="realm roles" and .protocolMapper=="oidc-usermodel-realm-role-mapper") | .id // empty') if [[ -n "${existing_mapper}" ]]; then - echo -e "${GREEN}โ
Realm roles mapper already exists${NC}" + echo -e "${GREEN}[OK] Realm roles mapper already exists${NC}" else echo -e "${YELLOW}๐ Creating realm roles mapper...${NC}" @@ -254,11 +254,11 @@ configure_role_mapper() { -s 'config."access.token.claim"=true' \ -s 'config."claim.name"=roles' \ -s 'config."jsonType.label"=String' >/dev/null || { - echo -e "${RED}โ Failed to create realm roles mapper${NC}" + echo -e "${RED}[FAIL] Failed to create realm roles mapper${NC}" return 1 } - echo -e "${GREEN}โ
Realm roles mapper created${NC}" + echo -e "${GREEN}[OK] Realm roles mapper created${NC}" fi } @@ -270,7 +270,7 @@ configure_audience_mapper() { internal_id=$(kcadm get clients -r "${REALM_NAME}" -q clientId="${CLIENT_ID}" | jq -r '.[0].id // empty') if [[ -z "${internal_id}" ]]; then - echo -e "${RED}โ Could not find client ${CLIENT_ID} to configure audience mapper${NC}" + echo -e "${RED}[FAIL] Could not find client ${CLIENT_ID} to configure audience mapper${NC}" return 1 fi @@ -279,7 +279,7 @@ configure_audience_mapper() { existing_mapper=$(kcadm get "clients/${internal_id}/protocol-mappers/models" -r "${REALM_NAME}" | jq -r '.[] | select(.name=="audience-mapper" and .protocolMapper=="oidc-audience-mapper") | .id // empty') if [[ -n "${existing_mapper}" ]]; then - echo -e "${GREEN}โ
Audience mapper already exists${NC}" + echo -e "${GREEN}[OK] Audience mapper already exists${NC}" else echo -e "${YELLOW}๐ Creating audience mapper...${NC}" @@ -292,17 +292,17 @@ configure_audience_mapper() { -s 'config."included.client.audience"='"${CLIENT_ID}" \ -s 'config."id.token.claim"=false' \ -s 'config."access.token.claim"=true' >/dev/null || { - echo -e "${RED}โ Failed to create audience mapper${NC}" + echo -e "${RED}[FAIL] Failed to create audience mapper${NC}" return 1 } - echo -e "${GREEN}โ
Audience mapper created${NC}" + echo -e "${GREEN}[OK] Audience mapper created${NC}" fi } main() { - command -v docker >/dev/null || { echo -e "${RED}โ Docker is required${NC}"; exit 1; } - command -v jq >/dev/null || { echo -e "${RED}โ jq is required${NC}"; exit 1; } + command -v docker >/dev/null || { echo -e "${RED}[FAIL] Docker is required${NC}"; exit 1; } + command -v jq >/dev/null || { echo -e "${RED}[FAIL] jq is required${NC}"; exit 1; } ensure_container echo "Keycloak URL: ${KEYCLOAK_URL}" @@ -347,7 +347,7 @@ main() { -o /tmp/auth_test_response.json) if [[ "${validation_result: -3}" == "200" ]]; then - echo -e "${GREEN}โ
Authentication validation successful${NC}" + echo -e "${GREEN}[OK] Authentication validation successful${NC}" # Extract and decode JWT token to check for roles local access_token=$(cat /tmp/auth_test_response.json | jq -r '.access_token // empty') @@ -363,7 +363,7 @@ main() { local roles=$(echo "${decoded}" | jq -r '.roles // empty' 2>/dev/null || echo "") if [[ -n "${roles}" && "${roles}" != "null" ]]; then - echo -e "${GREEN}โ
JWT token includes roles: ${roles}${NC}" + echo -e "${GREEN}[OK] JWT token includes roles: ${roles}${NC}" else echo -e "${YELLOW}โ ๏ธ JWT token does not include 'roles' claim${NC}" echo -e "${YELLOW}Decoded payload sample:${NC}" @@ -371,14 +371,14 @@ main() { fi fi else - echo -e "${RED}โ Authentication validation failed with HTTP ${validation_result: -3}${NC}" + echo -e "${RED}[FAIL] Authentication validation failed with HTTP ${validation_result: -3}${NC}" echo -e "${YELLOW}Response body:${NC}" cat /tmp/auth_test_response.json 2>/dev/null || echo "No response body" echo -e "${YELLOW}This may indicate a setup issue that needs to be resolved${NC}" fi rm -f /tmp/auth_test_response.json - echo -e "${GREEN}โ
Keycloak test realm '${REALM_NAME}' configured${NC}" + echo -e "${GREEN}[OK] Keycloak test realm '${REALM_NAME}' configured${NC}" } setup_iam_config() { @@ -400,7 +400,7 @@ setup_iam_config() { # Verify source config exists if [[ ! -f "$config_source" ]]; then - echo -e "${RED}โ Config file $config_source not found in $script_dir${NC}" + echo -e "${RED}[FAIL] Config file $config_source not found in $script_dir${NC}" exit 1 fi @@ -408,7 +408,7 @@ setup_iam_config() { cp "$config_source" "iam_config.json" local detected_issuer=$(cat iam_config.json | jq -r '.providers[] | select(.name=="keycloak") | .config.issuer') - echo -e "${GREEN}โ
IAM configuration set successfully${NC}" + echo -e "${GREEN}[OK] IAM configuration set successfully${NC}" echo " - Using config: $config_source" echo " - Keycloak issuer: $detected_issuer" } diff --git a/test/s3/iam/setup_keycloak_docker.sh b/test/s3/iam/setup_keycloak_docker.sh index e648bb7b6..6dce68abf 100755 --- a/test/s3/iam/setup_keycloak_docker.sh +++ b/test/s3/iam/setup_keycloak_docker.sh @@ -19,7 +19,7 @@ timeout 120 bash -c ' echo "Waiting for Keycloak..." sleep 5 done - echo "โ
Keycloak health check passed" + echo "[OK] Keycloak health check passed" ' "$KEYCLOAK_URL" # Download kcadm.sh if not available @@ -51,14 +51,14 @@ kcadm() { sleep 5 done - echo "โ Failed to execute kcadm command after $max_retries retries" + echo "[FAIL] Failed to execute kcadm command after $max_retries retries" return 1 } # Create realm echo "๐ Creating realm '$REALM_NAME'..." kcadm create realms -s realm="$REALM_NAME" -s enabled=true || echo "Realm may already exist" -echo "โ
Realm created" +echo "[OK] Realm created" # Create OIDC client echo "๐ Creating client '$CLIENT_ID'..." @@ -74,9 +74,9 @@ CLIENT_UUID=$(kcadm create clients -r "$REALM_NAME" \ -i 2>/dev/null || echo "existing-client") if [ "$CLIENT_UUID" != "existing-client" ]; then - echo "โ
Client created with ID: $CLIENT_UUID" + echo "[OK] Client created with ID: $CLIENT_UUID" else - echo "โ
Using existing client" + echo "[OK] Using existing client" CLIENT_UUID=$(kcadm get clients -r "$REALM_NAME" -q clientId="$CLIENT_ID" --fields id --format csv --noquotes | tail -n +2) fi @@ -94,8 +94,8 @@ MAPPER_CONFIG='{ } }' -kcadm create clients/"$CLIENT_UUID"/protocol-mappers/models -r "$REALM_NAME" -b "$MAPPER_CONFIG" 2>/dev/null || echo "โ
Role mapper already exists" -echo "โ
Realm roles mapper configured" +kcadm create clients/"$CLIENT_UUID"/protocol-mappers/models -r "$REALM_NAME" -b "$MAPPER_CONFIG" 2>/dev/null || echo "[OK] Role mapper already exists" +echo "[OK] Realm roles mapper configured" # Configure audience mapper to ensure JWT tokens have correct audience claim echo "๐ง Configuring audience mapper for client '$CLIENT_ID'..." @@ -110,8 +110,8 @@ AUDIENCE_MAPPER_CONFIG='{ } }' -kcadm create clients/"$CLIENT_UUID"/protocol-mappers/models -r "$REALM_NAME" -b "$AUDIENCE_MAPPER_CONFIG" 2>/dev/null || echo "โ
Audience mapper already exists" -echo "โ
Audience mapper configured" +kcadm create clients/"$CLIENT_UUID"/protocol-mappers/models -r "$REALM_NAME" -b "$AUDIENCE_MAPPER_CONFIG" 2>/dev/null || echo "[OK] Audience mapper already exists" +echo "[OK] Audience mapper configured" # Create realm roles echo "๐ Creating realm roles..." @@ -393,11 +393,11 @@ ACCESS_TOKEN=$(curl -s -X POST "$KEYCLOAK_TOKEN_URL" \ -d "scope=openid profile email" | jq -r '.access_token') if [ "$ACCESS_TOKEN" = "null" ] || [ -z "$ACCESS_TOKEN" ]; then - echo "โ Failed to obtain access token" + echo "[FAIL] Failed to obtain access token" exit 1 fi -echo "โ
Authentication validation successful" +echo "[OK] Authentication validation successful" # Decode and check JWT claims PAYLOAD=$(echo "$ACCESS_TOKEN" | cut -d'.' -f2) @@ -410,10 +410,10 @@ CLAIMS=$(echo "$PAYLOAD" | base64 -d 2>/dev/null | jq .) ROLES=$(echo "$CLAIMS" | jq -r '.roles[]?') if [ -n "$ROLES" ]; then - echo "โ
JWT token includes roles: [$(echo "$ROLES" | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g')]" + echo "[OK] JWT token includes roles: [$(echo "$ROLES" | tr '\n' ',' | sed 's/,$//' | sed 's/,/, /g')]" else echo "โ ๏ธ No roles found in JWT token" fi -echo "โ
Keycloak test realm '$REALM_NAME' configured for Docker environment" +echo "[OK] Keycloak test realm '$REALM_NAME' configured for Docker environment" echo "๐ณ Setup complete! You can now run: docker-compose up -d" |
