aboutsummaryrefslogtreecommitdiff
path: root/weed/iamapi/iamapi_management_handlers.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/iamapi/iamapi_management_handlers.go')
-rw-r--r--weed/iamapi/iamapi_management_handlers.go150
1 files changed, 129 insertions, 21 deletions
diff --git a/weed/iamapi/iamapi_management_handlers.go b/weed/iamapi/iamapi_management_handlers.go
index 4ca3525ec..b00ada234 100644
--- a/weed/iamapi/iamapi_management_handlers.go
+++ b/weed/iamapi/iamapi_management_handlers.go
@@ -11,6 +11,7 @@ import (
"math/rand"
"net/http"
"net/url"
+ "reflect"
"strings"
"sync"
"time"
@@ -19,27 +20,77 @@ import (
)
const (
- charsetUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
- charset = charsetUpper + "abcdefghijklmnopqrstuvwxyz/"
+ charsetUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+ charset = charsetUpper + "abcdefghijklmnopqrstuvwxyz/"
+ policyDocumentVersion = "2012-10-17"
+ StatementActionAdmin = "*"
+ StatementActionWrite = "Put*"
+ StatementActionRead = "Get*"
+ StatementActionList = "List*"
+ StatementActionTagging = "Tagging*"
)
var (
seededRand *rand.Rand = rand.New(
rand.NewSource(time.Now().UnixNano()))
policyDocuments = map[string]*PolicyDocument{}
+ policyLock = sync.RWMutex{}
)
+func MapToStatementAction(action string) string {
+ switch action {
+ case StatementActionAdmin:
+ return s3_constants.ACTION_ADMIN
+ case StatementActionWrite:
+ return s3_constants.ACTION_WRITE
+ case StatementActionRead:
+ return s3_constants.ACTION_READ
+ case StatementActionList:
+ return s3_constants.ACTION_LIST
+ case StatementActionTagging:
+ return s3_constants.ACTION_TAGGING
+ default:
+ return ""
+ }
+}
+
+func MapToIdentitiesAction(action string) string {
+ switch action {
+ case s3_constants.ACTION_ADMIN:
+ return StatementActionAdmin
+ case s3_constants.ACTION_WRITE:
+ return StatementActionWrite
+ case s3_constants.ACTION_READ:
+ return StatementActionRead
+ case s3_constants.ACTION_LIST:
+ return StatementActionList
+ case s3_constants.ACTION_TAGGING:
+ return StatementActionTagging
+ default:
+ return ""
+ }
+}
+
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)
+}
+
func Hash(s *string) string {
h := sha1.New()
h.Write([]byte(*s))
@@ -83,7 +134,7 @@ func (iama *IamApiServer) CreateUser(s3cfg *iam_pb.S3ApiConfiguration, values ur
func (iama *IamApiServer) DeleteUser(s3cfg *iam_pb.S3ApiConfiguration, userName string) (resp DeleteUserResponse, err error) {
for i, ident := range s3cfg.Identities {
if userName == ident.Name {
- ident.Credentials = append(ident.Credentials[:i], ident.Credentials[i+1:]...)
+ s3cfg.Identities = append(s3cfg.Identities[:i], s3cfg.Identities[i+1:]...)
return resp, nil
}
}
@@ -119,7 +170,16 @@ func (iama *IamApiServer) CreatePolicy(s3cfg *iam_pb.S3ApiConfiguration, values
resp.CreatePolicyResult.Policy.PolicyName = &policyName
resp.CreatePolicyResult.Policy.Arn = &arn
resp.CreatePolicyResult.Policy.PolicyId = &policyId
- policyDocuments[policyName] = &policyDocument
+ policies := Policies{}
+ policyLock.Lock()
+ defer policyLock.Unlock()
+ if err = iama.s3ApiConfig.GetPolicies(&policies); err != nil {
+ return resp, err
+ }
+ policies.Policies[policyName] = policyDocument
+ if err = iama.s3ApiConfig.PutPolicies(&policies); err != nil {
+ return resp, err
+ }
return resp, nil
}
@@ -144,6 +204,60 @@ func (iama *IamApiServer) PutUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values
return resp, nil
}
+func (iama *IamApiServer) GetUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp GetUserPolicyResponse, err error) {
+ userName := values.Get("UserName")
+ policyName := values.Get("PolicyName")
+ for _, ident := range s3cfg.Identities {
+ if userName != ident.Name {
+ continue
+ }
+
+ resp.GetUserPolicyResult.UserName = userName
+ resp.GetUserPolicyResult.PolicyName = policyName
+ if len(ident.Actions) == 0 {
+ return resp, fmt.Errorf(iam.ErrCodeNoSuchEntityException)
+ }
+
+ policyDocument := PolicyDocument{Version: policyDocumentVersion}
+ statements := make(map[string][]string)
+ for _, action := range ident.Actions {
+ // parse "Read:EXAMPLE-BUCKET"
+ act := strings.Split(action, ":")
+
+ resource := "*"
+ if len(act) == 2 {
+ resource = fmt.Sprintf("arn:aws:s3:::%s/*", act[1])
+ }
+ statements[resource] = append(statements[resource],
+ fmt.Sprintf("s3:%s", MapToIdentitiesAction(act[0])),
+ )
+ }
+ 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)
+ isEqAction = true
+ break
+ }
+ }
+ if isEqAction {
+ continue
+ }
+ policyDocumentStatement := Statement{
+ Effect: "Allow",
+ Action: actions,
+ }
+ policyDocumentStatement.Resource = append(policyDocumentStatement.Resource, resource)
+ policyDocument.Statement = append(policyDocument.Statement, &policyDocumentStatement)
+ }
+ resp.GetUserPolicyResult.PolicyDocument = policyDocument.String()
+ return resp, nil
+ }
+ return resp, fmt.Errorf(iam.ErrCodeNoSuchEntityException)
+}
+
func (iama *IamApiServer) DeleteUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp PutUserPolicyResponse, err error) {
userName := values.Get("UserName")
for i, ident := range s3cfg.Identities {
@@ -155,21 +269,6 @@ func (iama *IamApiServer) DeleteUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, val
return resp, fmt.Errorf(iam.ErrCodeNoSuchEntityException)
}
-func MapAction(action string) string {
- switch action {
- case "*":
- return s3_constants.ACTION_ADMIN
- case "Put*":
- return s3_constants.ACTION_WRITE
- case "Get*":
- return s3_constants.ACTION_READ
- case "List*":
- return s3_constants.ACTION_LIST
- default:
- return s3_constants.ACTION_TAGGING
- }
-}
-
func GetActions(policy *PolicyDocument) (actions []string) {
for _, statement := range policy.Statement {
if statement.Effect != "Allow" {
@@ -189,8 +288,9 @@ func GetActions(policy *PolicyDocument) (actions []string) {
glog.Infof("not match action: %s", act)
continue
}
+ statementAction := MapToStatementAction(act[1])
if res[5] == "*" {
- actions = append(actions, MapAction(act[1]))
+ actions = append(actions, statementAction)
continue
}
// Parse my-bucket/shared/*
@@ -199,7 +299,7 @@ func GetActions(policy *PolicyDocument) (actions []string) {
glog.Infof("not match bucket: %s", path)
continue
}
- actions = append(actions, fmt.Sprintf("%s:%s", MapAction(act[1]), path[0]))
+ actions = append(actions, fmt.Sprintf("%s:%s", statementAction, path[0]))
}
}
}
@@ -291,6 +391,7 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
writeIamErrorResponse(w, err, "user", userName, nil)
return
}
+ changed = false
case "DeleteUser":
userName := values.Get("UserName")
response, err = iama.DeleteUser(s3cfg, userName)
@@ -316,6 +417,13 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
writeErrorResponse(w, s3err.ErrInvalidRequest, r.URL)
return
}
+ case "GetUserPolicy":
+ response, err = iama.GetUserPolicy(s3cfg, values)
+ if err != nil {
+ writeIamErrorResponse(w, err, "user", values.Get("UserName"), nil)
+ return
+ }
+ changed = false
case "DeleteUserPolicy":
if response, err = iama.DeleteUserPolicy(s3cfg, values); err != nil {
writeIamErrorResponse(w, err, "user", values.Get("UserName"), nil)