mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-10 23:26:53 +00:00
fix(iam): report duplicate access keys clearly (#5066)
* fix(iam): report duplicate access keys clearly * fix(iam): narrow duplicate access key handling
This commit is contained in:
@@ -90,6 +90,10 @@ pub enum Error {
|
||||
|
||||
#[error("invalid access_key")]
|
||||
InvalidAccessKey,
|
||||
|
||||
#[error("access key is already in use")]
|
||||
AccessKeyAlreadyExists,
|
||||
|
||||
#[error("action not allowed")]
|
||||
IAMActionNotAllowed,
|
||||
|
||||
@@ -159,6 +163,7 @@ impl Clone for Error {
|
||||
Error::NoAccessKey => Error::NoAccessKey,
|
||||
Error::InvalidToken => Error::InvalidToken,
|
||||
Error::InvalidAccessKey => Error::InvalidAccessKey,
|
||||
Error::AccessKeyAlreadyExists => Error::AccessKeyAlreadyExists,
|
||||
Error::IAMActionNotAllowed => Error::IAMActionNotAllowed,
|
||||
Error::InvalidExpiration => Error::InvalidExpiration,
|
||||
Error::NoSecretKeyWithAccessKey => Error::NoSecretKeyWithAccessKey,
|
||||
@@ -297,6 +302,7 @@ mod tests {
|
||||
Error::NoSuchUser("testuser".to_string()),
|
||||
Error::NoSuchAccount("testaccount".to_string()),
|
||||
Error::InvalidArgument,
|
||||
Error::AccessKeyAlreadyExists,
|
||||
Error::IAMActionNotAllowed,
|
||||
Error::PolicyTooLarge,
|
||||
Error::ConfigNotFound,
|
||||
@@ -415,6 +421,7 @@ mod tests {
|
||||
(Error::NoSuchUser("testuser".to_string()), "user 'testuser' does not exist"),
|
||||
(Error::NoSuchAccount("testaccount".to_string()), "account 'testaccount' does not exist"),
|
||||
(Error::InvalidArgument, "invalid arguments specified"),
|
||||
(Error::AccessKeyAlreadyExists, "access key is already in use"),
|
||||
(Error::IAMActionNotAllowed, "action not allowed"),
|
||||
(Error::ConfigNotFound, "config not found"),
|
||||
];
|
||||
|
||||
@@ -787,7 +787,7 @@ where
|
||||
if let Some(x) = users.get(&cred.access_key)
|
||||
&& x.credentials.is_service_account()
|
||||
{
|
||||
return Err(Error::IAMActionNotAllowed);
|
||||
return Err(Error::AccessKeyAlreadyExists);
|
||||
}
|
||||
drop(cache);
|
||||
drop(users);
|
||||
@@ -1336,7 +1336,7 @@ where
|
||||
if let Some(x) = users.get(access_key) {
|
||||
warn!(error = ?x, "IAM user already exists");
|
||||
if x.credentials.is_temp() {
|
||||
return Err(Error::IAMActionNotAllowed);
|
||||
return Err(Error::AccessKeyAlreadyExists);
|
||||
}
|
||||
}
|
||||
drop(cache);
|
||||
|
||||
+75
-1
@@ -456,7 +456,7 @@ impl<T: Store> IamSys<T> {
|
||||
}
|
||||
|
||||
if parent_user == opts.access_key {
|
||||
return Err(IamError::IAMActionNotAllowed);
|
||||
return Err(IamError::AccessKeyAlreadyExists);
|
||||
}
|
||||
|
||||
if opts.access_key == SITE_REPLICATOR_SERVICE_ACCOUNT && !opts.allow_site_replicator_account {
|
||||
@@ -1686,6 +1686,80 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
async fn test_iam_sys() -> IamSys<StsTestMockStore> {
|
||||
let store = StsTestMockStore::new(false);
|
||||
let cache = IamCache::new(store).await.expect("IAM cache should initialize");
|
||||
IamSys::new(cache)
|
||||
}
|
||||
|
||||
fn service_account_opts(access_key: &str, secret_key: &str) -> NewServiceAccountOpts {
|
||||
NewServiceAccountOpts {
|
||||
access_key: access_key.to_string(),
|
||||
secret_key: secret_key.to_string(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn new_service_account_rejects_parent_access_key() {
|
||||
ensure_test_global_credentials();
|
||||
|
||||
let iam_sys = test_iam_sys().await;
|
||||
let access_key = "PARENTACCESSKEY123";
|
||||
|
||||
let err = iam_sys
|
||||
.new_service_account(access_key, None, service_account_opts(access_key, "parentAccessKeySecret123"))
|
||||
.await
|
||||
.expect_err("a service account must not reuse its parent access key");
|
||||
|
||||
assert_eq!(err, Error::AccessKeyAlreadyExists);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn duplicate_service_account_returns_access_key_already_exists() {
|
||||
ensure_test_global_credentials();
|
||||
|
||||
let iam_sys = test_iam_sys().await;
|
||||
let access_key = "DUPLICATESERVICEKEY1";
|
||||
|
||||
iam_sys
|
||||
.new_service_account("svc-parent-user", None, service_account_opts(access_key, "firstServiceSecret123"))
|
||||
.await
|
||||
.expect("initial service account should be created");
|
||||
|
||||
let err = iam_sys
|
||||
.new_service_account("svc-parent-user", None, service_account_opts(access_key, "secondServiceSecret123"))
|
||||
.await
|
||||
.expect_err("duplicate service account should fail");
|
||||
|
||||
assert_eq!(err, Error::AccessKeyAlreadyExists);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn user_creation_rejects_service_account_access_key() {
|
||||
ensure_test_global_credentials();
|
||||
|
||||
let iam_sys = test_iam_sys().await;
|
||||
let access_key = "SERVICEACCOUNTKEY123";
|
||||
|
||||
iam_sys
|
||||
.new_service_account("svc-parent-user", None, service_account_opts(access_key, "serviceAccountSecret123"))
|
||||
.await
|
||||
.expect("service account should be created");
|
||||
|
||||
let user = AddOrUpdateUserReq {
|
||||
secret_key: "regularUserSecret123".to_string(),
|
||||
policy: None,
|
||||
status: rustfs_madmin::AccountStatus::Enabled,
|
||||
};
|
||||
let err = iam_sys
|
||||
.create_user(access_key, &user)
|
||||
.await
|
||||
.expect_err("user creation must reject a service-account access key");
|
||||
|
||||
assert_eq!(err, Error::AccessKeyAlreadyExists);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_new_service_account_without_expiration_omits_exp_claim() {
|
||||
ensure_test_global_credentials();
|
||||
|
||||
Reference in New Issue
Block a user