From 8a95f9c10c3d4c9e1f6761f5620da3e5253398f5 Mon Sep 17 00:00:00 2001 From: Konstantin Lebedev Date: Mon, 29 Mar 2021 12:01:44 +0500 Subject: [PATCH] iam GetUser --- weed/command/filer.go | 25 ++++- weed/iamapi/iamapi_handlers.go | 18 ++++ weed/iamapi/iamapi_management_handlers.go | 119 +++++++--------------- weed/iamapi/iamapi_response.go | 93 +++++++++++++++++ 4 files changed, 167 insertions(+), 88 deletions(-) create mode 100644 weed/iamapi/iamapi_response.go diff --git a/weed/command/filer.go b/weed/command/filer.go index 534bd9e04..b256e385f 100644 --- a/weed/command/filer.go +++ b/weed/command/filer.go @@ -25,6 +25,8 @@ var ( filerS3Options S3Options filerStartWebDav *bool filerWebDavOptions WebDavOption + filerStartIam *bool + filerIamOptions IamOptions ) type FilerOptions struct { @@ -89,6 +91,10 @@ func init() { filerWebDavOptions.tlsCertificate = cmdFiler.Flag.String("webdav.cert.file", "", "path to the TLS certificate file") filerWebDavOptions.cacheDir = cmdFiler.Flag.String("webdav.cacheDir", os.TempDir(), "local cache directory for file chunks") filerWebDavOptions.cacheSizeMB = cmdFiler.Flag.Int64("webdav.cacheCapacityMB", 1000, "local cache capacity in MB") + + // start iam on filer + filerStartIam = cmdFiler.Flag.Bool("iam", false, "whether to start IAM service") + filerIamOptions.port = cmdFiler.Flag.Int("iam.port", 8111, "iam server http listen port") } var cmdFiler = &Command{ @@ -119,22 +125,33 @@ func runFiler(cmd *Command, args []string) bool { go stats_collect.StartMetricsServer(*f.metricsHttpPort) + filerAddress := fmt.Sprintf("%s:%d", *f.ip, *f.port) + startDelay := time.Duration(2) if *filerStartS3 { - filerAddress := fmt.Sprintf("%s:%d", *f.ip, *f.port) filerS3Options.filer = &filerAddress go func() { - time.Sleep(2 * time.Second) + time.Sleep(startDelay * time.Second) filerS3Options.startS3Server() }() + startDelay++ } if *filerStartWebDav { - filerAddress := fmt.Sprintf("%s:%d", *f.ip, *f.port) filerWebDavOptions.filer = &filerAddress go func() { - time.Sleep(2 * time.Second) + time.Sleep(startDelay * time.Second) filerWebDavOptions.startWebDav() }() + startDelay++ + } + + if *filerStartIam { + filerIamOptions.filer = &filerAddress + filerIamOptions.masters = f.masters + go func() { + time.Sleep(startDelay * time.Second) + filerIamOptions.startIamServer() + }() } f.startFiler() diff --git a/weed/iamapi/iamapi_handlers.go b/weed/iamapi/iamapi_handlers.go index c436ba998..962717ad9 100644 --- a/weed/iamapi/iamapi_handlers.go +++ b/weed/iamapi/iamapi_handlers.go @@ -12,6 +12,8 @@ import ( "github.com/chrislusf/seaweedfs/weed/glog" "github.com/chrislusf/seaweedfs/weed/s3api/s3err" + + "github.com/aws/aws-sdk-go/service/iam" ) type mimeType string @@ -48,6 +50,22 @@ func writeErrorResponse(w http.ResponseWriter, errorCode s3err.ErrorCode, reqURL writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeXML) } +func writeIamErrorResponse(w http.ResponseWriter, err error, object string, value string) { + errCode := err.Error() + errorResp := ErrorResponse{} + errorResp.Error.Type = "Sender" + errorResp.Error.Code = &errCode + switch errCode { + case iam.ErrCodeNoSuchEntityException: + msg := fmt.Sprintf("The %s with name %s cannot be found.", object, value) + errorResp.Error.Message = &msg + writeResponse(w, http.StatusNotFound, encodeResponse(errorResp), mimeXML) + default: + writeResponse(w, http.StatusInternalServerError, encodeResponse(errorResp), mimeXML) + + } +} + func getRESTErrorResponse(err s3err.APIError, resource string) s3err.RESTErrorResponse { return s3err.RESTErrorResponse{ Code: err.Code, diff --git a/weed/iamapi/iamapi_management_handlers.go b/weed/iamapi/iamapi_management_handlers.go index 322c16d73..e4daa081f 100644 --- a/weed/iamapi/iamapi_management_handlers.go +++ b/weed/iamapi/iamapi_management_handlers.go @@ -4,7 +4,6 @@ import ( "bytes" "crypto/sha1" "encoding/json" - "encoding/xml" "fmt" "github.com/chrislusf/seaweedfs/weed/filer" "github.com/chrislusf/seaweedfs/weed/glog" @@ -19,12 +18,10 @@ import ( "strings" "time" - // "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/iam" ) const ( - version = "2010-05-08" charsetUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" charset = charsetUpper + "abcdefghijklmnopqrstuvwxyz/" ) @@ -44,73 +41,6 @@ type PolicyDocument struct { } `json:"Statement"` } -type CommonResponse struct { - ResponseMetadata struct { - RequestId string `xml:"RequestId"` - } `xml:"ResponseMetadata"` -} - -type ListUsersResponse struct { - CommonResponse - XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ ListUsersResponse"` - ListUsersResult struct { - Users []*iam.User `xml:"Users>member"` - IsTruncated bool `xml:"IsTruncated"` - } `xml:"ListUsersResult"` -} - -type ListAccessKeysResponse struct { - CommonResponse - XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ ListAccessKeysResponse"` - ListAccessKeysResult struct { - AccessKeyMetadata []*iam.AccessKeyMetadata `xml:"AccessKeyMetadata>member"` - IsTruncated bool `xml:"IsTruncated"` - } `xml:"ListAccessKeysResult"` -} - -type DeleteUserResponse struct { - CommonResponse - XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ DeleteUserResponse"` -} - -type DeleteAccessKeyResponse struct { - CommonResponse - XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ DeleteAccessKeyResponse"` -} - -type CreatePolicyResponse struct { - CommonResponse - XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ CreatePolicyResponse"` - CreatePolicyResult struct { - Policy iam.Policy `xml:"Policy"` - } `xml:"CreatePolicyResult"` -} - -type CreateUserResponse struct { - CommonResponse - XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ CreateUserResponse"` - CreateUserResult struct { - User iam.User `xml:"User"` - } `xml:"CreateUserResult"` -} - -type CreateAccessKeyResponse struct { - CommonResponse - XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ CreateAccessKeyResponse"` - CreateAccessKeyResult struct { - AccessKey iam.AccessKey `xml:"AccessKey"` - } `xml:"CreateAccessKeyResult"` -} - -type PutUserPolicyResponse struct { - CommonResponse - XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ PutUserPolicyResponse"` -} - -func (r *CommonResponse) SetRequestId() { - r.ResponseMetadata.RequestId = fmt.Sprintf("%d", time.Now().UnixNano()) -} - func Hash(s *string) string { h := sha1.New() h.Write([]byte(*s)) @@ -150,6 +80,27 @@ func (iama *IamApiServer) CreateUser(s3cfg *iam_pb.S3ApiConfiguration, values ur s3cfg.Identities = append(s3cfg.Identities, &iam_pb.Identity{Name: userName}) return resp } + +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:]...) + return resp, nil + } + } + return resp, fmt.Errorf(iam.ErrCodeNoSuchEntityException) +} + +func (iama *IamApiServer) GetUser(s3cfg *iam_pb.S3ApiConfiguration, userName string) (resp GetUserResponse, err error) { + for _, ident := range s3cfg.Identities { + if userName == ident.Name { + resp.GetUserResult.User = iam.User{UserName: &ident.Name} + return resp, nil + } + } + return resp, fmt.Errorf(iam.ErrCodeNoSuchEntityException) +} + func GetPolicyDocument(policy *string) (policyDocument PolicyDocument, err error) { if err = json.Unmarshal([]byte(*policy), &policyDocument); err != nil { return PolicyDocument{}, err @@ -245,17 +196,6 @@ func GetActions(policy *PolicyDocument) (actions []string) { return actions } -func (iama *IamApiServer) DeleteUser(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp DeleteUserResponse) { - userName := values.Get("UserName") - for i, ident := range s3cfg.Identities { - if userName == ident.Name { - ident.Credentials = append(ident.Credentials[:i], ident.Credentials[i+1:]...) - break - } - } - return resp -} - func (iama *IamApiServer) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp CreateAccessKeyResponse) { userName := values.Get("UserName") status := iam.StatusTypeActive @@ -320,6 +260,7 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) { glog.Info("values ", values) var response interface{} + var err error changed := true switch r.Form.Get("Action") { case "ListUsers": @@ -330,21 +271,31 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) { changed = false case "CreateUser": response = iama.CreateUser(s3cfg, values) + case "GetUser": + userName := values.Get("UserName") + response, err = iama.GetUser(s3cfg, userName) + if err != nil { + writeIamErrorResponse(w, err, "user", userName) + return + } case "DeleteUser": - response = iama.DeleteUser(s3cfg, values) + userName := values.Get("UserName") + response, err = iama.DeleteUser(s3cfg, userName) + if err != nil { + writeIamErrorResponse(w, err, "user", userName) + return + } case "CreateAccessKey": response = iama.CreateAccessKey(s3cfg, values) case "DeleteAccessKey": response = iama.DeleteAccessKey(s3cfg, values) case "CreatePolicy": - var err error response, err = iama.CreatePolicy(s3cfg, values) if err != nil { writeErrorResponse(w, s3err.ErrInvalidRequest, r.URL) return } case "PutUserPolicy": - var err error response, err = iama.PutUserPolicy(s3cfg, values) if err != nil { writeErrorResponse(w, s3err.ErrInvalidRequest, r.URL) diff --git a/weed/iamapi/iamapi_response.go b/weed/iamapi/iamapi_response.go new file mode 100644 index 000000000..26dd0f263 --- /dev/null +++ b/weed/iamapi/iamapi_response.go @@ -0,0 +1,93 @@ +package iamapi + +import ( + "encoding/xml" + "fmt" + "time" + + "github.com/aws/aws-sdk-go/service/iam" +) + +type CommonResponse struct { + ResponseMetadata struct { + RequestId string `xml:"RequestId"` + } `xml:"ResponseMetadata"` +} + +type ListUsersResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ ListUsersResponse"` + ListUsersResult struct { + Users []*iam.User `xml:"Users>member"` + IsTruncated bool `xml:"IsTruncated"` + } `xml:"ListUsersResult"` +} + +type ListAccessKeysResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ ListAccessKeysResponse"` + ListAccessKeysResult struct { + AccessKeyMetadata []*iam.AccessKeyMetadata `xml:"AccessKeyMetadata>member"` + IsTruncated bool `xml:"IsTruncated"` + } `xml:"ListAccessKeysResult"` +} + +type DeleteAccessKeyResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ DeleteAccessKeyResponse"` +} + +type CreatePolicyResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ CreatePolicyResponse"` + CreatePolicyResult struct { + Policy iam.Policy `xml:"Policy"` + } `xml:"CreatePolicyResult"` +} + +type CreateUserResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ CreateUserResponse"` + CreateUserResult struct { + User iam.User `xml:"User"` + } `xml:"CreateUserResult"` +} + +type DeleteUserResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ DeleteUserResponse"` +} + +type GetUserResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ GetUserResponse"` + GetUserResult struct { + User iam.User `xml:"User"` + } `xml:"GetUserResult"` +} + +type CreateAccessKeyResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ CreateAccessKeyResponse"` + CreateAccessKeyResult struct { + AccessKey iam.AccessKey `xml:"AccessKey"` + } `xml:"CreateAccessKeyResult"` +} + +type PutUserPolicyResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ PutUserPolicyResponse"` +} + +type ErrorResponse struct { + CommonResponse + XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ ErrorResponse"` + Error struct { + iam.ErrorDetails + Type string `xml:"Type"` + } `xml:"Error"` +} + +func (r *CommonResponse) SetRequestId() { + r.ResponseMetadata.RequestId = fmt.Sprintf("%d", time.Now().UnixNano()) +}