diff options
Diffstat (limited to 'weed/iamapi/iamapi_management_handlers.go')
| -rw-r--r-- | weed/iamapi/iamapi_management_handlers.go | 171 |
1 files changed, 149 insertions, 22 deletions
diff --git a/weed/iamapi/iamapi_management_handlers.go b/weed/iamapi/iamapi_management_handlers.go index 470731064..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,19 +204,69 @@ func (iama *IamApiServer) PutUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values return resp, nil } -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 (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 { + if ident.Name == userName { + s3cfg.Identities = append(s3cfg.Identities[:i], s3cfg.Identities[i+1:]...) + return resp, nil + } } + return resp, fmt.Errorf(iam.ErrCodeNoSuchEntityException) } func GetActions(policy *PolicyDocument) (actions []string) { @@ -178,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/* @@ -188,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])) } } } @@ -277,14 +388,15 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) { userName := values.Get("UserName") response, err = iama.GetUser(s3cfg, userName) if err != nil { - writeIamErrorResponse(w, err, "user", userName) + writeIamErrorResponse(w, err, "user", userName, nil) return } + changed = false case "DeleteUser": userName := values.Get("UserName") response, err = iama.DeleteUser(s3cfg, userName) if err != nil { - writeIamErrorResponse(w, err, "user", userName) + writeIamErrorResponse(w, err, "user", userName, nil) return } case "CreateAccessKey": @@ -305,8 +417,23 @@ 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) + } default: - writeErrorResponse(w, s3err.ErrNotImplemented, r.URL) + errNotImplemented := s3err.GetAPIError(s3err.ErrNotImplemented) + errorResponse := ErrorResponse{} + errorResponse.Error.Code = &errNotImplemented.Code + errorResponse.Error.Message = &errNotImplemented.Description + writeResponse(w, errNotImplemented.HTTPStatusCode, encodeResponse(errorResponse), mimeXML) return } if changed { @@ -314,7 +441,7 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) { err := iama.s3ApiConfig.PutS3ApiConfiguration(s3cfg) s3cfgLock.Unlock() if err != nil { - writeErrorResponse(w, s3err.ErrInternalError, r.URL) + writeIamErrorResponse(w, fmt.Errorf(iam.ErrCodeServiceFailureException), "", "", err) return } } |
