Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/server/system_services/account_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -1394,10 +1394,11 @@ async function update_access_key(req) {
async function get_access_key_last_used(req) {
const action = IAM_ACTIONS.GET_ACCESS_KEY_LAST_USED;
const requesting_account = req.account;
const requested_account = account_util.validate_and_return_requested_account(req.rpc_params, action, requesting_account);
const access_key_id = req.rpc_params.access_key;
const requested_account = account_util._check_if_iam_user_belongs_to_account_owner_by_access_key(
action, requesting_account, access_key_id);
const dummy_region = 'us-west-2';
const dummy_service_name = 's3';
account_util._check_access_key_belongs_to_account(action, requesting_account, req.rpc_params.access_key);
// TODO: Need to return valid last_used_date date, Low priority.
return {
region: dummy_region, // GAP
Expand Down
68 changes: 66 additions & 2 deletions src/test/integration_tests/api/iam/test_iam_basic_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,6 @@ mocha.describe('IAM integration tests', async function() {
});

mocha.it('get access key (last used)', async function() {
// Skipping for containerized noobaa
if (!is_nc_coretest) this.skip(); // eslint-disable-line no-invalid-this
const input = {
AccessKeyId: access_key_id
};
Expand Down Expand Up @@ -1057,6 +1055,39 @@ mocha.describe('IAM integration tests', async function() {
});

});

mocha.describe('IAM Access Keys API', async function() {
const username2 = 'Alejandro';
let access_key_id;

mocha.describe('IAM GetAccessKeyLastUsed API', async function() {
mocha.before(async () => {
await create_iam_user(username2);
const res = await create_access_key_iam_user(username2);
access_key_id = res.access_key_id;
});

mocha.after(async () => {
await delete_access_key_iam_user(access_key_id, username2);
await delete_iam_user(username2);
});

mocha.it('get access key last used with invalid access key ID should fail', async function() {
const access_key_id_invalid = access_key_id + '0';
try {
const input = {
AccessKeyId: access_key_id_invalid
};
const command = new GetAccessKeyLastUsedCommand(input);
await iam_account.send(command);
assert.fail('get access key last used with invalid access key ID - should throw an error');
} catch (err) {
const err_code = err.Error.Code;
assert.equal(err_code, IamError.NoSuchEntity.code);
}
});
});
});
});
});

Expand Down Expand Up @@ -1095,3 +1126,36 @@ async function delete_iam_user(username_to_delete) {
const response = await iam_account.send(command);
_check_status_code_ok(response);
}


/**
* Create an IAM user's access key with the given username.
* use this function for before/after hooks to avoid code duplication
* @param {string} username
*/
async function create_access_key_iam_user(username) {
const input = {
UserName: username
};
const command = new CreateAccessKeyCommand(input);
const response = await iam_account.send(command);
_check_status_code_ok(response);
return { access_key_id: response.AccessKey.AccessKeyId, secret_access_key: response.AccessKey.SecretAccessKey };
}


/**
* Delete an IAM user's access key with the given access key ID and username.
* use this function for before/after hooks to avoid code duplication
* @param {string} access_key_to_delete
* @param {string} username
*/
async function delete_access_key_iam_user(access_key_to_delete, username) {
const input = {
UserName: username,
AccessKeyId: access_key_to_delete
};
const command = new DeleteAccessKeyCommand(input);
const response = await iam_account.send(command);
_check_status_code_ok(response);
}
24 changes: 24 additions & 0 deletions src/util/account_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,29 @@ function _check_number_of_access_key_array(action, requested_account) {
}
}

function _check_if_iam_user_belongs_to_account_owner_by_access_key(action, requesting_account, access_key_id) {
const access_key_id_wrapped = new SensitiveString(access_key_id);
const requested_account = system_store.get_account_by_access_key(access_key_id_wrapped);
if (!requested_account) {
_throw_error_no_such_entity_access_key(action, access_key_id);
}
const is_account_on_himself = String(requesting_account._id) === String(requested_account._id);
if (is_account_on_himself) {
// didn't block an account from running action on itself since it not editing anything here
return requested_account;
} else {
const is_root_account = _check_root_account(requesting_account);
if (!is_root_account) {
_throw_access_denied_error(action, requesting_account, { access_key: access_key_id }, "ACCESS_KEY");
}
const is_requested_account_owned_by_root_account = _check_root_account_owns_user(requesting_account, requested_account);
if (!is_requested_account_owned_by_root_account) {
_throw_error_no_such_entity_access_key(action, access_key_id);
}
return requested_account;
}
}

function _check_access_key_belongs_to_account(action, requested_account, access_key_id) {
const is_access_key_belongs_to_account = _check_specific_access_key_exists(requested_account.access_keys, access_key_id);
if (!is_access_key_belongs_to_account) {
Expand Down Expand Up @@ -777,3 +800,4 @@ exports.validate_and_return_requested_account = validate_and_return_requested_ac
exports.return_list_member = return_list_member;
exports.get_owner_account_id = get_owner_account_id;
exports.get_sorted_list_tags_for_user = get_sorted_list_tags_for_user;
exports._check_if_iam_user_belongs_to_account_owner_by_access_key = _check_if_iam_user_belongs_to_account_owner_by_access_key;