@ -26,6 +26,7 @@ import (
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
"github.com/seaweedfs/seaweedfs/weed/util/request_id"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/proto"
)
)
@ -157,18 +158,20 @@ const (
iamAccessKeyStatusInactive = iamlib . AccessKeyStatusInactive
iamAccessKeyStatusInactive = iamlib . AccessKeyStatusInactive
)
)
func newIamErrorResponse ( errCode string , errMsg string ) iamErrorResponse {
func newIamErrorResponse ( errCode string , errMsg string , requestID string ) iamErrorResponse {
errorResp := iamErrorResponse { }
errorResp := iamErrorResponse { }
errorResp . Error . Type = "Sender"
errorResp . Error . Type = "Sender"
errorResp . Error . Code = & errCode
errorResp . Error . Code = & errCode
errorResp . Error . Message = & errMsg
errorResp . Error . Message = & errMsg
errorResp . SetRequestId ( )
errorResp . SetRequestId ( requestID )
return errorResp
return errorResp
}
}
func ( e * EmbeddedIamApi ) writeIamErrorResponse ( w http . ResponseWriter , r * http . Request , iamErr * iamError ) {
func ( e * EmbeddedIamApi ) writeIamErrorResponse ( w http . ResponseWriter , r * http . Request , reqID string , iamErr * iamError ) {
if iamErr == nil {
if iamErr == nil {
glog . Errorf ( "No error found" )
glog . Errorf ( "writeIamErrorResponse called with nil error" )
internalResp := newIamErrorResponse ( iam . ErrCodeServiceFailureException , "Internal server error" , reqID )
s3err . WriteXMLResponse ( w , r , http . StatusInternalServerError , internalResp )
return
return
}
}
@ -176,8 +179,8 @@ func (e *EmbeddedIamApi) writeIamErrorResponse(w http.ResponseWriter, r *http.Re
errMsg := iamErr . Error . Error ( )
errMsg := iamErr . Error . Error ( )
glog . Errorf ( "IAM Response %+v" , errMsg )
glog . Errorf ( "IAM Response %+v" , errMsg )
errorResp := newIamErrorResponse ( errCode , errMsg )
internalErrorResponse := newIamErrorResponse ( iam . ErrCodeServiceFailureException , "Internal server error" )
errorResp := newIamErrorResponse ( errCode , errMsg , reqID )
internalErrorResponse := newIamErrorResponse ( iam . ErrCodeServiceFailureException , "Internal server error" , reqID )
switch errCode {
switch errCode {
case iam . ErrCodeNoSuchEntityException :
case iam . ErrCodeNoSuchEntityException :
@ -230,8 +233,8 @@ func (e *EmbeddedIamApi) ReloadConfiguration() error {
}
}
// ListUsers lists all IAM users.
// ListUsers lists all IAM users.
func ( e * EmbeddedIamApi ) ListUsers ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) iamListUsersResponse {
var resp iamListUsersResponse
func ( e * EmbeddedIamApi ) ListUsers ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) * iamListUsersResponse {
resp := & iamListUsersResponse { }
for _ , ident := range s3cfg . Identities {
for _ , ident := range s3cfg . Identities {
resp . ListUsersResult . Users = append ( resp . ListUsersResult . Users , & iam . User { UserName : & ident . Name } )
resp . ListUsersResult . Users = append ( resp . ListUsersResult . Users , & iam . User { UserName : & ident . Name } )
}
}
@ -239,8 +242,8 @@ func (e *EmbeddedIamApi) ListUsers(s3cfg *iam_pb.S3ApiConfiguration, values url.
}
}
// ListAccessKeys lists access keys for a user.
// ListAccessKeys lists access keys for a user.
func ( e * EmbeddedIamApi ) ListAccessKeys ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) iamListAccessKeysResponse {
var resp iamListAccessKeysResponse
func ( e * EmbeddedIamApi ) ListAccessKeys ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) * iamListAccessKeysResponse {
resp := & iamListAccessKeysResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
for _ , ident := range s3cfg . Identities {
for _ , ident := range s3cfg . Identities {
if userName != "" && userName != ident . Name {
if userName != "" && userName != ident . Name {
@ -265,8 +268,8 @@ func (e *EmbeddedIamApi) ListAccessKeys(s3cfg *iam_pb.S3ApiConfiguration, values
}
}
// CreateUser creates a new IAM user.
// CreateUser creates a new IAM user.
func ( e * EmbeddedIamApi ) CreateUser ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamCreateUserResponse , * iamError ) {
var resp iamCreateUserResponse
func ( e * EmbeddedIamApi ) CreateUser ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamCreateUserResponse , * iamError ) {
resp := & iamCreateUserResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
// Validate UserName is not empty
// Validate UserName is not empty
@ -287,8 +290,8 @@ func (e *EmbeddedIamApi) CreateUser(s3cfg *iam_pb.S3ApiConfiguration, values url
}
}
// DeleteUser deletes an IAM user.
// DeleteUser deletes an IAM user.
func ( e * EmbeddedIamApi ) DeleteUser ( s3cfg * iam_pb . S3ApiConfiguration , userName string ) ( iamDeleteUserResponse , * iamError ) {
var resp iamDeleteUserResponse
func ( e * EmbeddedIamApi ) DeleteUser ( s3cfg * iam_pb . S3ApiConfiguration , userName string ) ( * iamDeleteUserResponse , * iamError ) {
resp := & iamDeleteUserResponse { }
for i , ident := range s3cfg . Identities {
for i , ident := range s3cfg . Identities {
if userName == ident . Name {
if userName == ident . Name {
// AWS IAM behavior: prevent deletion if user has service accounts
// AWS IAM behavior: prevent deletion if user has service accounts
@ -308,8 +311,8 @@ func (e *EmbeddedIamApi) DeleteUser(s3cfg *iam_pb.S3ApiConfiguration, userName s
}
}
// GetUser gets an IAM user.
// GetUser gets an IAM user.
func ( e * EmbeddedIamApi ) GetUser ( s3cfg * iam_pb . S3ApiConfiguration , userName string ) ( iamGetUserResponse , * iamError ) {
var resp iamGetUserResponse
func ( e * EmbeddedIamApi ) GetUser ( s3cfg * iam_pb . S3ApiConfiguration , userName string ) ( * iamGetUserResponse , * iamError ) {
resp := & iamGetUserResponse { }
for _ , ident := range s3cfg . Identities {
for _ , ident := range s3cfg . Identities {
if userName == ident . Name {
if userName == ident . Name {
resp . GetUserResult . User = iam . User { UserName : & ident . Name }
resp . GetUserResult . User = iam . User { UserName : & ident . Name }
@ -320,8 +323,8 @@ func (e *EmbeddedIamApi) GetUser(s3cfg *iam_pb.S3ApiConfiguration, userName stri
}
}
// UpdateUser updates an IAM user.
// UpdateUser updates an IAM user.
func ( e * EmbeddedIamApi ) UpdateUser ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamUpdateUserResponse , * iamError ) {
var resp iamUpdateUserResponse
func ( e * EmbeddedIamApi ) UpdateUser ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamUpdateUserResponse , * iamError ) {
resp := & iamUpdateUserResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
newUserName := values . Get ( "NewUserName" )
newUserName := values . Get ( "NewUserName" )
if newUserName != "" {
if newUserName != "" {
@ -338,8 +341,8 @@ func (e *EmbeddedIamApi) UpdateUser(s3cfg *iam_pb.S3ApiConfiguration, values url
}
}
// CreateAccessKey creates an access key for a user.
// CreateAccessKey creates an access key for a user.
func ( e * EmbeddedIamApi ) CreateAccessKey ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamCreateAccessKeyResponse , * iamError ) {
var resp iamCreateAccessKeyResponse
func ( e * EmbeddedIamApi ) CreateAccessKey ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamCreateAccessKeyResponse , * iamError ) {
resp := & iamCreateAccessKeyResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
status := iam . StatusTypeActive
status := iam . StatusTypeActive
@ -372,8 +375,8 @@ func (e *EmbeddedIamApi) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, value
}
}
// DeleteAccessKey deletes an access key for a user.
// DeleteAccessKey deletes an access key for a user.
func ( e * EmbeddedIamApi ) DeleteAccessKey ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) iamDeleteAccessKeyResponse {
var resp iamDeleteAccessKeyResponse
func ( e * EmbeddedIamApi ) DeleteAccessKey ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) * iamDeleteAccessKeyResponse {
resp := & iamDeleteAccessKeyResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
accessKeyId := values . Get ( "AccessKeyId" )
accessKeyId := values . Get ( "AccessKeyId" )
for _ , ident := range s3cfg . Identities {
for _ , ident := range s3cfg . Identities {
@ -400,8 +403,8 @@ func (e *EmbeddedIamApi) GetPolicyDocument(policy *string) (policy_engine.Policy
}
}
// CreatePolicy validates and creates a new IAM managed policy.
// CreatePolicy validates and creates a new IAM managed policy.
func ( e * EmbeddedIamApi ) CreatePolicy ( ctx context . Context , values url . Values ) ( iamCreatePolicyResponse , * iamError ) {
var resp iamCreatePolicyResponse
func ( e * EmbeddedIamApi ) CreatePolicy ( ctx context . Context , values url . Values ) ( * iamCreatePolicyResponse , * iamError ) {
resp := & iamCreatePolicyResponse { }
policyName := values . Get ( "PolicyName" )
policyName := values . Get ( "PolicyName" )
policyDocumentString := values . Get ( "PolicyDocument" )
policyDocumentString := values . Get ( "PolicyDocument" )
if policyName == "" {
if policyName == "" {
@ -443,8 +446,8 @@ func (e *EmbeddedIamApi) CreatePolicy(ctx context.Context, values url.Values) (i
}
}
// DeletePolicy deletes a managed policy by ARN.
// DeletePolicy deletes a managed policy by ARN.
func ( e * EmbeddedIamApi ) DeletePolicy ( ctx context . Context , values url . Values ) ( iamDeletePolicyResponse , * iamError ) {
var resp iamDeletePolicyResponse
func ( e * EmbeddedIamApi ) DeletePolicy ( ctx context . Context , values url . Values ) ( * iamDeletePolicyResponse , * iamError ) {
resp := & iamDeletePolicyResponse { }
policyArn := values . Get ( "PolicyArn" )
policyArn := values . Get ( "PolicyArn" )
policyName , err := iamPolicyNameFromArn ( policyArn )
policyName , err := iamPolicyNameFromArn ( policyArn )
if err != nil {
if err != nil {
@ -485,8 +488,8 @@ func (e *EmbeddedIamApi) DeletePolicy(ctx context.Context, values url.Values) (i
}
}
// ListPolicies lists managed policies.
// ListPolicies lists managed policies.
func ( e * EmbeddedIamApi ) ListPolicies ( ctx context . Context , values url . Values ) ( iamListPoliciesResponse , * iamError ) {
var resp iamListPoliciesResponse
func ( e * EmbeddedIamApi ) ListPolicies ( ctx context . Context , values url . Values ) ( * iamListPoliciesResponse , * iamError ) {
resp := & iamListPoliciesResponse { }
pathPrefix := values . Get ( "PathPrefix" )
pathPrefix := values . Get ( "PathPrefix" )
if pathPrefix == "" {
if pathPrefix == "" {
pathPrefix = "/"
pathPrefix = "/"
@ -558,8 +561,8 @@ func (e *EmbeddedIamApi) ListPolicies(ctx context.Context, values url.Values) (i
}
}
// GetPolicy returns metadata for a managed policy.
// GetPolicy returns metadata for a managed policy.
func ( e * EmbeddedIamApi ) GetPolicy ( ctx context . Context , values url . Values ) ( iamGetPolicyResponse , * iamError ) {
var resp iamGetPolicyResponse
func ( e * EmbeddedIamApi ) GetPolicy ( ctx context . Context , values url . Values ) ( * iamGetPolicyResponse , * iamError ) {
resp := & iamGetPolicyResponse { }
policyArn := values . Get ( "PolicyArn" )
policyArn := values . Get ( "PolicyArn" )
policyName , err := iamPolicyNameFromArn ( policyArn )
policyName , err := iamPolicyNameFromArn ( policyArn )
if err != nil {
if err != nil {
@ -595,8 +598,8 @@ func (e *EmbeddedIamApi) GetPolicy(ctx context.Context, values url.Values) (iamG
// ListPolicyVersions lists versions for a managed policy.
// ListPolicyVersions lists versions for a managed policy.
// Current SeaweedFS implementation stores one version per policy (v1).
// Current SeaweedFS implementation stores one version per policy (v1).
func ( e * EmbeddedIamApi ) ListPolicyVersions ( ctx context . Context , values url . Values ) ( iamListPolicyVersionsResponse , * iamError ) {
var resp iamListPolicyVersionsResponse
func ( e * EmbeddedIamApi ) ListPolicyVersions ( ctx context . Context , values url . Values ) ( * iamListPolicyVersionsResponse , * iamError ) {
resp := & iamListPolicyVersionsResponse { }
policyArn := values . Get ( "PolicyArn" )
policyArn := values . Get ( "PolicyArn" )
policyName , err := iamPolicyNameFromArn ( policyArn )
policyName , err := iamPolicyNameFromArn ( policyArn )
if err != nil {
if err != nil {
@ -625,8 +628,8 @@ func (e *EmbeddedIamApi) ListPolicyVersions(ctx context.Context, values url.Valu
// GetPolicyVersion returns the document for a specific policy version.
// GetPolicyVersion returns the document for a specific policy version.
// Current SeaweedFS implementation stores one version per policy (v1).
// Current SeaweedFS implementation stores one version per policy (v1).
func ( e * EmbeddedIamApi ) GetPolicyVersion ( ctx context . Context , values url . Values ) ( iamGetPolicyVersionResponse , * iamError ) {
var resp iamGetPolicyVersionResponse
func ( e * EmbeddedIamApi ) GetPolicyVersion ( ctx context . Context , values url . Values ) ( * iamGetPolicyVersionResponse , * iamError ) {
resp := & iamGetPolicyVersionResponse { }
policyArn := values . Get ( "PolicyArn" )
policyArn := values . Get ( "PolicyArn" )
versionID := values . Get ( "VersionId" )
versionID := values . Get ( "VersionId" )
if versionID == "" {
if versionID == "" {
@ -754,8 +757,8 @@ func (e *EmbeddedIamApi) getActions(policy *policy_engine.PolicyDocument) ([]str
}
}
// PutUserPolicy attaches a policy to a user.
// PutUserPolicy attaches a policy to a user.
func ( e * EmbeddedIamApi ) PutUserPolicy ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamPutUserPolicyResponse , * iamError ) {
var resp iamPutUserPolicyResponse
func ( e * EmbeddedIamApi ) PutUserPolicy ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamPutUserPolicyResponse , * iamError ) {
resp := & iamPutUserPolicyResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
policyDocumentString := values . Get ( "PolicyDocument" )
policyDocumentString := values . Get ( "PolicyDocument" )
policyDocument , err := e . GetPolicyDocument ( & policyDocumentString )
policyDocument , err := e . GetPolicyDocument ( & policyDocumentString )
@ -778,8 +781,8 @@ func (e *EmbeddedIamApi) PutUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values
}
}
// GetUserPolicy gets the policy attached to a user.
// GetUserPolicy gets the policy attached to a user.
func ( e * EmbeddedIamApi ) GetUserPolicy ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamGetUserPolicyResponse , * iamError ) {
var resp iamGetUserPolicyResponse
func ( e * EmbeddedIamApi ) GetUserPolicy ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamGetUserPolicyResponse , * iamError ) {
resp := & iamGetUserPolicyResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
policyName := values . Get ( "PolicyName" )
policyName := values . Get ( "PolicyName" )
for _ , ident := range s3cfg . Identities {
for _ , ident := range s3cfg . Identities {
@ -845,8 +848,8 @@ func (e *EmbeddedIamApi) GetUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, values
}
}
// DeleteUserPolicy removes the inline policy from a user (clears their actions).
// DeleteUserPolicy removes the inline policy from a user (clears their actions).
func ( e * EmbeddedIamApi ) DeleteUserPolicy ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamDeleteUserPolicyResponse , * iamError ) {
var resp iamDeleteUserPolicyResponse
func ( e * EmbeddedIamApi ) DeleteUserPolicy ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamDeleteUserPolicyResponse , * iamError ) {
resp := & iamDeleteUserPolicyResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
for _ , ident := range s3cfg . Identities {
for _ , ident := range s3cfg . Identities {
if ident . Name == userName {
if ident . Name == userName {
@ -858,8 +861,8 @@ func (e *EmbeddedIamApi) DeleteUserPolicy(s3cfg *iam_pb.S3ApiConfiguration, valu
}
}
// AttachUserPolicy attaches a managed policy to a user.
// AttachUserPolicy attaches a managed policy to a user.
func ( e * EmbeddedIamApi ) AttachUserPolicy ( ctx context . Context , values url . Values ) ( iamAttachUserPolicyResponse , * iamError ) {
var resp iamAttachUserPolicyResponse
func ( e * EmbeddedIamApi ) AttachUserPolicy ( ctx context . Context , values url . Values ) ( * iamAttachUserPolicyResponse , * iamError ) {
resp := & iamAttachUserPolicyResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
if userName == "" {
if userName == "" {
@ -926,8 +929,8 @@ func (e *EmbeddedIamApi) AttachUserPolicy(ctx context.Context, values url.Values
}
}
// DetachUserPolicy detaches a managed policy from a user.
// DetachUserPolicy detaches a managed policy from a user.
func ( e * EmbeddedIamApi ) DetachUserPolicy ( ctx context . Context , values url . Values ) ( iamDetachUserPolicyResponse , * iamError ) {
var resp iamDetachUserPolicyResponse
func ( e * EmbeddedIamApi ) DetachUserPolicy ( ctx context . Context , values url . Values ) ( * iamDetachUserPolicyResponse , * iamError ) {
resp := & iamDetachUserPolicyResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
if userName == "" {
if userName == "" {
@ -971,8 +974,8 @@ func (e *EmbeddedIamApi) DetachUserPolicy(ctx context.Context, values url.Values
}
}
// ListAttachedUserPolicies lists managed policies attached to a user.
// ListAttachedUserPolicies lists managed policies attached to a user.
func ( e * EmbeddedIamApi ) ListAttachedUserPolicies ( ctx context . Context , values url . Values ) ( iamListAttachedUserPoliciesResponse , * iamError ) {
var resp iamListAttachedUserPoliciesResponse
func ( e * EmbeddedIamApi ) ListAttachedUserPolicies ( ctx context . Context , values url . Values ) ( * iamListAttachedUserPoliciesResponse , * iamError ) {
resp := & iamListAttachedUserPoliciesResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
if userName == "" {
if userName == "" {
@ -1056,8 +1059,8 @@ func (e *EmbeddedIamApi) ListAttachedUserPolicies(ctx context.Context, values ur
// SetUserStatus enables or disables a user without deleting them.
// SetUserStatus enables or disables a user without deleting them.
// This is a SeaweedFS extension for temporary user suspension, offboarding, etc.
// This is a SeaweedFS extension for temporary user suspension, offboarding, etc.
// When a user is disabled, all API requests using their credentials will return AccessDenied.
// When a user is disabled, all API requests using their credentials will return AccessDenied.
func ( e * EmbeddedIamApi ) SetUserStatus ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamSetUserStatusResponse , * iamError ) {
var resp iamSetUserStatusResponse
func ( e * EmbeddedIamApi ) SetUserStatus ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamSetUserStatusResponse , * iamError ) {
resp := & iamSetUserStatusResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
status := values . Get ( "Status" )
status := values . Get ( "Status" )
@ -1083,8 +1086,8 @@ func (e *EmbeddedIamApi) SetUserStatus(s3cfg *iam_pb.S3ApiConfiguration, values
// UpdateAccessKey updates the status of an access key (Active or Inactive).
// UpdateAccessKey updates the status of an access key (Active or Inactive).
// This allows key rotation workflows where old keys are deactivated before deletion.
// This allows key rotation workflows where old keys are deactivated before deletion.
func ( e * EmbeddedIamApi ) UpdateAccessKey ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamUpdateAccessKeyResponse , * iamError ) {
var resp iamUpdateAccessKeyResponse
func ( e * EmbeddedIamApi ) UpdateAccessKey ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamUpdateAccessKeyResponse , * iamError ) {
resp := & iamUpdateAccessKeyResponse { }
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
accessKeyId := values . Get ( "AccessKeyId" )
accessKeyId := values . Get ( "AccessKeyId" )
status := values . Get ( "Status" )
status := values . Get ( "Status" )
@ -1129,8 +1132,8 @@ func findIdentityByName(s3cfg *iam_pb.S3ApiConfiguration, name string) *iam_pb.I
}
}
// CreateServiceAccount creates a new service account for a user.
// CreateServiceAccount creates a new service account for a user.
func ( e * EmbeddedIamApi ) CreateServiceAccount ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values , createdBy string ) ( iamCreateServiceAccountResponse , * iamError ) {
var resp iamCreateServiceAccountResponse
func ( e * EmbeddedIamApi ) CreateServiceAccount ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values , createdBy string ) ( * iamCreateServiceAccountResponse , * iamError ) {
resp := & iamCreateServiceAccountResponse { }
parentUser := values . Get ( "ParentUser" )
parentUser := values . Get ( "ParentUser" )
description := values . Get ( "Description" )
description := values . Get ( "Description" )
expirationStr := values . Get ( "Expiration" ) // Unix timestamp as string
expirationStr := values . Get ( "Expiration" ) // Unix timestamp as string
@ -1239,8 +1242,8 @@ func (e *EmbeddedIamApi) CreateServiceAccount(s3cfg *iam_pb.S3ApiConfiguration,
}
}
// DeleteServiceAccount deletes a service account.
// DeleteServiceAccount deletes a service account.
func ( e * EmbeddedIamApi ) DeleteServiceAccount ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamDeleteServiceAccountResponse , * iamError ) {
var resp iamDeleteServiceAccountResponse
func ( e * EmbeddedIamApi ) DeleteServiceAccount ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamDeleteServiceAccountResponse , * iamError ) {
resp := & iamDeleteServiceAccountResponse { }
saId := values . Get ( "ServiceAccountId" )
saId := values . Get ( "ServiceAccountId" )
if saId == "" {
if saId == "" {
@ -1272,8 +1275,8 @@ func (e *EmbeddedIamApi) DeleteServiceAccount(s3cfg *iam_pb.S3ApiConfiguration,
}
}
// ListServiceAccounts lists service accounts, optionally filtered by parent user.
// ListServiceAccounts lists service accounts, optionally filtered by parent user.
func ( e * EmbeddedIamApi ) ListServiceAccounts ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) iamListServiceAccountsResponse {
var resp iamListServiceAccountsResponse
func ( e * EmbeddedIamApi ) ListServiceAccounts ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) * iamListServiceAccountsResponse {
resp := & iamListServiceAccountsResponse { }
parentUser := values . Get ( "ParentUser" ) // Optional filter
parentUser := values . Get ( "ParentUser" ) // Optional filter
for _ , sa := range s3cfg . ServiceAccounts {
for _ , sa := range s3cfg . ServiceAccounts {
@ -1307,8 +1310,8 @@ func (e *EmbeddedIamApi) ListServiceAccounts(s3cfg *iam_pb.S3ApiConfiguration, v
}
}
// GetServiceAccount retrieves a service account by ID.
// GetServiceAccount retrieves a service account by ID.
func ( e * EmbeddedIamApi ) GetServiceAccount ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamGetServiceAccountResponse , * iamError ) {
var resp iamGetServiceAccountResponse
func ( e * EmbeddedIamApi ) GetServiceAccount ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamGetServiceAccountResponse , * iamError ) {
resp := & iamGetServiceAccountResponse { }
saId := values . Get ( "ServiceAccountId" )
saId := values . Get ( "ServiceAccountId" )
if saId == "" {
if saId == "" {
@ -1344,8 +1347,8 @@ func (e *EmbeddedIamApi) GetServiceAccount(s3cfg *iam_pb.S3ApiConfiguration, val
}
}
// UpdateServiceAccount updates a service account's status, description, or expiration.
// UpdateServiceAccount updates a service account's status, description, or expiration.
func ( e * EmbeddedIamApi ) UpdateServiceAccount ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( iamUpdateServiceAccountResponse , * iamError ) {
var resp iamUpdateServiceAccountResponse
func ( e * EmbeddedIamApi ) UpdateServiceAccount ( s3cfg * iam_pb . S3ApiConfiguration , values url . Values ) ( * iamUpdateServiceAccountResponse , * iamError ) {
resp := & iamUpdateServiceAccountResponse { }
saId := values . Get ( "ServiceAccountId" )
saId := values . Get ( "ServiceAccountId" )
newStatus := values . Get ( "Status" )
newStatus := values . Get ( "Status" )
newDescription := values . Get ( "Description" )
newDescription := values . Get ( "Description" )
@ -1543,7 +1546,11 @@ func (e *EmbeddedIamApi) AuthIam(f http.HandlerFunc, _ Action) http.HandlerFunc
// ExecuteAction executes an IAM action with the given values.
// ExecuteAction executes an IAM action with the given values.
// If skipPersist is true, the changed configuration is not saved to the persistent store.
// If skipPersist is true, the changed configuration is not saved to the persistent store.
func ( e * EmbeddedIamApi ) ExecuteAction ( ctx context . Context , values url . Values , skipPersist bool ) ( interface { } , * iamError ) {
// reqID is set on the response; if empty, a new request ID is generated.
func ( e * EmbeddedIamApi ) ExecuteAction ( ctx context . Context , values url . Values , skipPersist bool , reqID string ) ( iamlib . RequestIDSetter , * iamError ) {
if reqID == "" {
reqID = request_id . New ( )
}
// Lock to prevent concurrent read-modify-write race conditions
// Lock to prevent concurrent read-modify-write race conditions
e . policyLock . Lock ( )
e . policyLock . Lock ( )
defer e . policyLock . Unlock ( )
defer e . policyLock . Unlock ( )
@ -1564,8 +1571,7 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
}
}
glog . V ( 4 ) . Infof ( "IAM ExecuteAction: %+v" , values )
glog . V ( 4 ) . Infof ( "IAM ExecuteAction: %+v" , values )
var response interface { }
var iamErr * iamError
var response iamlib . RequestIDSetter
changed := true
changed := true
switch values . Get ( "Action" ) {
switch values . Get ( "Action" ) {
case "ListUsers" :
case "ListUsers" :
@ -1577,29 +1583,34 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
response = e . ListAccessKeys ( s3cfg , values )
response = e . ListAccessKeys ( s3cfg , values )
changed = false
changed = false
case "CreateUser" :
case "CreateUser" :
var iamErr * iamError
response , iamErr = e . CreateUser ( s3cfg , values )
response , iamErr = e . CreateUser ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
case "GetUser" :
case "GetUser" :
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
var iamErr * iamError
response , iamErr = e . GetUser ( s3cfg , userName )
response , iamErr = e . GetUser ( s3cfg , userName )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "UpdateUser" :
case "UpdateUser" :
var iamErr * iamError
response , iamErr = e . UpdateUser ( s3cfg , values )
response , iamErr = e . UpdateUser ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
case "DeleteUser" :
case "DeleteUser" :
userName := values . Get ( "UserName" )
userName := values . Get ( "UserName" )
var iamErr * iamError
response , iamErr = e . DeleteUser ( s3cfg , userName )
response , iamErr = e . DeleteUser ( s3cfg , userName )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
case "CreateAccessKey" :
case "CreateAccessKey" :
var iamErr * iamError
response , iamErr = e . CreateAccessKey ( s3cfg , values )
response , iamErr = e . CreateAccessKey ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
glog . Errorf ( "CreateAccessKey: %+v" , iamErr . Error )
glog . Errorf ( "CreateAccessKey: %+v" , iamErr . Error )
@ -1608,6 +1619,7 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
case "DeleteAccessKey" :
case "DeleteAccessKey" :
response = e . DeleteAccessKey ( s3cfg , values )
response = e . DeleteAccessKey ( s3cfg , values )
case "CreatePolicy" :
case "CreatePolicy" :
var iamErr * iamError
response , iamErr = e . CreatePolicy ( ctx , values )
response , iamErr = e . CreatePolicy ( ctx , values )
if iamErr != nil {
if iamErr != nil {
glog . Errorf ( "CreatePolicy: %+v" , iamErr . Error )
glog . Errorf ( "CreatePolicy: %+v" , iamErr . Error )
@ -1615,6 +1627,7 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
}
}
changed = false
changed = false
case "DeletePolicy" :
case "DeletePolicy" :
var iamErr * iamError
response , iamErr = e . DeletePolicy ( ctx , values )
response , iamErr = e . DeletePolicy ( ctx , values )
if iamErr != nil {
if iamErr != nil {
glog . Errorf ( "DeletePolicy: %+v" , iamErr . Error )
glog . Errorf ( "DeletePolicy: %+v" , iamErr . Error )
@ -1622,70 +1635,82 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
}
}
changed = false
changed = false
case "PutUserPolicy" :
case "PutUserPolicy" :
var iamErr * iamError
response , iamErr = e . PutUserPolicy ( s3cfg , values )
response , iamErr = e . PutUserPolicy ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
glog . Errorf ( "PutUserPolicy: %+v" , iamErr . Error )
glog . Errorf ( "PutUserPolicy: %+v" , iamErr . Error )
return nil , iamErr
return nil , iamErr
}
}
case "GetUserPolicy" :
case "GetUserPolicy" :
var iamErr * iamError
response , iamErr = e . GetUserPolicy ( s3cfg , values )
response , iamErr = e . GetUserPolicy ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "DeleteUserPolicy" :
case "DeleteUserPolicy" :
var iamErr * iamError
response , iamErr = e . DeleteUserPolicy ( s3cfg , values )
response , iamErr = e . DeleteUserPolicy ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
case "AttachUserPolicy" :
case "AttachUserPolicy" :
var iamErr * iamError
response , iamErr = e . AttachUserPolicy ( ctx , values )
response , iamErr = e . AttachUserPolicy ( ctx , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "DetachUserPolicy" :
case "DetachUserPolicy" :
var iamErr * iamError
response , iamErr = e . DetachUserPolicy ( ctx , values )
response , iamErr = e . DetachUserPolicy ( ctx , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "ListAttachedUserPolicies" :
case "ListAttachedUserPolicies" :
var iamErr * iamError
response , iamErr = e . ListAttachedUserPolicies ( ctx , values )
response , iamErr = e . ListAttachedUserPolicies ( ctx , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "ListPolicies" :
case "ListPolicies" :
var iamErr * iamError
response , iamErr = e . ListPolicies ( ctx , values )
response , iamErr = e . ListPolicies ( ctx , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "GetPolicy" :
case "GetPolicy" :
var iamErr * iamError
response , iamErr = e . GetPolicy ( ctx , values )
response , iamErr = e . GetPolicy ( ctx , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "ListPolicyVersions" :
case "ListPolicyVersions" :
var iamErr * iamError
response , iamErr = e . ListPolicyVersions ( ctx , values )
response , iamErr = e . ListPolicyVersions ( ctx , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "GetPolicyVersion" :
case "GetPolicyVersion" :
var iamErr * iamError
response , iamErr = e . GetPolicyVersion ( ctx , values )
response , iamErr = e . GetPolicyVersion ( ctx , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "SetUserStatus" :
case "SetUserStatus" :
var iamErr * iamError
response , iamErr = e . SetUserStatus ( s3cfg , values )
response , iamErr = e . SetUserStatus ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
case "UpdateAccessKey" :
case "UpdateAccessKey" :
var iamErr * iamError
response , iamErr = e . UpdateAccessKey ( s3cfg , values )
response , iamErr = e . UpdateAccessKey ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
@ -1693,11 +1718,13 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
// Service Account actions
// Service Account actions
case "CreateServiceAccount" :
case "CreateServiceAccount" :
createdBy := values . Get ( "CreatedBy" )
createdBy := values . Get ( "CreatedBy" )
var iamErr * iamError
response , iamErr = e . CreateServiceAccount ( s3cfg , values , createdBy )
response , iamErr = e . CreateServiceAccount ( s3cfg , values , createdBy )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
case "DeleteServiceAccount" :
case "DeleteServiceAccount" :
var iamErr * iamError
response , iamErr = e . DeleteServiceAccount ( s3cfg , values )
response , iamErr = e . DeleteServiceAccount ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
@ -1706,12 +1733,14 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
response = e . ListServiceAccounts ( s3cfg , values )
response = e . ListServiceAccounts ( s3cfg , values )
changed = false
changed = false
case "GetServiceAccount" :
case "GetServiceAccount" :
var iamErr * iamError
response , iamErr = e . GetServiceAccount ( s3cfg , values )
response , iamErr = e . GetServiceAccount ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
}
}
changed = false
changed = false
case "UpdateServiceAccount" :
case "UpdateServiceAccount" :
var iamErr * iamError
response , iamErr = e . UpdateServiceAccount ( s3cfg , values )
response , iamErr = e . UpdateServiceAccount ( s3cfg , values )
if iamErr != nil {
if iamErr != nil {
return nil , iamErr
return nil , iamErr
@ -1722,8 +1751,7 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
if changed {
if changed {
if ! skipPersist {
if ! skipPersist {
if err := e . PutS3ApiConfiguration ( s3cfg ) ; err != nil {
if err := e . PutS3ApiConfiguration ( s3cfg ) ; err != nil {
iamErr = & iamError { Code : iam . ErrCodeServiceFailureException , Error : err }
return nil , iamErr
return nil , & iamError { Code : iam . ErrCodeServiceFailureException , Error : err }
}
}
}
}
// Reload in-memory identity maps so subsequent LookupByAccessKey calls
// Reload in-memory identity maps so subsequent LookupByAccessKey calls
@ -1739,11 +1767,13 @@ func (e *EmbeddedIamApi) ExecuteAction(ctx context.Context, values url.Values, s
glog . Errorf ( "Failed to reload IAM configuration after managed policy mutation: %v" , err )
glog . Errorf ( "Failed to reload IAM configuration after managed policy mutation: %v" , err )
}
}
}
}
return response , iamErr
response . SetRequestId ( reqID )
return response , nil
}
}
// DoActions handles IAM API actions.
// DoActions handles IAM API actions.
func ( e * EmbeddedIamApi ) DoActions ( w http . ResponseWriter , r * http . Request ) {
func ( e * EmbeddedIamApi ) DoActions ( w http . ResponseWriter , r * http . Request ) {
r , reqID := request_id . Ensure ( r )
if err := r . ParseForm ( ) ; err != nil {
if err := r . ParseForm ( ) ; err != nil {
s3err . WriteErrorResponse ( w , r , s3err . ErrInvalidRequest )
s3err . WriteErrorResponse ( w , r , s3err . ErrInvalidRequest )
return
return
@ -1759,15 +1789,11 @@ func (e *EmbeddedIamApi) DoActions(w http.ResponseWriter, r *http.Request) {
values . Set ( "CreatedBy" , createdBy )
values . Set ( "CreatedBy" , createdBy )
}
}
response , iamErr := e . ExecuteAction ( r . Context ( ) , values , false )
response , iamErr := e . ExecuteAction ( r . Context ( ) , values , false , reqID )
if iamErr != nil {
if iamErr != nil {
e . writeIamErrorResponse ( w , r , iamErr )
e . writeIamErrorResponse ( w , r , reqID , iamErr )
return
return
}
}
// Set RequestId for AWS compatibility
if r , ok := response . ( interface { SetRequestId ( ) } ) ; ok {
r . SetRequestId ( )
}
s3err . WriteXMLResponse ( w , r , http . StatusOK , response )
s3err . WriteXMLResponse ( w , r , http . StatusOK , response )
}
}