Add policy engine (#6970)
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
|
||||
@@ -39,7 +40,7 @@ const (
|
||||
var (
|
||||
seededRand *rand.Rand = rand.New(
|
||||
rand.NewSource(time.Now().UnixNano()))
|
||||
policyDocuments = map[string]*PolicyDocument{}
|
||||
policyDocuments = map[string]*policy_engine.PolicyDocument{}
|
||||
policyLock = sync.RWMutex{}
|
||||
)
|
||||
|
||||
@@ -93,24 +94,8 @@ const (
|
||||
USER_DOES_NOT_EXIST = "the user with name %s cannot be found."
|
||||
)
|
||||
|
||||
type Statement struct {
|
||||
Effect string `json:"Effect"`
|
||||
Action []string `json:"Action"`
|
||||
Resource []string `json:"Resource"`
|
||||
}
|
||||
|
||||
type Policies struct {
|
||||
Policies map[string]PolicyDocument `json:"policies"`
|
||||
}
|
||||
|
||||
type PolicyDocument struct {
|
||||
Version string `json:"Version"`
|
||||
Statement []*Statement `json:"Statement"`
|
||||
}
|
||||
|
||||
func (p PolicyDocument) String() string {
|
||||
b, _ := json.Marshal(p)
|
||||
return string(b)
|
||||
Policies map[string]policy_engine.PolicyDocument `json:"policies"`
|
||||
}
|
||||
|
||||
func Hash(s *string) string {
|
||||
@@ -193,11 +178,12 @@ func (iama *IamApiServer) UpdateUser(s3cfg *iam_pb.S3ApiConfiguration, values ur
|
||||
return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf(USER_DOES_NOT_EXIST, userName)}
|
||||
}
|
||||
|
||||
func GetPolicyDocument(policy *string) (policyDocument PolicyDocument, err error) {
|
||||
if err = json.Unmarshal([]byte(*policy), &policyDocument); err != nil {
|
||||
return PolicyDocument{}, err
|
||||
func GetPolicyDocument(policy *string) (policy_engine.PolicyDocument, error) {
|
||||
var policyDocument policy_engine.PolicyDocument
|
||||
if err := json.Unmarshal([]byte(*policy), &policyDocument); err != nil {
|
||||
return policy_engine.PolicyDocument{}, err
|
||||
}
|
||||
return policyDocument, err
|
||||
return policyDocument, nil
|
||||
}
|
||||
|
||||
func (iama *IamApiServer) CreatePolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp CreatePolicyResponse, iamError *IamError) {
|
||||
@@ -270,7 +256,7 @@ func (iama *IamApiServer) GetUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values
|
||||
return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: errors.New("no actions found")}
|
||||
}
|
||||
|
||||
policyDocument := PolicyDocument{Version: policyDocumentVersion}
|
||||
policyDocument := policy_engine.PolicyDocument{Version: policyDocumentVersion}
|
||||
statements := make(map[string][]string)
|
||||
for _, action := range ident.Actions {
|
||||
// parse "Read:EXAMPLE-BUCKET"
|
||||
@@ -287,9 +273,9 @@ func (iama *IamApiServer) GetUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values
|
||||
for resource, actions := range statements {
|
||||
isEqAction := false
|
||||
for i, statement := range policyDocument.Statement {
|
||||
if reflect.DeepEqual(statement.Action, actions) {
|
||||
policyDocument.Statement[i].Resource = append(
|
||||
policyDocument.Statement[i].Resource, resource)
|
||||
if reflect.DeepEqual(statement.Action.Strings(), actions) {
|
||||
policyDocument.Statement[i].Resource = policy_engine.NewStringOrStringSlice(append(
|
||||
policyDocument.Statement[i].Resource.Strings(), resource)...)
|
||||
isEqAction = true
|
||||
break
|
||||
}
|
||||
@@ -297,14 +283,18 @@ func (iama *IamApiServer) GetUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values
|
||||
if isEqAction {
|
||||
continue
|
||||
}
|
||||
policyDocumentStatement := Statement{
|
||||
Effect: "Allow",
|
||||
Action: actions,
|
||||
policyDocumentStatement := policy_engine.PolicyStatement{
|
||||
Effect: policy_engine.PolicyEffectAllow,
|
||||
Action: policy_engine.NewStringOrStringSlice(actions...),
|
||||
Resource: policy_engine.NewStringOrStringSlice(resource),
|
||||
}
|
||||
policyDocumentStatement.Resource = append(policyDocumentStatement.Resource, resource)
|
||||
policyDocument.Statement = append(policyDocument.Statement, &policyDocumentStatement)
|
||||
policyDocument.Statement = append(policyDocument.Statement, policyDocumentStatement)
|
||||
}
|
||||
resp.GetUserPolicyResult.PolicyDocument = policyDocument.String()
|
||||
policyDocumentJSON, err := json.Marshal(policyDocument)
|
||||
if err != nil {
|
||||
return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err}
|
||||
}
|
||||
resp.GetUserPolicyResult.PolicyDocument = string(policyDocumentJSON)
|
||||
return resp, nil
|
||||
}
|
||||
return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf(USER_DOES_NOT_EXIST, userName)}
|
||||
@@ -321,21 +311,21 @@ func (iama *IamApiServer) DeleteUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, val
|
||||
return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf(USER_DOES_NOT_EXIST, userName)}
|
||||
}
|
||||
|
||||
func GetActions(policy *PolicyDocument) ([]string, error) {
|
||||
func GetActions(policy *policy_engine.PolicyDocument) ([]string, error) {
|
||||
var actions []string
|
||||
|
||||
for _, statement := range policy.Statement {
|
||||
if statement.Effect != "Allow" {
|
||||
if statement.Effect != policy_engine.PolicyEffectAllow {
|
||||
return nil, fmt.Errorf("not a valid effect: '%s'. Only 'Allow' is possible", statement.Effect)
|
||||
}
|
||||
for _, resource := range statement.Resource {
|
||||
for _, resource := range statement.Resource.Strings() {
|
||||
// Parse "arn:aws:s3:::my-bucket/shared/*"
|
||||
res := strings.Split(resource, ":")
|
||||
if len(res) != 6 || res[0] != "arn" || res[1] != "aws" || res[2] != "s3" {
|
||||
glog.Infof("not a valid resource: %s", res)
|
||||
continue
|
||||
}
|
||||
for _, action := range statement.Action {
|
||||
for _, action := range statement.Action.Strings() {
|
||||
// Parse "s3:Get*"
|
||||
act := strings.Split(action, ":")
|
||||
if len(act) != 2 || act[0] != "s3" {
|
||||
|
||||
@@ -3,28 +3,19 @@ package iamapi
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetActionsUserPath(t *testing.T) {
|
||||
|
||||
policyDocument := PolicyDocument{
|
||||
policyDocument := policy_engine.PolicyDocument{
|
||||
Version: "2012-10-17",
|
||||
Statement: []*Statement{
|
||||
Statement: []policy_engine.PolicyStatement{
|
||||
{
|
||||
Effect: "Allow",
|
||||
Action: []string{
|
||||
"s3:Put*",
|
||||
"s3:PutBucketAcl",
|
||||
"s3:Get*",
|
||||
"s3:GetBucketAcl",
|
||||
"s3:List*",
|
||||
"s3:Tagging*",
|
||||
"s3:DeleteBucket*",
|
||||
},
|
||||
Resource: []string{
|
||||
"arn:aws:s3:::shared/user-Alice/*",
|
||||
},
|
||||
Effect: policy_engine.PolicyEffectAllow,
|
||||
Action: policy_engine.NewStringOrStringSlice("s3:Put*", "s3:PutBucketAcl", "s3:Get*", "s3:GetBucketAcl", "s3:List*", "s3:Tagging*", "s3:DeleteBucket*"),
|
||||
Resource: policy_engine.NewStringOrStringSlice("arn:aws:s3:::shared/user-Alice/*"),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -45,18 +36,13 @@ func TestGetActionsUserPath(t *testing.T) {
|
||||
|
||||
func TestGetActionsWildcardPath(t *testing.T) {
|
||||
|
||||
policyDocument := PolicyDocument{
|
||||
policyDocument := policy_engine.PolicyDocument{
|
||||
Version: "2012-10-17",
|
||||
Statement: []*Statement{
|
||||
Statement: []policy_engine.PolicyStatement{
|
||||
{
|
||||
Effect: "Allow",
|
||||
Action: []string{
|
||||
"s3:Get*",
|
||||
"s3:PutBucketAcl",
|
||||
},
|
||||
Resource: []string{
|
||||
"arn:aws:s3:::*",
|
||||
},
|
||||
Effect: policy_engine.PolicyEffectAllow,
|
||||
Action: policy_engine.NewStringOrStringSlice("s3:Get*", "s3:PutBucketAcl"),
|
||||
Resource: policy_engine.NewStringOrStringSlice("arn:aws:s3:::*"),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -71,17 +57,13 @@ func TestGetActionsWildcardPath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetActionsInvalidAction(t *testing.T) {
|
||||
policyDocument := PolicyDocument{
|
||||
policyDocument := policy_engine.PolicyDocument{
|
||||
Version: "2012-10-17",
|
||||
Statement: []*Statement{
|
||||
Statement: []policy_engine.PolicyStatement{
|
||||
{
|
||||
Effect: "Allow",
|
||||
Action: []string{
|
||||
"s3:InvalidAction",
|
||||
},
|
||||
Resource: []string{
|
||||
"arn:aws:s3:::shared/user-Alice/*",
|
||||
},
|
||||
Effect: policy_engine.PolicyEffectAllow,
|
||||
Action: policy_engine.NewStringOrStringSlice("s3:InvalidAction"),
|
||||
Resource: policy_engine.NewStringOrStringSlice("arn:aws:s3:::shared/user-Alice/*"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
|
||||
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
@@ -160,7 +161,7 @@ func (iama *IamS3ApiConfigure) GetPolicies(policies *Policies) (err error) {
|
||||
return err
|
||||
}
|
||||
if err == filer_pb.ErrNotFound || buf.Len() == 0 {
|
||||
policies.Policies = make(map[string]PolicyDocument)
|
||||
policies.Policies = make(map[string]policy_engine.PolicyDocument)
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal(buf.Bytes(), policies); err != nil {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -23,7 +24,7 @@ var GetPolicies func(policies *Policies) (err error)
|
||||
var PutPolicies func(policies *Policies) (err error)
|
||||
|
||||
var s3config = iam_pb.S3ApiConfiguration{}
|
||||
var policiesFile = Policies{Policies: make(map[string]PolicyDocument)}
|
||||
var policiesFile = Policies{Policies: make(map[string]policy_engine.PolicyDocument)}
|
||||
var ias = IamApiServer{s3ApiConfig: iamS3ApiConfigureMock{}}
|
||||
|
||||
type iamS3ApiConfigureMock struct{}
|
||||
|
||||
Reference in New Issue
Block a user