Add UpdateAccessKey support to IAM API (#8342)
* Add UpdateAccessKey support to IAM API * simplify
This commit is contained in:
@@ -34,7 +34,7 @@ func writeIamErrorResponse(w http.ResponseWriter, r *http.Request, iamError *Iam
|
||||
switch errCode {
|
||||
case iam.ErrCodeNoSuchEntityException:
|
||||
s3err.WriteXMLResponse(w, r, http.StatusNotFound, errorResp)
|
||||
case iam.ErrCodeMalformedPolicyDocumentException:
|
||||
case iam.ErrCodeMalformedPolicyDocumentException, iam.ErrCodeInvalidInputException:
|
||||
s3err.WriteXMLResponse(w, r, http.StatusBadRequest, errorResp)
|
||||
case iam.ErrCodeServiceFailureException:
|
||||
// We do not want to expose internal server error to the client
|
||||
|
||||
@@ -35,6 +35,8 @@ const (
|
||||
StatementActionTagging = iamlib.StatementActionTagging
|
||||
StatementActionDelete = iamlib.StatementActionDelete
|
||||
USER_DOES_NOT_EXIST = iamlib.UserDoesNotExist
|
||||
accessKeyStatusActive = iamlib.AccessKeyStatusActive
|
||||
accessKeyStatusInactive = iamlib.AccessKeyStatusInactive
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -67,6 +69,17 @@ func stringSlicesEqual(a, b []string) bool {
|
||||
return iamlib.StringSlicesEqual(a, b)
|
||||
}
|
||||
|
||||
func validateAccessKeyStatus(status string) error {
|
||||
switch status {
|
||||
case accessKeyStatusActive, accessKeyStatusInactive:
|
||||
return nil
|
||||
case "":
|
||||
return fmt.Errorf("Status parameter is required")
|
||||
default:
|
||||
return fmt.Errorf("Status must be '%s' or '%s'", accessKeyStatusActive, accessKeyStatusInactive)
|
||||
}
|
||||
}
|
||||
|
||||
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})
|
||||
@@ -75,15 +88,20 @@ func (iama *IamApiServer) ListUsers(s3cfg *iam_pb.S3ApiConfiguration, values url
|
||||
}
|
||||
|
||||
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 {
|
||||
status := cred.Status
|
||||
if status == "" {
|
||||
status = accessKeyStatusActive
|
||||
}
|
||||
identName := ident.Name
|
||||
accessKey := cred.AccessKey
|
||||
resp.ListAccessKeysResult.AccessKeyMetadata = append(resp.ListAccessKeysResult.AccessKeyMetadata,
|
||||
&iam.AccessKeyMetadata{UserName: &ident.Name, AccessKeyId: &cred.AccessKey, Status: &status},
|
||||
&iam.AccessKeyMetadata{UserName: &identName, AccessKeyId: &accessKey, Status: &status},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -325,7 +343,7 @@ func (iama *IamApiServer) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, valu
|
||||
for _, ident := range s3cfg.Identities {
|
||||
if userName == ident.Name {
|
||||
ident.Credentials = append(ident.Credentials,
|
||||
&iam_pb.Credential{AccessKey: accessKeyId, SecretKey: secretAccessKey})
|
||||
&iam_pb.Credential{AccessKey: accessKeyId, SecretKey: secretAccessKey, Status: accessKeyStatusActive})
|
||||
changed = true
|
||||
break
|
||||
}
|
||||
@@ -338,6 +356,7 @@ func (iama *IamApiServer) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, valu
|
||||
{
|
||||
AccessKey: accessKeyId,
|
||||
SecretKey: secretAccessKey,
|
||||
Status: accessKeyStatusActive,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -346,6 +365,37 @@ func (iama *IamApiServer) CreateAccessKey(s3cfg *iam_pb.S3ApiConfiguration, valu
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
userName := values.Get("UserName")
|
||||
accessKeyId := values.Get("AccessKeyId")
|
||||
status := values.Get("Status")
|
||||
|
||||
if userName == "" {
|
||||
return resp, &IamError{Code: iam.ErrCodeInvalidInputException, Error: fmt.Errorf("UserName is required")}
|
||||
}
|
||||
if accessKeyId == "" {
|
||||
return resp, &IamError{Code: iam.ErrCodeInvalidInputException, Error: fmt.Errorf("AccessKeyId is required")}
|
||||
}
|
||||
if err := validateAccessKeyStatus(status); err != nil {
|
||||
return resp, &IamError{Code: iam.ErrCodeInvalidInputException, Error: err}
|
||||
}
|
||||
|
||||
for _, ident := range s3cfg.Identities {
|
||||
if ident.Name != userName {
|
||||
continue
|
||||
}
|
||||
for _, cred := range ident.Credentials {
|
||||
if cred.AccessKey == accessKeyId {
|
||||
cred.Status = status
|
||||
return resp, nil
|
||||
}
|
||||
}
|
||||
return resp, &IamError{Code: iam.ErrCodeNoSuchEntityException, Error: fmt.Errorf("the access key with id %s for user %s cannot be found", accessKeyId, userName)}
|
||||
}
|
||||
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) {
|
||||
userName := values.Get("UserName")
|
||||
accessKeyId := values.Get("AccessKeyId")
|
||||
@@ -475,6 +525,13 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||
case "DeleteAccessKey":
|
||||
iama.handleImplicitUsername(r, values)
|
||||
response = iama.DeleteAccessKey(s3cfg, values)
|
||||
case "UpdateAccessKey":
|
||||
iama.handleImplicitUsername(r, values)
|
||||
response, iamError = iama.UpdateAccessKey(s3cfg, values)
|
||||
if iamError != nil {
|
||||
writeIamErrorResponse(w, r, iamError)
|
||||
return
|
||||
}
|
||||
case "CreatePolicy":
|
||||
response, iamError = iama.CreatePolicy(s3cfg, values)
|
||||
if iamError != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ type (
|
||||
GetUserResponse = iamlib.GetUserResponse
|
||||
UpdateUserResponse = iamlib.UpdateUserResponse
|
||||
CreateAccessKeyResponse = iamlib.CreateAccessKeyResponse
|
||||
UpdateAccessKeyResponse = iamlib.UpdateAccessKeyResponse
|
||||
PutUserPolicyResponse = iamlib.PutUserPolicyResponse
|
||||
DeleteUserPolicyResponse = iamlib.DeleteUserPolicyResponse
|
||||
GetUserPolicyResponse = iamlib.GetUserPolicyResponse
|
||||
|
||||
@@ -84,6 +84,58 @@ func TestListAccessKeys(t *testing.T) {
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
}
|
||||
|
||||
func TestUpdateAccessKey(t *testing.T) {
|
||||
svc := iam.New(session.New())
|
||||
|
||||
createReq, _ := svc.CreateAccessKeyRequest(&iam.CreateAccessKeyInput{UserName: aws.String("Test")})
|
||||
_ = createReq.Build()
|
||||
createOut := CreateAccessKeyResponse{}
|
||||
response, err := executeRequest(createReq.HTTPRequest, createOut)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
var createResp CreateAccessKeyResponse
|
||||
err = xml.Unmarshal(response.Body.Bytes(), &createResp)
|
||||
assert.Equal(t, nil, err)
|
||||
accessKeyId := createResp.CreateAccessKeyResult.AccessKey.AccessKeyId
|
||||
if accessKeyId == nil {
|
||||
t.Fatalf("expected access key id to be set")
|
||||
}
|
||||
|
||||
updateReq, _ := svc.UpdateAccessKeyRequest(&iam.UpdateAccessKeyInput{
|
||||
UserName: aws.String("Test"),
|
||||
AccessKeyId: accessKeyId,
|
||||
Status: aws.String("Inactive"),
|
||||
})
|
||||
_ = updateReq.Build()
|
||||
updateOut := UpdateAccessKeyResponse{}
|
||||
response, err = executeRequest(updateReq.HTTPRequest, updateOut)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
listReq, _ := svc.ListAccessKeysRequest(&iam.ListAccessKeysInput{UserName: aws.String("Test")})
|
||||
_ = listReq.Build()
|
||||
listOut := ListAccessKeysResponse{}
|
||||
response, err = executeRequest(listReq.HTTPRequest, listOut)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
var listResp ListAccessKeysResponse
|
||||
err = xml.Unmarshal(response.Body.Bytes(), &listResp)
|
||||
assert.Equal(t, nil, err)
|
||||
found := false
|
||||
for _, key := range listResp.ListAccessKeysResult.AccessKeyMetadata {
|
||||
if key.AccessKeyId != nil && *key.AccessKeyId == *accessKeyId {
|
||||
found = true
|
||||
if assert.NotNil(t, key.Status) {
|
||||
assert.Equal(t, "Inactive", *key.Status)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
}
|
||||
|
||||
func TestGetUser(t *testing.T) {
|
||||
userName := aws.String("Test")
|
||||
params := &iam.GetUserInput{UserName: userName}
|
||||
|
||||
Reference in New Issue
Block a user