s3/iam: reuse one request id per request (#8538)
* request_id: add shared request middleware
* s3err: preserve request ids in responses and logs
* iam: reuse request ids in XML responses
* sts: reuse request ids in XML responses
* request_id: drop legacy header fallback
* request_id: use AWS-style request id format
* iam: fix AWS-compatible XML format for ErrorResponse and field ordering
- ErrorResponse uses bare <RequestId> at root level instead of
<ResponseMetadata> wrapper, matching the AWS IAM error response spec
- Move CommonResponse to last field in success response structs so
<ResponseMetadata> serializes after result elements
- Add randomness to request ID generation to avoid collisions
- Add tests for XML ordering and ErrorResponse format
* iam: remove duplicate error_response_test.go
Test is already covered by responses_test.go.
* address PR review comments
- Guard against typed nil pointers in SetResponseRequestID before
interface assertion (CodeRabbit)
- Use regexp instead of strings.Index in test helpers for extracting
request IDs (Gemini)
* request_id: prevent spoofing, fix nil-error branch, thread reqID to error writers
- Ensure() now always generates a server-side ID, ignoring client-sent
x-amz-request-id headers to prevent request ID spoofing. Uses a
private context key (contextKey{}) instead of the header string.
- writeIamErrorResponse in both iamapi and embedded IAM now accepts
reqID as a parameter instead of calling Ensure() internally, ensuring
a single request ID per request lifecycle.
- The nil-iamError branch in writeIamErrorResponse now writes a 500
Internal Server Error response instead of returning silently.
- Updated tests to set request IDs via context (not headers) and added
tests for spoofing prevention and context reuse.
* sts: add request-id consistency assertions to ActionInBody tests
* test: update admin test to expect server-generated request IDs
The test previously sent a client x-amz-request-id header and expected
it echoed back. Since Ensure() now ignores client headers to prevent
spoofing, update the test to verify the server returns a non-empty
server-generated request ID instead.
* iam: add generic WithRequestID helper alongside reflection-based fallback
Add WithRequestID[T] that uses generics to take the address of a value
type, satisfying the pointer receiver on SetRequestId without reflection.
The existing SetResponseRequestID is kept for the two call sites that
operate on interface{} (from large action switches where the concrete
type varies at runtime). Generics cannot replace reflection there since
Go cannot infer type parameters from interface{}.
* Remove reflection and generics from request ID setting
Call SetRequestId directly on concrete response types in each switch
branch before boxing into interface{}, eliminating the need for
WithRequestID (generics) and SetResponseRequestID (reflection).
* iam: return pointer responses in action dispatch
* Fix IAM error handling consistency and ensure request IDs on all responses
- UpdateUser/CreatePolicy error branches: use writeIamErrorResponse instead
of s3err.WriteErrorResponse to preserve IAM formatting and request ID
- ExecuteAction: accept reqID parameter and generate one if empty, ensuring
every response carries a RequestId regardless of caller
* Clean up inline policies on DeleteUser and UpdateUser rename
DeleteUser: remove InlinePolicies[userName] from policy storage before
removing the identity, so policies are not orphaned.
UpdateUser: move InlinePolicies[userName] to InlinePolicies[newUserName]
when renaming, so GetUserPolicy/DeleteUserPolicy work under the new name.
Both operations persist the updated policies and return an error if
the storage write fails, preventing partial state.
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/request_id"
|
||||
)
|
||||
|
||||
// Constants from shared package
|
||||
@@ -162,14 +163,16 @@ func validateAccessKeyStatus(status string) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (iama *IamApiServer) ListUsers(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp ListUsersResponse) {
|
||||
func (iama *IamApiServer) ListUsers(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *ListUsersResponse) {
|
||||
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) {
|
||||
func (iama *IamApiServer) ListAccessKeys(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *ListAccessKeysResponse) {
|
||||
resp = &ListAccessKeysResponse{}
|
||||
userName := values.Get("UserName")
|
||||
for _, ident := range s3cfg.Identities {
|
||||
if userName != "" && userName != ident.Name {
|
||||
@@ -190,16 +193,31 @@ func (iama *IamApiServer) ListAccessKeys(s3cfg *iam_pb.S3ApiConfiguration, value
|
||||
return resp
|
||||
}
|
||||
|
||||
func (iama *IamApiServer) CreateUser(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp CreateUserResponse) {
|
||||
func (iama *IamApiServer) CreateUser(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *CreateUserResponse) {
|
||||
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) {
|
||||
func (iama *IamApiServer) DeleteUser(s3cfg *iam_pb.S3ApiConfiguration, userName string) (resp *DeleteUserResponse, err *IamError) {
|
||||
resp = &DeleteUserResponse{}
|
||||
for i, ident := range s3cfg.Identities {
|
||||
if userName == ident.Name {
|
||||
// Clean up any inline policies stored for this user
|
||||
policies := Policies{}
|
||||
if pErr := iama.s3ApiConfig.GetPolicies(&policies); pErr != nil && !errors.Is(pErr, filer_pb.ErrNotFound) {
|
||||
return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: pErr}
|
||||
}
|
||||
if policies.InlinePolicies != nil {
|
||||
if _, exists := policies.InlinePolicies[userName]; exists {
|
||||
delete(policies.InlinePolicies, userName)
|
||||
if pErr := iama.s3ApiConfig.PutPolicies(&policies); pErr != nil {
|
||||
return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: pErr}
|
||||
}
|
||||
}
|
||||
}
|
||||
s3cfg.Identities = append(s3cfg.Identities[:i], s3cfg.Identities[i+1:]...)
|
||||
return resp, nil
|
||||
}
|
||||
@@ -207,7 +225,8 @@ func (iama *IamApiServer) DeleteUser(s3cfg *iam_pb.S3ApiConfiguration, userName
|
||||
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) {
|
||||
func (iama *IamApiServer) GetUser(s3cfg *iam_pb.S3ApiConfiguration, userName string) (resp *GetUserResponse, err *IamError) {
|
||||
resp = &GetUserResponse{}
|
||||
for _, ident := range s3cfg.Identities {
|
||||
if userName == ident.Name {
|
||||
resp.GetUserResult.User = iam.User{UserName: &ident.Name}
|
||||
@@ -217,13 +236,28 @@ func (iama *IamApiServer) GetUser(s3cfg *iam_pb.S3ApiConfiguration, userName str
|
||||
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) {
|
||||
func (iama *IamApiServer) UpdateUser(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *UpdateUserResponse, err *IamError) {
|
||||
resp = &UpdateUserResponse{}
|
||||
userName := values.Get("UserName")
|
||||
newUserName := values.Get("NewUserName")
|
||||
if newUserName != "" {
|
||||
for _, ident := range s3cfg.Identities {
|
||||
if userName == ident.Name {
|
||||
ident.Name = newUserName
|
||||
// Move any inline policies from old username to new username
|
||||
policies := Policies{}
|
||||
if pErr := iama.s3ApiConfig.GetPolicies(&policies); pErr != nil && !errors.Is(pErr, filer_pb.ErrNotFound) {
|
||||
return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: pErr}
|
||||
}
|
||||
if policies.InlinePolicies != nil {
|
||||
if userPolicies, exists := policies.InlinePolicies[userName]; exists {
|
||||
delete(policies.InlinePolicies, userName)
|
||||
policies.InlinePolicies[newUserName] = userPolicies
|
||||
if pErr := iama.s3ApiConfig.PutPolicies(&policies); pErr != nil {
|
||||
return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: pErr}
|
||||
}
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
}
|
||||
@@ -241,12 +275,13 @@ func GetPolicyDocument(policy *string) (policy_engine.PolicyDocument, error) {
|
||||
return policyDocument, nil
|
||||
}
|
||||
|
||||
func (iama *IamApiServer) CreatePolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp CreatePolicyResponse, iamError *IamError) {
|
||||
func (iama *IamApiServer) CreatePolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *CreatePolicyResponse, iamError *IamError) {
|
||||
resp = &CreatePolicyResponse{}
|
||||
policyName := values.Get("PolicyName")
|
||||
policyDocumentString := values.Get("PolicyDocument")
|
||||
policyDocument, err := GetPolicyDocument(&policyDocumentString)
|
||||
if err != nil {
|
||||
return CreatePolicyResponse{}, &IamError{Code: iam.ErrCodeMalformedPolicyDocumentException, Error: err}
|
||||
return resp, &IamError{Code: iam.ErrCodeMalformedPolicyDocumentException, Error: err}
|
||||
}
|
||||
policyId := Hash(&policyName)
|
||||
arn := fmt.Sprintf("arn:aws:iam:::policy/%s", policyName)
|
||||
@@ -274,16 +309,17 @@ type IamError struct {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
func (iama *IamApiServer) PutUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *PutUserPolicyResponse, iamError *IamError) {
|
||||
resp = &PutUserPolicyResponse{}
|
||||
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}
|
||||
return resp, &IamError{Code: iam.ErrCodeMalformedPolicyDocumentException, Error: err}
|
||||
}
|
||||
if _, err := GetActions(&policyDocument); err != nil {
|
||||
return PutUserPolicyResponse{}, &IamError{Code: iam.ErrCodeMalformedPolicyDocumentException, Error: err}
|
||||
return resp, &IamError{Code: iam.ErrCodeMalformedPolicyDocumentException, Error: err}
|
||||
}
|
||||
|
||||
// Verify the user exists before persisting the policy
|
||||
@@ -295,20 +331,20 @@ func (iama *IamApiServer) PutUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values
|
||||
}
|
||||
}
|
||||
if targetIdent == nil {
|
||||
return PutUserPolicyResponse{}, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf("the user with name %s cannot be found", userName)}
|
||||
return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf("the user with name %s cannot be found", userName)}
|
||||
}
|
||||
|
||||
// Persist inline policy to storage using per-user indexed structure
|
||||
policies := Policies{}
|
||||
if err = iama.s3ApiConfig.GetPolicies(&policies); err != nil && !errors.Is(err, filer_pb.ErrNotFound) {
|
||||
return PutUserPolicyResponse{}, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err}
|
||||
return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err}
|
||||
}
|
||||
|
||||
userPolicies := policies.getOrCreateUserPolicies(userName)
|
||||
userPolicies[policyName] = policyDocument
|
||||
|
||||
if err = iama.s3ApiConfig.PutPolicies(&policies); err != nil {
|
||||
return PutUserPolicyResponse{}, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err}
|
||||
return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err}
|
||||
}
|
||||
|
||||
// Recompute aggregated actions (inline + managed)
|
||||
@@ -321,7 +357,8 @@ 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 *IamError) {
|
||||
func (iama *IamApiServer) GetUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *GetUserPolicyResponse, err *IamError) {
|
||||
resp = &GetUserPolicyResponse{}
|
||||
userName := values.Get("UserName")
|
||||
policyName := values.Get("PolicyName")
|
||||
for _, ident := range s3cfg.Identities {
|
||||
@@ -404,7 +441,8 @@ func (iama *IamApiServer) GetUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values
|
||||
}
|
||||
|
||||
// DeleteUserPolicy removes the inline policy from a user (clears their actions).
|
||||
func (iama *IamApiServer) DeleteUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp DeleteUserPolicyResponse, err *IamError) {
|
||||
func (iama *IamApiServer) DeleteUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *DeleteUserPolicyResponse, err *IamError) {
|
||||
resp = &DeleteUserPolicyResponse{}
|
||||
userName := values.Get("UserName")
|
||||
policyName := values.Get("PolicyName")
|
||||
|
||||
@@ -447,7 +485,8 @@ func (iama *IamApiServer) DeleteUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, val
|
||||
}
|
||||
|
||||
// GetPolicy retrieves a managed policy by ARN.
|
||||
func (iama *IamApiServer) GetPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp GetPolicyResponse, iamError *IamError) {
|
||||
func (iama *IamApiServer) GetPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *GetPolicyResponse, iamError *IamError) {
|
||||
resp = &GetPolicyResponse{}
|
||||
policyArn := values.Get("PolicyArn")
|
||||
policyName, iamError := parsePolicyArn(policyArn)
|
||||
if iamError != nil {
|
||||
@@ -472,7 +511,8 @@ func (iama *IamApiServer) GetPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url
|
||||
|
||||
// DeletePolicy removes a managed policy. Rejects deletion if the policy is still attached to any user
|
||||
// (matching AWS IAM behavior: must detach before deleting).
|
||||
func (iama *IamApiServer) DeletePolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp DeletePolicyResponse, iamError *IamError) {
|
||||
func (iama *IamApiServer) DeletePolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *DeletePolicyResponse, iamError *IamError) {
|
||||
resp = &DeletePolicyResponse{}
|
||||
policyArn := values.Get("PolicyArn")
|
||||
policyName, iamError := parsePolicyArn(policyArn)
|
||||
if iamError != nil {
|
||||
@@ -509,7 +549,8 @@ func (iama *IamApiServer) DeletePolicy(s3cfg *iam_pb.S3ApiConfiguration, values
|
||||
}
|
||||
|
||||
// ListPolicies lists all managed policies.
|
||||
func (iama *IamApiServer) ListPolicies(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp ListPoliciesResponse, iamError *IamError) {
|
||||
func (iama *IamApiServer) ListPolicies(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *ListPoliciesResponse, iamError *IamError) {
|
||||
resp = &ListPoliciesResponse{}
|
||||
policies := Policies{}
|
||||
if err := iama.s3ApiConfig.GetPolicies(&policies); err != nil && !errors.Is(err, filer_pb.ErrNotFound) {
|
||||
return resp, &IamError{Code: iam.ErrCodeServiceFailureException, Error: err}
|
||||
@@ -529,7 +570,8 @@ func (iama *IamApiServer) ListPolicies(s3cfg *iam_pb.S3ApiConfiguration, values
|
||||
}
|
||||
|
||||
// AttachUserPolicy attaches a managed policy to a user.
|
||||
func (iama *IamApiServer) AttachUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp AttachUserPolicyResponse, iamError *IamError) {
|
||||
func (iama *IamApiServer) AttachUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *AttachUserPolicyResponse, iamError *IamError) {
|
||||
resp = &AttachUserPolicyResponse{}
|
||||
userName := values.Get("UserName")
|
||||
policyArn := values.Get("PolicyArn")
|
||||
policyName, iamError := parsePolicyArn(policyArn)
|
||||
@@ -574,7 +616,8 @@ func (iama *IamApiServer) AttachUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, val
|
||||
}
|
||||
|
||||
// DetachUserPolicy detaches a managed policy from a user.
|
||||
func (iama *IamApiServer) DetachUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp DetachUserPolicyResponse, iamError *IamError) {
|
||||
func (iama *IamApiServer) DetachUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *DetachUserPolicyResponse, iamError *IamError) {
|
||||
resp = &DetachUserPolicyResponse{}
|
||||
userName := values.Get("UserName")
|
||||
policyArn := values.Get("PolicyArn")
|
||||
policyName, iamError := parsePolicyArn(policyArn)
|
||||
@@ -622,7 +665,8 @@ func (iama *IamApiServer) DetachUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, val
|
||||
}
|
||||
|
||||
// ListAttachedUserPolicies lists the managed policies attached to a user.
|
||||
func (iama *IamApiServer) ListAttachedUserPolicies(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp ListAttachedUserPoliciesResponse, iamError *IamError) {
|
||||
func (iama *IamApiServer) ListAttachedUserPolicies(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *ListAttachedUserPoliciesResponse, iamError *IamError) {
|
||||
resp = &ListAttachedUserPoliciesResponse{}
|
||||
userName := values.Get("UserName")
|
||||
for _, ident := range s3cfg.Identities {
|
||||
if ident.Name != userName {
|
||||
@@ -714,7 +758,8 @@ func GetActions(policy *policy_engine.PolicyDocument) ([]string, error) {
|
||||
return actions, nil
|
||||
}
|
||||
|
||||
func (iama *IamApiServer) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp CreateAccessKeyResponse, iamErr *IamError) {
|
||||
func (iama *IamApiServer) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *CreateAccessKeyResponse, iamErr *IamError) {
|
||||
resp = &CreateAccessKeyResponse{}
|
||||
userName := values.Get("UserName")
|
||||
status := iam.StatusTypeActive
|
||||
|
||||
@@ -758,7 +803,8 @@ func (iama *IamApiServer) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, valu
|
||||
}
|
||||
|
||||
// UpdateAccessKey updates the status of an access key (Active or Inactive).
|
||||
func (iama *IamApiServer) UpdateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp UpdateAccessKeyResponse, err *IamError) {
|
||||
func (iama *IamApiServer) UpdateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *UpdateAccessKeyResponse, err *IamError) {
|
||||
resp = &UpdateAccessKeyResponse{}
|
||||
userName := values.Get("UserName")
|
||||
accessKeyId := values.Get("AccessKeyId")
|
||||
status := values.Get("Status")
|
||||
@@ -788,7 +834,8 @@ func (iama *IamApiServer) UpdateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, valu
|
||||
return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf(USER_DOES_NOT_EXIST, userName)}
|
||||
}
|
||||
|
||||
func (iama *IamApiServer) DeleteAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp DeleteAccessKeyResponse) {
|
||||
func (iama *IamApiServer) DeleteAccessKey(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) (resp *DeleteAccessKeyResponse) {
|
||||
resp = &DeleteAccessKeyResponse{}
|
||||
userName := values.Get("UserName")
|
||||
accessKeyId := values.Get("AccessKeyId")
|
||||
for _, ident := range s3cfg.Identities {
|
||||
@@ -859,6 +906,8 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||
policyLock.Lock()
|
||||
defer policyLock.Unlock()
|
||||
|
||||
r, reqID := request_id.Ensure(r)
|
||||
|
||||
if err := r.ParseForm(); err != nil {
|
||||
s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
|
||||
return
|
||||
@@ -871,8 +920,7 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
glog.V(4).Infof("DoActions: %+v", values)
|
||||
var response interface{}
|
||||
var iamError *IamError
|
||||
var response iamlib.RequestIDSetter
|
||||
changed := true
|
||||
switch r.Form.Get("Action") {
|
||||
case "ListUsers":
|
||||
@@ -886,32 +934,35 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||
response = iama.CreateUser(s3cfg, values)
|
||||
case "GetUser":
|
||||
userName := values.Get("UserName")
|
||||
response, iamError = iama.GetUser(s3cfg, userName)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.GetUser(s3cfg, userName)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
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)
|
||||
var err *IamError
|
||||
response, err = iama.UpdateUser(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
case "DeleteUser":
|
||||
userName := values.Get("UserName")
|
||||
response, iamError = iama.DeleteUser(s3cfg, userName)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.DeleteUser(s3cfg, userName)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
case "CreateAccessKey":
|
||||
iama.handleImplicitUsername(r, values)
|
||||
response, iamError = iama.CreateAccessKey(s3cfg, values)
|
||||
if iamError != nil {
|
||||
glog.Errorf("CreateAccessKey: %+v", iamError.Error)
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.CreateAccessKey(s3cfg, values)
|
||||
if err != nil {
|
||||
glog.Errorf("CreateAccessKey: %+v", err.Error)
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
case "DeleteAccessKey":
|
||||
@@ -919,85 +970,94 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||
response = iama.DeleteAccessKey(s3cfg, values)
|
||||
case "UpdateAccessKey":
|
||||
iama.handleImplicitUsername(r, values)
|
||||
response, iamError = iama.UpdateAccessKey(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.UpdateAccessKey(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
case "CreatePolicy":
|
||||
response, iamError = iama.CreatePolicy(s3cfg, values)
|
||||
if iamError != nil {
|
||||
glog.Errorf("CreatePolicy: %+v", iamError.Error)
|
||||
s3err.WriteErrorResponse(w, r, s3err.ErrInvalidRequest)
|
||||
var err *IamError
|
||||
response, err = iama.CreatePolicy(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
// CreatePolicy persists the policy document via iama.s3ApiConfig.PutPolicies().
|
||||
// The `changed` flag is false because this does not modify the main s3cfg.Identities configuration.
|
||||
changed = false
|
||||
case "PutUserPolicy":
|
||||
var iamError *IamError
|
||||
response, iamError = iama.PutUserPolicy(s3cfg, values)
|
||||
if iamError != nil {
|
||||
glog.Errorf("PutUserPolicy: %+v", iamError.Error)
|
||||
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.PutUserPolicy(s3cfg, values)
|
||||
if err != nil {
|
||||
glog.Errorf("PutUserPolicy: %+v", err.Error)
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
case "GetUserPolicy":
|
||||
response, iamError = iama.GetUserPolicy(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.GetUserPolicy(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
changed = false
|
||||
case "DeleteUserPolicy":
|
||||
if response, iamError = iama.DeleteUserPolicy(s3cfg, values); iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.DeleteUserPolicy(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
case "GetPolicy":
|
||||
response, iamError = iama.GetPolicy(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.GetPolicy(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
changed = false
|
||||
case "DeletePolicy":
|
||||
response, iamError = iama.DeletePolicy(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.DeletePolicy(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
changed = false
|
||||
case "ListPolicies":
|
||||
response, iamError = iama.ListPolicies(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.ListPolicies(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
changed = false
|
||||
case "AttachUserPolicy":
|
||||
response, iamError = iama.AttachUserPolicy(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.AttachUserPolicy(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
case "DetachUserPolicy":
|
||||
response, iamError = iama.DetachUserPolicy(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.DetachUserPolicy(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
case "ListAttachedUserPolicies":
|
||||
response, iamError = iama.ListAttachedUserPolicies(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
var err *IamError
|
||||
response, err = iama.ListAttachedUserPolicies(s3cfg, values)
|
||||
if err != nil {
|
||||
writeIamErrorResponse(w, r, reqID, err)
|
||||
return
|
||||
}
|
||||
changed = false
|
||||
default:
|
||||
errNotImplemented := s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
errorResponse := newErrorResponse(errNotImplemented.Code, errNotImplemented.Description)
|
||||
errorResponse := newErrorResponse(errNotImplemented.Code, errNotImplemented.Description, reqID)
|
||||
s3err.WriteXMLResponse(w, r, errNotImplemented.HTTPStatusCode, errorResponse)
|
||||
return
|
||||
}
|
||||
@@ -1005,7 +1065,7 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||
err := iama.s3ApiConfig.PutS3ApiConfiguration(s3cfg)
|
||||
if err != nil {
|
||||
var iamError = IamError{Code: iam.ErrCodeServiceFailureException, Error: err}
|
||||
writeIamErrorResponse(w, r, &iamError)
|
||||
writeIamErrorResponse(w, r, reqID, &iamError)
|
||||
return
|
||||
}
|
||||
// Reload in-memory identity maps so subsequent LookupByAccessKey calls
|
||||
@@ -1017,5 +1077,6 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
}
|
||||
response.SetRequestId(reqID)
|
||||
s3err.WriteXMLResponse(w, r, http.StatusOK, response)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user