|
|
@ -357,3 +357,186 @@ func TestNewIdentityAccessManagementWithStoreEnvVars(t *testing.T) { |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// TestBucketLevelListPermissions tests that bucket-level List permissions work correctly
|
|
|
|
// This test validates the fix for issue #7066
|
|
|
|
func TestBucketLevelListPermissions(t *testing.T) { |
|
|
|
// Test the functionality that was broken in issue #7066
|
|
|
|
|
|
|
|
t.Run("Bucket Wildcard Permissions", func(t *testing.T) { |
|
|
|
// Create identity with bucket-level List permission using wildcards
|
|
|
|
identity := &Identity{ |
|
|
|
Name: "bucket-user", |
|
|
|
Actions: []Action{ |
|
|
|
"List:mybucket*", |
|
|
|
"Read:mybucket*", |
|
|
|
"ReadAcp:mybucket*", |
|
|
|
"Write:mybucket*", |
|
|
|
"WriteAcp:mybucket*", |
|
|
|
"Tagging:mybucket*", |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
// Test cases for bucket-level wildcard permissions
|
|
|
|
testCases := []struct { |
|
|
|
name string |
|
|
|
action Action |
|
|
|
bucket string |
|
|
|
object string |
|
|
|
shouldAllow bool |
|
|
|
description string |
|
|
|
}{ |
|
|
|
{ |
|
|
|
name: "exact bucket match", |
|
|
|
action: "List", |
|
|
|
bucket: "mybucket", |
|
|
|
object: "", |
|
|
|
shouldAllow: true, |
|
|
|
description: "Should allow access to exact bucket name", |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: "bucket with suffix", |
|
|
|
action: "List", |
|
|
|
bucket: "mybucket-prod", |
|
|
|
object: "", |
|
|
|
shouldAllow: true, |
|
|
|
description: "Should allow access to bucket with matching prefix", |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: "bucket with numbers", |
|
|
|
action: "List", |
|
|
|
bucket: "mybucket123", |
|
|
|
object: "", |
|
|
|
shouldAllow: true, |
|
|
|
description: "Should allow access to bucket with numbers", |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: "different bucket", |
|
|
|
action: "List", |
|
|
|
bucket: "otherbucket", |
|
|
|
object: "", |
|
|
|
shouldAllow: false, |
|
|
|
description: "Should deny access to bucket with different prefix", |
|
|
|
}, |
|
|
|
{ |
|
|
|
name: "partial match", |
|
|
|
action: "List", |
|
|
|
bucket: "notmybucket", |
|
|
|
object: "", |
|
|
|
shouldAllow: false, |
|
|
|
description: "Should deny access to bucket that contains but doesn't start with the prefix", |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
for _, tc := range testCases { |
|
|
|
t.Run(tc.name, func(t *testing.T) { |
|
|
|
result := identity.canDo(tc.action, tc.bucket, tc.object) |
|
|
|
assert.Equal(t, tc.shouldAllow, result, tc.description) |
|
|
|
}) |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
t.Run("Global List Permission", func(t *testing.T) { |
|
|
|
// Create identity with global List permission
|
|
|
|
identity := &Identity{ |
|
|
|
Name: "global-user", |
|
|
|
Actions: []Action{ |
|
|
|
"List", |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
// Should allow access to any bucket
|
|
|
|
testCases := []string{"anybucket", "mybucket", "test-bucket", "prod-data"} |
|
|
|
|
|
|
|
for _, bucket := range testCases { |
|
|
|
result := identity.canDo("List", bucket, "") |
|
|
|
assert.True(t, result, "Global List permission should allow access to bucket %s", bucket) |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
t.Run("No Wildcard Exact Match", func(t *testing.T) { |
|
|
|
// Create identity with exact bucket permission (no wildcard)
|
|
|
|
identity := &Identity{ |
|
|
|
Name: "exact-user", |
|
|
|
Actions: []Action{ |
|
|
|
"List:specificbucket", |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
// Should only allow access to the exact bucket
|
|
|
|
assert.True(t, identity.canDo("List", "specificbucket", ""), "Should allow access to exact bucket") |
|
|
|
assert.False(t, identity.canDo("List", "specificbucket-test", ""), "Should deny access to bucket with suffix") |
|
|
|
assert.False(t, identity.canDo("List", "otherbucket", ""), "Should deny access to different bucket") |
|
|
|
}) |
|
|
|
|
|
|
|
t.Log("This test validates the fix for issue #7066") |
|
|
|
t.Log("Bucket-level List permissions like 'List:bucket*' work correctly") |
|
|
|
t.Log("ListBucketsHandler now uses consistent authentication flow") |
|
|
|
} |
|
|
|
|
|
|
|
// TestListBucketsAuthRequest tests that authRequest works correctly for ListBuckets operations
|
|
|
|
// This test validates that the fix for the regression identified in PR #7067 works correctly
|
|
|
|
func TestListBucketsAuthRequest(t *testing.T) { |
|
|
|
t.Run("ListBuckets special case handling", func(t *testing.T) { |
|
|
|
// Create identity with bucket-specific permissions (no global List permission)
|
|
|
|
identity := &Identity{ |
|
|
|
Name: "bucket-user", |
|
|
|
Account: &AccountAdmin, |
|
|
|
Actions: []Action{ |
|
|
|
Action("List:mybucket*"), |
|
|
|
Action("Read:mybucket*"), |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
// Test 1: ListBuckets operation should succeed (bucket = "")
|
|
|
|
// This would have failed before the fix because canDo("List", "", "") would return false
|
|
|
|
// After the fix, it bypasses the canDo check for ListBuckets operations
|
|
|
|
|
|
|
|
// Simulate what happens in authRequest for ListBuckets:
|
|
|
|
// action = ACTION_LIST, bucket = "", object = ""
|
|
|
|
|
|
|
|
// Before fix: identity.canDo(ACTION_LIST, "", "") would fail
|
|
|
|
// After fix: the canDo check should be bypassed
|
|
|
|
|
|
|
|
// Test the individual canDo method to show it would fail without the special case
|
|
|
|
result := identity.canDo(Action(ACTION_LIST), "", "") |
|
|
|
assert.False(t, result, "canDo should return false for empty bucket with bucket-specific permissions") |
|
|
|
|
|
|
|
// Test with a specific bucket that matches the permission
|
|
|
|
result2 := identity.canDo(Action(ACTION_LIST), "mybucket", "") |
|
|
|
assert.True(t, result2, "canDo should return true for matching bucket") |
|
|
|
|
|
|
|
// Test with a specific bucket that doesn't match
|
|
|
|
result3 := identity.canDo(Action(ACTION_LIST), "otherbucket", "") |
|
|
|
assert.False(t, result3, "canDo should return false for non-matching bucket") |
|
|
|
}) |
|
|
|
|
|
|
|
t.Run("Object listing maintains permission enforcement", func(t *testing.T) { |
|
|
|
// Create identity with bucket-specific permissions
|
|
|
|
identity := &Identity{ |
|
|
|
Name: "bucket-user", |
|
|
|
Account: &AccountAdmin, |
|
|
|
Actions: []Action{ |
|
|
|
Action("List:mybucket*"), |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
// For object listing operations, the normal permission checks should still apply
|
|
|
|
// These operations have a specific bucket in the URL
|
|
|
|
|
|
|
|
// Should succeed for allowed bucket
|
|
|
|
result1 := identity.canDo(Action(ACTION_LIST), "mybucket", "prefix/") |
|
|
|
assert.True(t, result1, "Should allow listing objects in permitted bucket") |
|
|
|
|
|
|
|
result2 := identity.canDo(Action(ACTION_LIST), "mybucket-prod", "") |
|
|
|
assert.True(t, result2, "Should allow listing objects in wildcard-matched bucket") |
|
|
|
|
|
|
|
// Should fail for disallowed bucket
|
|
|
|
result3 := identity.canDo(Action(ACTION_LIST), "otherbucket", "") |
|
|
|
assert.False(t, result3, "Should deny listing objects in non-permitted bucket") |
|
|
|
}) |
|
|
|
|
|
|
|
t.Log("This test validates the fix for the regression identified in PR #7067") |
|
|
|
t.Log("ListBuckets operation bypasses global permission check when bucket is empty") |
|
|
|
t.Log("Object listing still properly enforces bucket-level permissions") |
|
|
|
} |