Browse Source

add acl validation for s3 bucket read api

pull/3846/head
changlin.shi 2 years ago
parent
commit
e76f66a0d0
  1. 38
      weed/s3api/s3api_acp.go
  2. 41
      weed/s3api/s3api_bucket_handlers.go
  3. 12
      weed/s3api/s3api_objects_list_handlers.go

38
weed/s3api/s3api_acp.go

@ -1,8 +1,10 @@
package s3api package s3api
import ( import (
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants" "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account" "github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3acl"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err" "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
"net/http" "net/http"
) )
@ -27,3 +29,39 @@ func (s3a *S3ApiServer) checkAccessByOwnership(r *http.Request, bucket string) s
} }
return s3err.ErrAccessDenied return s3err.ErrAccessDenied
} }
// Check Bucket/BucketAcl Read related access
// includes:
// - HeadBucketHandler
// - GetBucketAclHandler
// - ListObjectsV1Handler
// - ListObjectsV2Handler
func (s3a *S3ApiServer) checkAccessForReadBucket(r *http.Request, bucket, aclAction string) (*BucketMetaData, s3err.ErrorCode) {
bucketMetadata, errCode := s3a.bucketRegistry.GetBucketMetadata(bucket)
if errCode != s3err.ErrNone {
return nil, errCode
}
if bucketMetadata.ObjectOwnership == s3_constants.OwnershipBucketOwnerEnforced {
return bucketMetadata, s3err.ErrNone
}
accountId := s3acl.GetAccountId(r)
if accountId == s3account.AccountAdmin.Id || accountId == *bucketMetadata.Owner.ID {
return bucketMetadata, s3err.ErrNone
}
if len(bucketMetadata.Acl) > 0 {
reqGrants := s3acl.DetermineReqGrants(accountId, aclAction)
for _, bucketGrant := range bucketMetadata.Acl {
for _, reqGrant := range reqGrants {
if s3acl.GrantEquals(bucketGrant, reqGrant) {
return bucketMetadata, s3err.ErrNone
}
}
}
}
glog.V(3).Infof("acl denied! request account id: %s", accountId)
return nil, s3err.ErrAccessDenied
}

41
weed/s3api/s3api_bucket_handlers.go

@ -200,6 +200,11 @@ func (s3a *S3ApiServer) HeadBucketHandler(w http.ResponseWriter, r *http.Request
bucket, _ := s3_constants.GetBucketAndObject(r) bucket, _ := s3_constants.GetBucketAndObject(r)
glog.V(3).Infof("HeadBucketHandler %s", bucket) glog.V(3).Infof("HeadBucketHandler %s", bucket)
_, errorCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionRead)
if errorCode != s3err.ErrNone {
s3err.WriteErrorResponse(w, r, errorCode)
return
}
if entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket); entry == nil || err == filer_pb.ErrNotFound { if entry, err := s3a.getEntry(s3a.option.BucketsPath, bucket); entry == nil || err == filer_pb.ErrNotFound {
s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket) s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchBucket)
return return
@ -245,37 +250,19 @@ func (s3a *S3ApiServer) GetBucketAclHandler(w http.ResponseWriter, r *http.Reque
bucket, _ := s3_constants.GetBucketAndObject(r) bucket, _ := s3_constants.GetBucketAndObject(r)
glog.V(3).Infof("GetBucketAclHandler %s", bucket) glog.V(3).Infof("GetBucketAclHandler %s", bucket)
if err := s3a.checkBucket(r, bucket); err != s3err.ErrNone {
s3err.WriteErrorResponse(w, r, err)
bucketMetadata, errorCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionReadAcp)
if s3err.ErrNone != errorCode {
s3err.WriteErrorResponse(w, r, errorCode)
return return
} }
response := AccessControlPolicy{}
for _, ident := range s3a.iam.identities {
if len(ident.Credentials) == 0 {
continue
}
for _, action := range ident.Actions {
if !action.overBucket(bucket) || action.getPermission() == "" {
continue
}
id := ident.Credentials[0].AccessKey
if response.Owner.DisplayName == "" && action.isOwner(bucket) && len(ident.Credentials) > 0 {
response.Owner.DisplayName = ident.Name
response.Owner.ID = id
}
response.AccessControlList.Grant = append(response.AccessControlList.Grant, Grant{
Grantee: Grantee{
ID: id,
DisplayName: ident.Name,
Type: "CanonicalUser",
XMLXSI: "CanonicalUser",
XMLNS: "http://www.w3.org/2001/XMLSchema-instance"},
Permission: action.getPermission(),
})
}
acp := &s3.PutBucketAclInput{
AccessControlPolicy: &s3.AccessControlPolicy{
Grants: bucketMetadata.Acl,
Owner: bucketMetadata.Owner,
},
} }
writeSuccessResponseXML(w, r, response)
s3err.WriteAwsXMLResponse(w, r, http.StatusOK, acp)
} }
// GetBucketLifecycleConfigurationHandler Get Bucket Lifecycle configuration // GetBucketLifecycleConfigurationHandler Get Bucket Lifecycle configuration

12
weed/s3api/s3api_objects_list_handlers.go

@ -41,6 +41,12 @@ func (s3a *S3ApiServer) ListObjectsV2Handler(w http.ResponseWriter, r *http.Requ
bucket, _ := s3_constants.GetBucketAndObject(r) bucket, _ := s3_constants.GetBucketAndObject(r)
glog.V(3).Infof("ListObjectsV2Handler %s", bucket) glog.V(3).Infof("ListObjectsV2Handler %s", bucket)
_, errCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionRead)
if errCode != s3err.ErrNone {
s3err.WriteErrorResponse(w, r, errCode)
return
}
originalPrefix, continuationToken, startAfter, delimiter, _, maxKeys := getListObjectsV2Args(r.URL.Query()) originalPrefix, continuationToken, startAfter, delimiter, _, maxKeys := getListObjectsV2Args(r.URL.Query())
if maxKeys < 0 { if maxKeys < 0 {
@ -97,6 +103,12 @@ func (s3a *S3ApiServer) ListObjectsV1Handler(w http.ResponseWriter, r *http.Requ
bucket, _ := s3_constants.GetBucketAndObject(r) bucket, _ := s3_constants.GetBucketAndObject(r)
glog.V(3).Infof("ListObjectsV1Handler %s", bucket) glog.V(3).Infof("ListObjectsV1Handler %s", bucket)
_, errCode := s3a.checkAccessForReadBucket(r, bucket, s3_constants.PermissionRead)
if errCode != s3err.ErrNone {
s3err.WriteErrorResponse(w, r, errCode)
return
}
originalPrefix, marker, delimiter, maxKeys := getListObjectsV1Args(r.URL.Query()) originalPrefix, marker, delimiter, maxKeys := getListObjectsV1Args(r.URL.Query())
if maxKeys < 0 { if maxKeys < 0 {

Loading…
Cancel
Save