mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-07 04:27:49 +01:00
s3: require their own actions to change a bucket's CORS or versioning (#12433)
* s3: require their own actions to change a bucket's CORS or versioning PUT/DELETE ?cors and PUT ?versioning were authorized as Write, so an identity granted only object writes on a bucket could replace its CORS rules or suspend versioning. They now need PutBucketCors, DeleteBucketCors and PutBucketVersioning (or Admin), and inline policies granting s3:PutBucketCors, s3:DeleteBucketCors or s3:PutBucketVersioning map to those actions instead of Write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * s3: test that object Write cannot change bucket CORS or versioning Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * admin: offer the bucket CORS and versioning permissions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * s3: test each bucket config action with its own identity Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3a579ece3b
commit
3e64326f2b
7 files changed
+109
-7
No files matched your search
@@ -245,6 +245,11 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
<option value="PutBucketPolicy">Put Bucket Policy</option>
|
||||
<option value="DeleteBucketPolicy">Delete Bucket Policy</option>
|
||||
</optgroup>
|
||||
<optgroup label="Bucket Configuration Permissions">
|
||||
<option value="PutBucketCors">Put Bucket CORS</option>
|
||||
<option value="DeleteBucketCors">Delete Bucket CORS</option>
|
||||
<option value="PutBucketVersioning">Put Bucket Versioning</option>
|
||||
</optgroup>
|
||||
<optgroup label="S3 Tables Permissions">
|
||||
<option value="S3TablesAdmin">S3 Tables Admin (Full Access)</option>
|
||||
<option value="CreateTableBucket">Create Table Bucket</option>
|
||||
@@ -359,6 +364,11 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
<option value="PutBucketPolicy">Put Bucket Policy</option>
|
||||
<option value="DeleteBucketPolicy">Delete Bucket Policy</option>
|
||||
</optgroup>
|
||||
<optgroup label="Bucket Configuration Permissions">
|
||||
<option value="PutBucketCors">Put Bucket CORS</option>
|
||||
<option value="DeleteBucketCors">Delete Bucket CORS</option>
|
||||
<option value="PutBucketVersioning">Put Bucket Versioning</option>
|
||||
</optgroup>
|
||||
<optgroup label="S3 Tables Permissions">
|
||||
<option value="S3TablesAdmin">S3 Tables Admin (Full Access)</option>
|
||||
<option value="CreateTableBucket">Create Table Bucket</option>
|
||||
|
||||
@@ -237,7 +237,7 @@ func ObjectStoreUsers(data dash.ObjectStoreUsersData) templ.Component {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div><div class=\"mb-3\"><label for=\"email\" class=\"form-label\">Email</label> <input type=\"email\" class=\"form-control\" id=\"email\" name=\"email\"></div><div class=\"mb-3\"><label for=\"actions\" class=\"form-label\">Permissions</label> <select multiple class=\"form-control\" id=\"actions\" name=\"actions\" size=\"10\"><option value=\"Admin\">Admin (Full Access)</option> <option value=\"Read\">Read</option> <option value=\"Write\">Write</option> <option value=\"List\">List</option> <option value=\"Tagging\">Tagging</option> <option value=\"ReadAcp\" title=\"Needed for GET ?acl on buckets and objects\">Read ACL (ReadAcp)</option> <option value=\"WriteAcp\" title=\"Needed for PUT ?acl and for uploads that send x-amz-acl or x-amz-grant-* headers\">Write ACL (WriteAcp)</option> <optgroup label=\"Object Lock Permissions\"><option value=\"BypassGovernanceRetention\">Bypass Governance Retention</option> <option value=\"GetObjectRetention\">Get Object Retention</option> <option value=\"PutObjectRetention\">Put Object Retention</option> <option value=\"GetObjectLegalHold\">Get Object Legal Hold</option> <option value=\"PutObjectLegalHold\">Put Object Legal Hold</option> <option value=\"GetBucketObjectLockConfiguration\">Get Bucket Object Lock Configuration</option> <option value=\"PutBucketObjectLockConfiguration\">Put Bucket Object Lock Configuration</option></optgroup> <optgroup label=\"Bucket Policy Permissions\"><option value=\"PutBucketPolicy\">Put Bucket Policy</option> <option value=\"DeleteBucketPolicy\">Delete Bucket Policy</option></optgroup> <optgroup label=\"S3 Tables Permissions\"><option value=\"S3TablesAdmin\">S3 Tables Admin (Full Access)</option> <option value=\"CreateTableBucket\">Create Table Bucket</option> <option value=\"GetTableBucket\">Get Table Bucket</option> <option value=\"ListTableBuckets\">List Table Buckets</option> <option value=\"DeleteTableBucket\">Delete Table Bucket</option> <option value=\"PutTableBucketPolicy\">Put Table Bucket Policy</option> <option value=\"GetTableBucketPolicy\">Get Table Bucket Policy</option> <option value=\"DeleteTableBucketPolicy\">Delete Table Bucket Policy</option> <option value=\"CreateNamespace\">Create Namespace</option> <option value=\"GetNamespace\">Get Namespace</option> <option value=\"ListNamespaces\">List Namespaces</option> <option value=\"DeleteNamespace\">Delete Namespace</option> <option value=\"CreateTable\">Create Table</option> <option value=\"GetTable\">Get Table</option> <option value=\"ListTables\">List Tables</option> <option value=\"DeleteTable\">Delete Table</option> <option value=\"PutTablePolicy\">Put Table Policy</option> <option value=\"GetTablePolicy\">Get Table Policy</option> <option value=\"DeleteTablePolicy\">Delete Table Policy</option> <option value=\"TagResource\">Tag Resource</option> <option value=\"ListTagsForResource\">List Tags</option> <option value=\"UntagResource\">Untag Resource</option></optgroup></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple permissions</small></div><div class=\"mb-3\"><label class=\"form-label\">Bucket Scope</label> <small class=\"form-text text-muted d-block mb-2\">Apply selected permissions to specific buckets or all buckets</small><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"allBuckets\" value=\"all\" checked onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"allBuckets\">All Buckets</label></div><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"specificBuckets\" value=\"specific\" onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"specificBuckets\">Specific Buckets</label></div><div id=\"bucketSelectionList\" class=\"mt-2\" style=\"display: none;\"><select multiple class=\"form-select\" id=\"selectedBuckets\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple buckets</small></div></div><div class=\"mb-3\"><label for=\"policies\" class=\"form-label\">Attached Policies</label> <select multiple class=\"form-control\" id=\"policies\" name=\"policies\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple policies</small></div><div class=\"mb-3 form-check\"><input type=\"checkbox\" class=\"form-check-input\" id=\"generateKey\" name=\"generateKey\" checked> <label class=\"form-check-label\" for=\"generateKey\">Generate access key automatically</label></div></form></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"button\" class=\"btn btn-primary\" onclick=\"handleCreateUser()\">Create User</button></div></div></div></div><!-- Edit User Modal --><div class=\"modal fade\" id=\"editUseLine truncated
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div><div class=\"mb-3\"><label for=\"email\" class=\"form-label\">Email</label> <input type=\"email\" class=\"form-control\" id=\"email\" name=\"email\"></div><div class=\"mb-3\"><label for=\"actions\" class=\"form-label\">Permissions</label> <select multiple class=\"form-control\" id=\"actions\" name=\"actions\" size=\"10\"><option value=\"Admin\">Admin (Full Access)</option> <option value=\"Read\">Read</option> <option value=\"Write\">Write</option> <option value=\"List\">List</option> <option value=\"Tagging\">Tagging</option> <option value=\"ReadAcp\" title=\"Needed for GET ?acl on buckets and objects\">Read ACL (ReadAcp)</option> <option value=\"WriteAcp\" title=\"Needed for PUT ?acl and for uploads that send x-amz-acl or x-amz-grant-* headers\">Write ACL (WriteAcp)</option> <optgroup label=\"Object Lock Permissions\"><option value=\"BypassGovernanceRetention\">Bypass Governance Retention</option> <option value=\"GetObjectRetention\">Get Object Retention</option> <option value=\"PutObjectRetention\">Put Object Retention</option> <option value=\"GetObjectLegalHold\">Get Object Legal Hold</option> <option value=\"PutObjectLegalHold\">Put Object Legal Hold</option> <option value=\"GetBucketObjectLockConfiguration\">Get Bucket Object Lock Configuration</option> <option value=\"PutBucketObjectLockConfiguration\">Put Bucket Object Lock Configuration</option></optgroup> <optgroup label=\"Bucket Policy Permissions\"><option value=\"PutBucketPolicy\">Put Bucket Policy</option> <option value=\"DeleteBucketPolicy\">Delete Bucket Policy</option></optgroup> <optgroup label=\"Bucket Configuration Permissions\"><option value=\"PutBucketCors\">Put Bucket CORS</option> <option value=\"DeleteBucketCors\">Delete Bucket CORS</option> <option value=\"PutBucketVersioning\">Put Bucket Versioning</option></optgroup> <optgroup label=\"S3 Tables Permissions\"><option value=\"S3TablesAdmin\">S3 Tables Admin (Full Access)</option> <option value=\"CreateTableBucket\">Create Table Bucket</option> <option value=\"GetTableBucket\">Get Table Bucket</option> <option value=\"ListTableBuckets\">List Table Buckets</option> <option value=\"DeleteTableBucket\">Delete Table Bucket</option> <option value=\"PutTableBucketPolicy\">Put Table Bucket Policy</option> <option value=\"GetTableBucketPolicy\">Get Table Bucket Policy</option> <option value=\"DeleteTableBucketPolicy\">Delete Table Bucket Policy</option> <option value=\"CreateNamespace\">Create Namespace</option> <option value=\"GetNamespace\">Get Namespace</option> <option value=\"ListNamespaces\">List Namespaces</option> <option value=\"DeleteNamespace\">Delete Namespace</option> <option value=\"CreateTable\">Create Table</option> <option value=\"GetTable\">Get Table</option> <option value=\"ListTables\">List Tables</option> <option value=\"DeleteTable\">Delete Table</option> <option value=\"PutTablePolicy\">Put Table Policy</option> <option value=\"GetTablePolicy\">Get Table Policy</option> <option value=\"DeleteTablePolicy\">Delete Table Policy</option> <option value=\"TagResource\">Tag Resource</option> <option value=\"ListTagsForResource\">List Tags</option> <option value=\"UntagResource\">Untag Resource</option></optgroup></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple permissions</small></div><div class=\"mb-3\"><label class=\"form-label\">Bucket Scope</label> <small class=\"form-text text-muted d-block mb-2\">Apply selected permissions to specific buckets or all buckets</small><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"allBuckets\" value=\"all\" checked onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"allBuckets\">All Buckets</label></div><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"specificBuckets\" value=\"specific\" onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"specificBuckets\">Specific Buckets</label></div><div id=\"bucketSelectionList\" class=\"mt-2\" style=\"display: none;\"><select multiple class=\"form-select\" id=\"selectedBuckets\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple buckets</small></div></div><div class=\"mb-3\"><label for=\"policies\" class=\"form-label\">Attached Policies</label> <select multiple class=\"form-control\" id=\"policies\" name=\"policies\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple policies</small></div><div class=\"mb-3 form-check\"><input type=\"checkbox\" class=\"form-check-input\" id=\"generateKey\" name=\"generateKey\" checked> <label class=\"form-check-label\" for=\"generateKey\">Generate access key automatically</label></div></form></div><div class=\"modal-footer\"><button type=\"button\" clasLine truncated
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
+9
-3
@@ -135,10 +135,10 @@ var baseS3ActionMap = map[string]string{
|
||||
"ListAllMyBuckets": s3_constants.ACTION_LIST,
|
||||
"GetBucketLocation": s3_constants.ACTION_READ,
|
||||
"GetBucketVersioning": s3_constants.ACTION_READ,
|
||||
"PutBucketVersioning": s3_constants.ACTION_WRITE,
|
||||
"PutBucketVersioning": s3_constants.ACTION_PUT_BUCKET_VERSIONING,
|
||||
"GetBucketCors": s3_constants.ACTION_READ,
|
||||
"PutBucketCors": s3_constants.ACTION_WRITE,
|
||||
"DeleteBucketCors": s3_constants.ACTION_WRITE,
|
||||
"PutBucketCors": s3_constants.ACTION_PUT_BUCKET_CORS,
|
||||
"DeleteBucketCors": s3_constants.ACTION_DELETE_BUCKET_CORS,
|
||||
"GetBucketNotification": s3_constants.ACTION_READ,
|
||||
"PutBucketNotification": s3_constants.ACTION_WRITE,
|
||||
"GetBucketObjectLockConfiguration": s3_constants.ACTION_GET_BUCKET_OBJECT_LOCK_CONFIG,
|
||||
@@ -220,6 +220,12 @@ func MapToIdentitiesAction(action string) string {
|
||||
return "PutBucketPolicy"
|
||||
case s3_constants.ACTION_DELETE_BUCKET_POLICY:
|
||||
return "DeleteBucketPolicy"
|
||||
case s3_constants.ACTION_PUT_BUCKET_CORS:
|
||||
return "PutBucketCors"
|
||||
case s3_constants.ACTION_DELETE_BUCKET_CORS:
|
||||
return "DeleteBucketCors"
|
||||
case s3_constants.ACTION_PUT_BUCKET_VERSIONING:
|
||||
return "PutBucketVersioning"
|
||||
case s3_constants.ACTION_LIST_MULTIPART_UPLOADS:
|
||||
return "ListBucketMultipartUploads"
|
||||
case s3_constants.ACTION_LIST_PARTS:
|
||||
|
||||
@@ -427,6 +427,12 @@ func mapBaseActionToS3Format(baseAction string) string {
|
||||
return s3_constants.S3_ACTION_PUT_BUCKET_POLICY
|
||||
case s3_constants.ACTION_DELETE_BUCKET_POLICY:
|
||||
return s3_constants.S3_ACTION_DELETE_BUCKET_POLICY
|
||||
case s3_constants.ACTION_PUT_BUCKET_CORS:
|
||||
return s3_constants.S3_ACTION_PUT_BUCKET_CORS
|
||||
case s3_constants.ACTION_DELETE_BUCKET_CORS:
|
||||
return s3_constants.S3_ACTION_DELETE_BUCKET_CORS
|
||||
case s3_constants.ACTION_PUT_BUCKET_VERSIONING:
|
||||
return s3_constants.S3_ACTION_PUT_BUCKET_VERSIONING
|
||||
case s3_constants.ACTION_PUT_BUCKET_QUOTA:
|
||||
return s3_constants.S3_ACTION_PUT_BUCKET_QUOTA
|
||||
case s3_constants.ACTION_GET_BUCKET_QUOTA:
|
||||
|
||||
@@ -18,6 +18,9 @@ const (
|
||||
ACTION_PUT_BUCKET_OBJECT_LOCK_CONFIG = "PutBucketObjectLockConfiguration"
|
||||
ACTION_PUT_BUCKET_POLICY = "PutBucketPolicy"
|
||||
ACTION_DELETE_BUCKET_POLICY = "DeleteBucketPolicy"
|
||||
ACTION_PUT_BUCKET_CORS = "PutBucketCors"
|
||||
ACTION_DELETE_BUCKET_CORS = "DeleteBucketCors"
|
||||
ACTION_PUT_BUCKET_VERSIONING = "PutBucketVersioning"
|
||||
ACTION_PUT_BUCKET_QUOTA = "PutBucketQuota"
|
||||
ACTION_GET_BUCKET_QUOTA = "GetBucketQuota"
|
||||
// Scoped to their single operation: the multipart listing routes are
|
||||
|
||||
@@ -1099,9 +1099,9 @@ func (s3a *S3ApiServer) registerRouter(router *mux.Router) {
|
||||
// GetBucketCors
|
||||
bucket.Methods(http.MethodGet).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.GetBucketCorsHandler, ACTION_READ)), "GET")).Queries("cors", "")
|
||||
// PutBucketCors
|
||||
bucket.Methods(http.MethodPut).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.PutBucketCorsHandler, ACTION_WRITE)), "PUT")).Queries("cors", "")
|
||||
bucket.Methods(http.MethodPut).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.PutBucketCorsHandler, ACTION_PUT_BUCKET_CORS)), "PUT")).Queries("cors", "")
|
||||
// DeleteBucketCors
|
||||
bucket.Methods(http.MethodDelete).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.DeleteBucketCorsHandler, ACTION_WRITE)), "DELETE")).Queries("cors", "")
|
||||
bucket.Methods(http.MethodDelete).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.DeleteBucketCorsHandler, ACTION_DELETE_BUCKET_CORS)), "DELETE")).Queries("cors", "")
|
||||
|
||||
// GetBucketLifecycleConfiguration
|
||||
bucket.Methods(http.MethodGet).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.GetBucketLifecycleConfigurationHandler, ACTION_READ)), "GET")).Queries("lifecycle", "")
|
||||
@@ -1134,7 +1134,7 @@ func (s3a *S3ApiServer) registerRouter(router *mux.Router) {
|
||||
|
||||
// GetBucketVersioning
|
||||
bucket.Methods(http.MethodGet).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.GetBucketVersioningHandler, ACTION_READ)), "GET")).Queries("versioning", "")
|
||||
bucket.Methods(http.MethodPut).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.PutBucketVersioningHandler, ACTION_WRITE)), "PUT")).Queries("versioning", "")
|
||||
bucket.Methods(http.MethodPut).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.PutBucketVersioningHandler, ACTION_PUT_BUCKET_VERSIONING)), "PUT")).Queries("versioning", "")
|
||||
|
||||
// GetObjectLockConfiguration / PutObjectLockConfiguration (bucket-level operations)
|
||||
bucket.Methods(http.MethodGet).HandlerFunc(track(s3a.iam.Auth(s3a.cb.Limit(s3a.GetObjectLockConfigurationHandler, ACTION_GET_BUCKET_OBJECT_LOCK_CONFIG)), "GET")).Queries("object-lock", "")
|
||||
|
||||
@@ -588,3 +588,80 @@ func TestRouting_BucketLifecycleWritesNeedAdmin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouting_BucketCorsAndVersioningWritesNeedTheirActions(t *testing.T) {
|
||||
const bucket = "config-bucket"
|
||||
configFile := filepath.Join(t.TempDir(), "s3.json")
|
||||
require.NoError(t, os.WriteFile(configFile, []byte(`{
|
||||
"identities": [
|
||||
{"name":"writer","credentials":[{"accessKey":"WRITERKEY","secretKey":"writersecret"}],"actions":["Read:`+bucket+`","Write:`+bucket+`","List:`+bucket+`","Tagging:`+bucket+`"]},
|
||||
{"name":"bucketadmin","credentials":[{"accessKey":"BUCKETADMINKEY","secretKey":"bucketadminsecret"}],"actions":["Admin:`+bucket+`"]},
|
||||
{"name":"corsputter","credentials":[{"accessKey":"CORSPUTKEY","secretKey":"corsputsecret"}],"actions":["PutBucketCors:`+bucket+`"]},
|
||||
{"name":"corsdeleter","credentials":[{"accessKey":"CORSDELKEY","secretKey":"corsdelsecret"}],"actions":["DeleteBucketCors:`+bucket+`"]},
|
||||
{"name":"versioner","credentials":[{"accessKey":"VERSIONERKEY","secretKey":"versionersecret"}],"actions":["PutBucketVersioning:`+bucket+`"]},
|
||||
{"name":"policyuser","credentials":[{"accessKey":"POLICYUSERKEY","secretKey":"policyusersecret"}],"policyNames":["ConfigPolicy"]}
|
||||
],
|
||||
"policies": [
|
||||
{"name":"ConfigPolicy","content":"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"s3:PutBucketCors\",\"s3:DeleteBucketCors\",\"s3:PutBucketVersioning\"],\"Resource\":[\"arn:aws:s3:::`+bucket+`\"]}]}"}
|
||||
]
|
||||
}`), 0600))
|
||||
|
||||
s3a := setupRoutingTestServer(t)
|
||||
s3a.iam = NewIdentityAccessManagementWithStore(&S3ApiServerOption{Config: configFile}, nil, "memory")
|
||||
require.True(t, s3a.iam.isEnabled())
|
||||
s3a.cb = &CircuitBreaker{s3a: s3a}
|
||||
s3a.bucketConfigCache = NewBucketConfigCache(time.Minute)
|
||||
s3a.bucketConfigCache.SetNegativeCache(bucket)
|
||||
router := mux.NewRouter()
|
||||
s3a.registerRouter(router)
|
||||
|
||||
send := func(accessKey, secretKey, method, query, body string) *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequest(method, "http://localhost:8333/"+bucket+"?"+query, strings.NewReader(body))
|
||||
creds := credentials.NewStaticCredentials(accessKey, secretKey, "")
|
||||
_, err := v4.NewSigner(creds).Sign(req, strings.NewReader(body), "s3", "us-east-1", time.Now())
|
||||
require.NoError(t, err)
|
||||
rr := httptest.NewRecorder()
|
||||
router.ServeHTTP(rr, req)
|
||||
return rr
|
||||
}
|
||||
|
||||
const corsXML = `<CORSConfiguration><CORSRule><AllowedOrigin>*</AllowedOrigin><AllowedMethod>GET</AllowedMethod></CORSRule></CORSConfiguration>`
|
||||
const versioningXML = `<VersioningConfiguration><Status>Suspended</Status></VersioningConfiguration>`
|
||||
singleActionKeys := map[string]string{"CORSPUTKEY": "corsputsecret", "CORSDELKEY": "corsdelsecret", "VERSIONERKEY": "versionersecret"}
|
||||
for _, tc := range []struct {
|
||||
method, query, body, allowedKey string
|
||||
}{
|
||||
{http.MethodPut, "cors", corsXML, "CORSPUTKEY"},
|
||||
{http.MethodDelete, "cors", "", "CORSDELKEY"},
|
||||
{http.MethodPut, "versioning", versioningXML, "VERSIONERKEY"},
|
||||
} {
|
||||
denied := [][2]string{{"WRITERKEY", "writersecret"}}
|
||||
allowed := [][2]string{{"BUCKETADMINKEY", "bucketadminsecret"}, {"POLICYUSERKEY", "policyusersecret"}}
|
||||
for key, secret := range singleActionKeys {
|
||||
if key == tc.allowedKey {
|
||||
allowed = append(allowed, [2]string{key, secret})
|
||||
} else {
|
||||
denied = append(denied, [2]string{key, secret})
|
||||
}
|
||||
}
|
||||
for _, key := range denied {
|
||||
rr := send(key[0], key[1], tc.method, tc.query, tc.body)
|
||||
assert.Equal(t, http.StatusForbidden, rr.Code, "%s %s ?%s", key[0], tc.method, tc.query)
|
||||
assert.Contains(t, rr.Body.String(), "AccessDenied", "%s %s ?%s", key[0], tc.method, tc.query)
|
||||
}
|
||||
for _, key := range allowed {
|
||||
rr := send(key[0], key[1], tc.method, tc.query, tc.body)
|
||||
assert.Equal(t, http.StatusNotFound, rr.Code, "%s %s ?%s", key[0], tc.method, tc.query)
|
||||
assert.Contains(t, rr.Body.String(), "NoSuchBucket", "%s %s ?%s", key[0], tc.method, tc.query)
|
||||
}
|
||||
}
|
||||
|
||||
for policyAction, identityAction := range map[string]string{
|
||||
"s3:PutBucketCors": s3_constants.ACTION_PUT_BUCKET_CORS,
|
||||
"s3:DeleteBucketCors": s3_constants.ACTION_DELETE_BUCKET_CORS,
|
||||
"s3:PutBucketVersioning": s3_constants.ACTION_PUT_BUCKET_VERSIONING,
|
||||
} {
|
||||
assert.Equal(t, identityAction, iamMapToStatementAction(policyAction), policyAction)
|
||||
assert.Equal(t, policyAction, "s3:"+iamMapToIdentitiesAction(identityAction), identityAction)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user