mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
wildcard prefix to restrict access to directories in s3 bucket
https://github.com/chrislusf/seaweedfs/discussions/2551
This commit is contained in:
parent
5799a20f71
commit
a7887166cf
|
@ -247,9 +247,9 @@ func (iam *IdentityAccessManagement) authRequest(r *http.Request, action Action)
|
||||||
|
|
||||||
glog.V(3).Infof("user name: %v actions: %v, action: %v", identity.Name, identity.Actions, action)
|
glog.V(3).Infof("user name: %v actions: %v, action: %v", identity.Name, identity.Actions, action)
|
||||||
|
|
||||||
bucket, _ := xhttp.GetBucketAndObject(r)
|
bucket, object := xhttp.GetBucketAndObject(r)
|
||||||
|
|
||||||
if !identity.canDo(action, bucket) {
|
if !identity.canDo(action, bucket, object) {
|
||||||
return identity, s3err.ErrAccessDenied
|
return identity, s3err.ErrAccessDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ func (iam *IdentityAccessManagement) authUser(r *http.Request) (*Identity, s3err
|
||||||
return identity, s3err.ErrNone
|
return identity, s3err.ErrNone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (identity *Identity) canDo(action Action, bucket string) bool {
|
func (identity *Identity) canDo(action Action, bucket string, objectKey string) bool {
|
||||||
if identity.isAdmin() {
|
if identity.isAdmin() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -319,15 +319,13 @@ func (identity *Identity) canDo(action Action, bucket string) bool {
|
||||||
if bucket == "" {
|
if bucket == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
target := string(action) + ":" + bucket + "/" + objectKey
|
||||||
limitedByBucket := string(action) + ":" + bucket
|
limitedByBucket := string(action) + ":" + bucket
|
||||||
adminLimitedByBucket := s3_constants.ACTION_ADMIN + ":" + bucket
|
adminLimitedByBucket := s3_constants.ACTION_ADMIN + ":" + bucket
|
||||||
for _, a := range identity.Actions {
|
for _, a := range identity.Actions {
|
||||||
act := string(a)
|
act := string(a)
|
||||||
if strings.HasSuffix(act, "*") {
|
if strings.HasSuffix(act, "*") {
|
||||||
if strings.HasPrefix(limitedByBucket, act[:len(act)-1]) {
|
if strings.HasPrefix(target, act[:len(act)-1]) {
|
||||||
return true
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(adminLimitedByBucket, act[:len(act)-1]) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package s3api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
|
. "github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/protobuf/jsonpb"
|
"github.com/golang/protobuf/jsonpb"
|
||||||
|
@ -67,3 +68,51 @@ func TestIdentityListFileFormat(t *testing.T) {
|
||||||
println(text)
|
println(text)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCanDo(t *testing.T) {
|
||||||
|
ident1 := &Identity{
|
||||||
|
Name: "anything",
|
||||||
|
Actions: []Action{
|
||||||
|
"Write:bucket1/a/b/c/*",
|
||||||
|
"Write:bucket1/a/b/other",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// object specific
|
||||||
|
assert.Equal(t, true, ident1.canDo(ACTION_WRITE, "bucket1", "a/b/c/d.txt"))
|
||||||
|
assert.Equal(t, false, ident1.canDo(ACTION_WRITE, "bucket1", "a/b/other/some"), "action without *")
|
||||||
|
|
||||||
|
// bucket specific
|
||||||
|
ident2 := &Identity{
|
||||||
|
Name: "anything",
|
||||||
|
Actions: []Action{
|
||||||
|
"Read:bucket1",
|
||||||
|
"Write:bucket1/*",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, true, ident2.canDo(ACTION_READ, "bucket1", "a/b/c/d.txt"))
|
||||||
|
assert.Equal(t, true, ident2.canDo(ACTION_WRITE, "bucket1", "a/b/c/d.txt"))
|
||||||
|
assert.Equal(t, false, ident2.canDo(ACTION_LIST, "bucket1", "a/b/c/d.txt"))
|
||||||
|
|
||||||
|
// across buckets
|
||||||
|
ident3 := &Identity{
|
||||||
|
Name: "anything",
|
||||||
|
Actions: []Action{
|
||||||
|
"Read",
|
||||||
|
"Write",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, true, ident3.canDo(ACTION_READ, "bucket1", "a/b/c/d.txt"))
|
||||||
|
assert.Equal(t, true, ident3.canDo(ACTION_WRITE, "bucket1", "a/b/c/d.txt"))
|
||||||
|
assert.Equal(t, false, ident3.canDo(ACTION_LIST, "bucket1", "a/b/other/some"))
|
||||||
|
|
||||||
|
// partial buckets
|
||||||
|
ident4 := &Identity{
|
||||||
|
Name: "anything",
|
||||||
|
Actions: []Action{
|
||||||
|
"Read:special_*",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, true, ident4.canDo(ACTION_READ, "special_bucket", "a/b/c/d.txt"))
|
||||||
|
assert.Equal(t, false, ident4.canDo(ACTION_READ, "bucket1", "a/b/c/d.txt"))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
xhttp "github.com/chrislusf/seaweedfs/weed/s3api/http"
|
xhttp "github.com/chrislusf/seaweedfs/weed/s3api/http"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
|
||||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
|
@ -91,8 +92,8 @@ func (iam *IdentityAccessManagement) calculateSeedSignature(r *http.Request) (cr
|
||||||
return nil, "", "", time.Time{}, s3err.ErrInvalidAccessKeyID
|
return nil, "", "", time.Time{}, s3err.ErrInvalidAccessKeyID
|
||||||
}
|
}
|
||||||
|
|
||||||
bucket, _ := xhttp.GetBucketAndObject(r)
|
bucket, object := xhttp.GetBucketAndObject(r)
|
||||||
if !identity.canDo("Write", bucket) {
|
if !identity.canDo(s3_constants.ACTION_WRITE, bucket, object) {
|
||||||
errCode = s3err.ErrAccessDenied
|
errCode = s3err.ErrAccessDenied
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
|
||||||
var buckets []*s3.Bucket
|
var buckets []*s3.Bucket
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if entry.IsDirectory {
|
if entry.IsDirectory {
|
||||||
if identity != nil && !identity.canDo(s3_constants.ACTION_LIST, entry.Name) {
|
if identity != nil && !identity.canDo(s3_constants.ACTION_LIST, entry.Name, "") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buckets = append(buckets, &s3.Bucket{
|
buckets = append(buckets, &s3.Bucket{
|
||||||
|
|
Loading…
Reference in a new issue