You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							530 lines
						
					
					
						
							17 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							530 lines
						
					
					
						
							17 KiB
						
					
					
				| package iamapi | |
| 
 | |
| import ( | |
| 	"crypto/sha1" | |
| 	"encoding/json" | |
| 	"errors" | |
| 	"fmt" | |
| 	"math/rand" | |
| 	"net/http" | |
| 	"net/url" | |
| 	"reflect" | |
| 	"strings" | |
| 	"sync" | |
| 	"time" | |
| 
 | |
| 	"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" | |
| 
 | |
| 	"github.com/aws/aws-sdk-go/service/iam" | |
| ) | |
| 
 | |
| const ( | |
| 	charsetUpper            = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | |
| 	charset                 = charsetUpper + "abcdefghijklmnopqrstuvwxyz/" | |
| 	policyDocumentVersion   = "2012-10-17" | |
| 	StatementActionAdmin    = "*" | |
| 	StatementActionWrite    = "Put*" | |
| 	StatementActionWriteAcp = "PutBucketAcl" | |
| 	StatementActionRead     = "Get*" | |
| 	StatementActionReadAcp  = "GetBucketAcl" | |
| 	StatementActionList     = "List*" | |
| 	StatementActionTagging  = "Tagging*" | |
| 	StatementActionDelete   = "DeleteBucket*" | |
| ) | |
| 
 | |
| var ( | |
| 	seededRand *rand.Rand = rand.New( | |
| 		rand.NewSource(time.Now().UnixNano())) | |
| 	policyDocuments = map[string]*policy_engine.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 StatementActionWriteAcp: | |
| 		return s3_constants.ACTION_WRITE_ACP | |
| 	case StatementActionRead: | |
| 		return s3_constants.ACTION_READ | |
| 	case StatementActionReadAcp: | |
| 		return s3_constants.ACTION_READ_ACP | |
| 	case StatementActionList: | |
| 		return s3_constants.ACTION_LIST | |
| 	case StatementActionTagging: | |
| 		return s3_constants.ACTION_TAGGING | |
| 	case StatementActionDelete: | |
| 		return s3_constants.ACTION_DELETE_BUCKET | |
| 	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_WRITE_ACP: | |
| 		return StatementActionWriteAcp | |
| 	case s3_constants.ACTION_READ: | |
| 		return StatementActionRead | |
| 	case s3_constants.ACTION_READ_ACP: | |
| 		return StatementActionReadAcp | |
| 	case s3_constants.ACTION_LIST: | |
| 		return StatementActionList | |
| 	case s3_constants.ACTION_TAGGING: | |
| 		return StatementActionTagging | |
| 	case s3_constants.ACTION_DELETE_BUCKET: | |
| 		return StatementActionDelete | |
| 	default: | |
| 		return "" | |
| 	} | |
| } | |
| 
 | |
| const ( | |
| 	USER_DOES_NOT_EXIST = "the user with name %s cannot be found." | |
| ) | |
| 
 | |
| type Policies struct { | |
| 	Policies map[string]policy_engine.PolicyDocument `json:"policies"` | |
| } | |
| 
 | |
| func Hash(s *string) string { | |
| 	h := sha1.New() | |
| 	h.Write([]byte(*s)) | |
| 	return fmt.Sprintf("%x", h.Sum(nil)) | |
| } | |
| 
 | |
| func StringWithCharset(length int, charset string) string { | |
| 	b := make([]byte, length) | |
| 	for i := range b { | |
| 		b[i] = charset[seededRand.Intn(len(charset))] | |
| 	} | |
| 	return string(b) | |
| } | |
| 
 | |
| func (iama *IamApiServer) ListUsers(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp ListUsersResponse) { | |
| 	for _, ident := range s3cfg.Identities { | |
| 		resp.ListUsersResult.Users = append(resp.ListUsersResult.Users, &iam.User{UserName: &ident.Name}) | |
| 	} | |
| 	return resp | |
| } | |
| 
 | |
| func (iama *IamApiServer) ListAccessKeys(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp ListAccessKeysResponse) { | |
| 	status := iam.StatusTypeActive | |
| 	userName := values.Get("UserName") | |
| 	for _, ident := range s3cfg.Identities { | |
| 		if userName != "" && userName != ident.Name { | |
| 			continue | |
| 		} | |
| 		for _, cred := range ident.Credentials { | |
| 			resp.ListAccessKeysResult.AccessKeyMetadata = append(resp.ListAccessKeysResult.AccessKeyMetadata, | |
| 				&iam.AccessKeyMetadata{UserName: &ident.Name, AccessKeyId: &cred.AccessKey, Status: &status}, | |
| 			) | |
| 		} | |
| 	} | |
| 	return resp | |
| } | |
| 
 | |
| func (iama *IamApiServer) CreateUser(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp CreateUserResponse) { | |
| 	userName := values.Get("UserName") | |
| 	resp.CreateUserResult.User.UserName = &userName | |
| 	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 *IamError) { | |
| 	for i, ident := range s3cfg.Identities { | |
| 		if userName == ident.Name { | |
| 			s3cfg.Identities = append(s3cfg.Identities[:i], s3cfg.Identities[i+1:]...) | |
| 			return resp, nil | |
| 		} | |
| 	} | |
| 	return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf(USER_DOES_NOT_EXIST, userName)} | |
| } | |
| 
 | |
| func (iama *IamApiServer) GetUser(s3cfg *iam_pb.S3ApiConfiguration, userName string) (resp GetUserResponse, err *IamError) { | |
| 	for _, ident := range s3cfg.Identities { | |
| 		if userName == ident.Name { | |
| 			resp.GetUserResult.User = iam.User{UserName: &ident.Name} | |
| 			return resp, nil | |
| 		} | |
| 	} | |
| 	return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf(USER_DOES_NOT_EXIST, userName)} | |
| } | |
| 
 | |
| func (iama *IamApiServer) UpdateUser(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp UpdateUserResponse, err *IamError) { | |
| 	userName := values.Get("UserName") | |
| 	newUserName := values.Get("NewUserName") | |
| 	if newUserName != "" { | |
| 		for _, ident := range s3cfg.Identities { | |
| 			if userName == ident.Name { | |
| 				ident.Name = newUserName | |
| 				return resp, nil | |
| 			} | |
| 		} | |
| 	} else { | |
| 		return resp, nil | |
| 	} | |
| 	return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf(USER_DOES_NOT_EXIST, userName)} | |
| } | |
| 
 | |
| 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, nil | |
| } | |
| 
 | |
| func (iama *IamApiServer) CreatePolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp CreatePolicyResponse, iamError *IamError) { | |
| 	policyName := values.Get("PolicyName") | |
| 	policyDocumentString := values.Get("PolicyDocument") | |
| 	policyDocument, err := GetPolicyDocument(&policyDocumentString) | |
| 	if err != nil { | |
| 		return CreatePolicyResponse{}, &IamError{Code: iam.ErrCodeMalformedPolicyDocumentException, Error: err} | |
| 	} | |
| 	policyId := Hash(&policyDocumentString) | |
| 	arn := fmt.Sprintf("arn:aws:iam:::policy/%s", policyName) | |
| 	resp.CreatePolicyResult.Policy.PolicyName = &policyName | |
| 	resp.CreatePolicyResult.Policy.Arn = &arn | |
| 	resp.CreatePolicyResult.Policy.PolicyId = &policyId | |
| 	policies := Policies{} | |
| 	policyLock.Lock() | |
| 	defer policyLock.Unlock() | |
| 	if err = iama.s3ApiConfig.GetPolicies(&policies); err != nil { | |
| 		return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err} | |
| 	} | |
| 	policies.Policies[policyName] = policyDocument | |
| 	if err = iama.s3ApiConfig.PutPolicies(&policies); err != nil { | |
| 		return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err} | |
| 	} | |
| 	return resp, nil | |
| } | |
| 
 | |
| type IamError struct { | |
| 	Code  string | |
| 	Error error | |
| } | |
| 
 | |
| // https://docs.aws.amazon.com/IAM/latest/APIReference/API_PutUserPolicy.html | |
| func (iama *IamApiServer) PutUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp PutUserPolicyResponse, iamError *IamError) { | |
| 	userName := values.Get("UserName") | |
| 	policyName := values.Get("PolicyName") | |
| 	policyDocumentString := values.Get("PolicyDocument") | |
| 	policyDocument, err := GetPolicyDocument(&policyDocumentString) | |
| 	if err != nil { | |
| 		return PutUserPolicyResponse{}, &IamError{Code: iam.ErrCodeMalformedPolicyDocumentException, Error: err} | |
| 	} | |
| 	policyDocuments[policyName] = &policyDocument | |
| 	actions, err := GetActions(&policyDocument) | |
| 	if err != nil { | |
| 		return PutUserPolicyResponse{}, &IamError{Code: iam.ErrCodeMalformedPolicyDocumentException, Error: err} | |
| 	} | |
| 	// Log the actions | |
| 	glog.V(3).Infof("PutUserPolicy: actions=%v", actions) | |
| 	for _, ident := range s3cfg.Identities { | |
| 		if userName != ident.Name { | |
| 			continue | |
| 		} | |
| 		ident.Actions = actions | |
| 		return resp, nil | |
| 	} | |
| 	return PutUserPolicyResponse{}, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf("the user with name %s cannot be found", userName)} | |
| } | |
| 
 | |
| func (iama *IamApiServer) GetUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp GetUserPolicyResponse, err *IamError) { | |
| 	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, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: errors.New("no actions found")} | |
| 		} | |
| 
 | |
| 		policyDocument := policy_engine.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.Strings(), actions) { | |
| 					policyDocument.Statement[i].Resource = policy_engine.NewStringOrStringSlice(append( | |
| 						policyDocument.Statement[i].Resource.Strings(), resource)...) | |
| 					isEqAction = true | |
| 					break | |
| 				} | |
| 			} | |
| 			if isEqAction { | |
| 				continue | |
| 			} | |
| 			policyDocumentStatement := policy_engine.PolicyStatement{ | |
| 				Effect:   policy_engine.PolicyEffectAllow, | |
| 				Action:   policy_engine.NewStringOrStringSlice(actions...), | |
| 				Resource: policy_engine.NewStringOrStringSlice(resource), | |
| 			} | |
| 			policyDocument.Statement = append(policyDocument.Statement, policyDocumentStatement) | |
| 		} | |
| 		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)} | |
| } | |
| 
 | |
| func (iama *IamApiServer) DeleteUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp PutUserPolicyResponse, err *IamError) { | |
| 	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, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf(USER_DOES_NOT_EXIST, userName)} | |
| } | |
| 
 | |
| func GetActions(policy *policy_engine.PolicyDocument) ([]string, error) { | |
| 	var actions []string | |
| 
 | |
| 	for _, statement := range policy.Statement { | |
| 		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.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" { | |
| 				continue | |
| 			} | |
| 			for _, action := range statement.Action.Strings() { | |
| 				// Parse "s3:Get*" | |
| 				act := strings.Split(action, ":") | |
| 				if len(act) != 2 || act[0] != "s3" { | |
| 					continue | |
| 				} | |
| 				statementAction := MapToStatementAction(act[1]) | |
| 
 | |
| 				if statementAction == "" { | |
| 					return nil, fmt.Errorf("not a valid action: '%s'", act[1]) | |
| 				} | |
| 
 | |
| 				path := res[5] | |
| 				if path == "*" { | |
| 					actions = append(actions, statementAction) | |
| 					continue | |
| 				} | |
| 				actions = append(actions, fmt.Sprintf("%s:%s", statementAction, path)) | |
| 			} | |
| 		} | |
| 	} | |
| 	return actions, nil | |
| } | |
| 
 | |
| func (iama *IamApiServer) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp CreateAccessKeyResponse) { | |
| 	userName := values.Get("UserName") | |
| 	status := iam.StatusTypeActive | |
| 	accessKeyId := StringWithCharset(21, charsetUpper) | |
| 	secretAccessKey := StringWithCharset(42, charset) | |
| 	resp.CreateAccessKeyResult.AccessKey.AccessKeyId = &accessKeyId | |
| 	resp.CreateAccessKeyResult.AccessKey.SecretAccessKey = &secretAccessKey | |
| 	resp.CreateAccessKeyResult.AccessKey.UserName = &userName | |
| 	resp.CreateAccessKeyResult.AccessKey.Status = &status | |
| 	changed := false | |
| 	for _, ident := range s3cfg.Identities { | |
| 		if userName == ident.Name { | |
| 			ident.Credentials = append(ident.Credentials, | |
| 				&iam_pb.Credential{AccessKey: accessKeyId, SecretKey: secretAccessKey}) | |
| 			changed = true | |
| 			break | |
| 		} | |
| 	} | |
| 	if !changed { | |
| 		s3cfg.Identities = append(s3cfg.Identities, | |
| 			&iam_pb.Identity{ | |
| 				Name: userName, | |
| 				Credentials: []*iam_pb.Credential{ | |
| 					{ | |
| 						AccessKey: accessKeyId, | |
| 						SecretKey: secretAccessKey, | |
| 					}, | |
| 				}, | |
| 			}, | |
| 		) | |
| 	} | |
| 	return resp | |
| } | |
| 
 | |
| func (iama *IamApiServer) DeleteAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp DeleteAccessKeyResponse) { | |
| 	userName := values.Get("UserName") | |
| 	accessKeyId := values.Get("AccessKeyId") | |
| 	for _, ident := range s3cfg.Identities { | |
| 		if userName == ident.Name { | |
| 			for i, cred := range ident.Credentials { | |
| 				if cred.AccessKey == accessKeyId { | |
| 					ident.Credentials = append(ident.Credentials[:i], ident.Credentials[i+1:]...) | |
| 					break | |
| 				} | |
| 			} | |
| 			break | |
| 		} | |
| 	} | |
| 	return resp | |
| } | |
| 
 | |
| // handleImplicitUsername adds username who signs the request to values if 'username' is not specified | |
| // According to https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-access-key.html/ | |
| // "If you do not specify a user name, IAM determines the user name implicitly based on the Amazon Web | |
| // Services access key ID signing the request." | |
| func handleImplicitUsername(r *http.Request, values url.Values) { | |
| 	if len(r.Header["Authorization"]) == 0 || values.Get("UserName") != "" { | |
| 		return | |
| 	} | |
| 	// get username who signs the request. For a typical Authorization: | |
| 	// "AWS4-HMAC-SHA256 Credential=197FSAQ7HHTA48X64O3A/20220420/test1/iam/aws4_request, SignedHeaders=content-type; | |
| 	// host;x-amz-date, Signature=6757dc6b3d7534d67e17842760310e99ee695408497f6edc4fdb84770c252dc8", | |
| 	// the "test1" will be extracted as the username | |
| 	glog.V(4).Infof("Authorization field: %v", r.Header["Authorization"][0]) | |
| 	s := strings.Split(r.Header["Authorization"][0], "Credential=") | |
| 	if len(s) < 2 { | |
| 		return | |
| 	} | |
| 	s = strings.Split(s[1], ",") | |
| 	if len(s) < 2 { | |
| 		return | |
| 	} | |
| 	s = strings.Split(s[0], "/") | |
| 	if len(s) < 5 { | |
| 		return | |
| 	} | |
| 	userName := s[2] | |
| 	values.Set("UserName", userName) | |
| } | |
| 
 | |
| func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) { | |
| 	if err := r.ParseForm(); err != nil { | |
| 		s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest) | |
| 		return | |
| 	} | |
| 	values := r.PostForm | |
| 	s3cfg := &iam_pb.S3ApiConfiguration{} | |
| 	if err := iama.s3ApiConfig.GetS3ApiConfiguration(s3cfg); err != nil && !errors.Is(err, filer_pb.ErrNotFound) { | |
| 		s3err.WriteErrorResponse(w, r, s3err.ErrInternalError) | |
| 		return | |
| 	} | |
| 
 | |
| 	glog.V(4).Infof("DoActions: %+v", values) | |
| 	var response interface{} | |
| 	var iamError *IamError | |
| 	changed := true | |
| 	switch r.Form.Get("Action") { | |
| 	case "ListUsers": | |
| 		response = iama.ListUsers(s3cfg, values) | |
| 		changed = false | |
| 	case "ListAccessKeys": | |
| 		handleImplicitUsername(r, values) | |
| 		response = iama.ListAccessKeys(s3cfg, values) | |
| 		changed = false | |
| 	case "CreateUser": | |
| 		response = iama.CreateUser(s3cfg, values) | |
| 	case "GetUser": | |
| 		userName := values.Get("UserName") | |
| 		response, iamError = iama.GetUser(s3cfg, userName) | |
| 		if iamError != nil { | |
| 			writeIamErrorResponse(w, r, iamError) | |
| 			return | |
| 		} | |
| 		changed = false | |
| 	case "UpdateUser": | |
| 		response, iamError = iama.UpdateUser(s3cfg, values) | |
| 		if iamError != nil { | |
| 			glog.Errorf("UpdateUser: %+v", iamError.Error) | |
| 			s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest) | |
| 			return | |
| 		} | |
| 	case "DeleteUser": | |
| 		userName := values.Get("UserName") | |
| 		response, iamError = iama.DeleteUser(s3cfg, userName) | |
| 		if iamError != nil { | |
| 			writeIamErrorResponse(w, r, iamError) | |
| 			return | |
| 		} | |
| 	case "CreateAccessKey": | |
| 		handleImplicitUsername(r, values) | |
| 		response = iama.CreateAccessKey(s3cfg, values) | |
| 	case "DeleteAccessKey": | |
| 		handleImplicitUsername(r, values) | |
| 		response = iama.DeleteAccessKey(s3cfg, values) | |
| 	case "CreatePolicy": | |
| 		response, iamError = iama.CreatePolicy(s3cfg, values) | |
| 		if iamError != nil { | |
| 			glog.Errorf("CreatePolicy:  %+v", iamError.Error) | |
| 			s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest) | |
| 			return | |
| 		} | |
| 	case "PutUserPolicy": | |
| 		var iamError *IamError | |
| 		response, iamError = iama.PutUserPolicy(s3cfg, values) | |
| 		if iamError != nil { | |
| 			glog.Errorf("PutUserPolicy:  %+v", iamError.Error) | |
| 
 | |
| 			writeIamErrorResponse(w, r, iamError) | |
| 			return | |
| 		} | |
| 	case "GetUserPolicy": | |
| 		response, iamError = iama.GetUserPolicy(s3cfg, values) | |
| 		if iamError != nil { | |
| 			writeIamErrorResponse(w, r, iamError) | |
| 			return | |
| 		} | |
| 		changed = false | |
| 	case "DeleteUserPolicy": | |
| 		if response, iamError = iama.DeleteUserPolicy(s3cfg, values); iamError != nil { | |
| 			writeIamErrorResponse(w, r, iamError) | |
| 			return | |
| 		} | |
| 	default: | |
| 		errNotImplemented := s3err.GetAPIError(s3err.ErrNotImplemented) | |
| 		errorResponse := ErrorResponse{} | |
| 		errorResponse.Error.Code = &errNotImplemented.Code | |
| 		errorResponse.Error.Message = &errNotImplemented.Description | |
| 		s3err.WriteXMLResponse(w, r, errNotImplemented.HTTPStatusCode, errorResponse) | |
| 		return | |
| 	} | |
| 	if changed { | |
| 		err := iama.s3ApiConfig.PutS3ApiConfiguration(s3cfg) | |
| 		if err != nil { | |
| 			var iamError = IamError{Code: iam.ErrCodeServiceFailureException, Error: err} | |
| 			writeIamErrorResponse(w, r, &iamError) | |
| 			return | |
| 		} | |
| 	} | |
| 	s3err.WriteXMLResponse(w, r, http.StatusOK, response) | |
| }
 |