This commit is contained in:
weisd
2025-06-06 11:35:27 +08:00
parent 9384b831ec
commit db355bb26b
37 changed files with 2169 additions and 668 deletions
+95 -44
View File
@@ -1,14 +1,12 @@
use ecstore::disk::error::DiskError;
use policy::policy::Error as PolicyError;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
PolicyError(#[from] PolicyError),
#[error("ecstore error: {0}")]
EcstoreError(common::error::Error),
#[error("{0}")]
StringError(String),
@@ -91,71 +89,124 @@ pub enum Error {
#[error("policy too large")]
PolicyTooLarge,
#[error("config not found")]
ConfigNotFound,
#[error("io error: {0}")]
Io(std::io::Error),
}
impl Error {
pub fn other<E>(error: E) -> Self
where
E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
Error::Io(std::io::Error::other(error))
}
}
impl From<ecstore::error::StorageError> for Error {
fn from(e: ecstore::error::StorageError) -> Self {
match e {
ecstore::error::StorageError::ConfigNotFound => Error::ConfigNotFound,
_ => Error::other(e),
}
}
}
impl From<policy::error::Error> for Error {
fn from(e: policy::error::Error) -> Self {
match e {
policy::error::Error::PolicyTooLarge => Error::PolicyTooLarge,
policy::error::Error::InvalidArgument => Error::InvalidArgument,
policy::error::Error::InvalidServiceType(s) => Error::InvalidServiceType(s),
policy::error::Error::IAMActionNotAllowed => Error::IAMActionNotAllowed,
policy::error::Error::InvalidExpiration => Error::InvalidExpiration,
policy::error::Error::NoAccessKey => Error::NoAccessKey,
policy::error::Error::InvalidToken => Error::InvalidToken,
policy::error::Error::InvalidAccessKey => Error::InvalidAccessKey,
policy::error::Error::NoSecretKeyWithAccessKey => Error::NoSecretKeyWithAccessKey,
policy::error::Error::NoAccessKeyWithSecretKey => Error::NoAccessKeyWithSecretKey,
policy::error::Error::Io(e) => Error::Io(e),
policy::error::Error::JWTError(e) => Error::JWTError(e),
policy::error::Error::NoSuchUser(s) => Error::NoSuchUser(s),
policy::error::Error::NoSuchAccount(s) => Error::NoSuchAccount(s),
policy::error::Error::NoSuchServiceAccount(s) => Error::NoSuchServiceAccount(s),
policy::error::Error::NoSuchTempAccount(s) => Error::NoSuchTempAccount(s),
policy::error::Error::NoSuchGroup(s) => Error::NoSuchGroup(s),
policy::error::Error::NoSuchPolicy => Error::NoSuchPolicy,
policy::error::Error::PolicyInUse => Error::PolicyInUse,
policy::error::Error::GroupNotEmpty => Error::GroupNotEmpty,
policy::error::Error::InvalidAccessKeyLength => Error::InvalidAccessKeyLength,
policy::error::Error::InvalidSecretKeyLength => Error::InvalidSecretKeyLength,
policy::error::Error::ContainsReservedChars => Error::ContainsReservedChars,
policy::error::Error::GroupNameContainsReservedChars => Error::GroupNameContainsReservedChars,
policy::error::Error::CredNotInitialized => Error::CredNotInitialized,
policy::error::Error::IamSysNotInitialized => Error::IamSysNotInitialized,
policy::error::Error::PolicyError(e) => Error::PolicyError(e),
policy::error::Error::StringError(s) => Error::StringError(s),
policy::error::Error::CryptoError(e) => Error::CryptoError(e),
policy::error::Error::ErrCredMalformed => Error::ErrCredMalformed,
}
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Error::other(e)
}
}
impl From<base64_simd::Error> for Error {
fn from(e: base64_simd::Error) -> Self {
Error::other(e)
}
}
pub fn is_err_config_not_found(err: &Error) -> bool {
matches!(err, Error::ConfigNotFound)
}
// pub fn is_err_no_such_user(e: &Error) -> bool {
// matches!(e, Error::NoSuchUser(_))
// }
pub fn is_err_no_such_policy(err: &common::error::Error) -> bool {
if let Some(e) = err.downcast_ref::<Error>() {
matches!(e, Error::NoSuchPolicy)
} else {
false
}
pub fn is_err_no_such_policy(err: &Error) -> bool {
matches!(err, Error::NoSuchPolicy)
}
pub fn is_err_no_such_user(err: &common::error::Error) -> bool {
if let Some(e) = err.downcast_ref::<Error>() {
matches!(e, Error::NoSuchUser(_))
} else {
false
}
pub fn is_err_no_such_user(err: &Error) -> bool {
matches!(err, Error::NoSuchUser(_))
}
pub fn is_err_no_such_account(err: &common::error::Error) -> bool {
if let Some(e) = err.downcast_ref::<Error>() {
matches!(e, Error::NoSuchAccount(_))
} else {
false
}
pub fn is_err_no_such_account(err: &Error) -> bool {
matches!(err, Error::NoSuchAccount(_))
}
pub fn is_err_no_such_temp_account(err: &common::error::Error) -> bool {
if let Some(e) = err.downcast_ref::<Error>() {
matches!(e, Error::NoSuchTempAccount(_))
} else {
false
}
pub fn is_err_no_such_temp_account(err: &Error) -> bool {
matches!(err, Error::NoSuchTempAccount(_))
}
pub fn is_err_no_such_group(err: &common::error::Error) -> bool {
if let Some(e) = err.downcast_ref::<Error>() {
matches!(e, Error::NoSuchGroup(_))
} else {
false
}
pub fn is_err_no_such_group(err: &Error) -> bool {
matches!(err, Error::NoSuchGroup(_))
}
pub fn is_err_no_such_service_account(err: &common::error::Error) -> bool {
if let Some(e) = err.downcast_ref::<Error>() {
matches!(e, Error::NoSuchServiceAccount(_))
} else {
false
}
pub fn is_err_no_such_service_account(err: &Error) -> bool {
matches!(err, Error::NoSuchServiceAccount(_))
}
// pub fn clone_err(e: &common::error::Error) -> common::error::Error {
// pub fn clone_err(e: &Error) -> Error {
// if let Some(e) = e.downcast_ref::<DiskError>() {
// clone_disk_err(e)
// } else if let Some(e) = e.downcast_ref::<std::io::Error>() {
// if let Some(code) = e.raw_os_error() {
// common::error::Error::new(std::io::Error::from_raw_os_error(code))
// Error::new(std::io::Error::from_raw_os_error(code))
// } else {
// common::error::Error::new(std::io::Error::new(e.kind(), e.to_string()))
// Error::new(std::io::Error::new(e.kind(), e.to_string()))
// }
// } else {
// //TODO: Optimize other types
// common::error::Error::msg(e.to_string())
// Error::msg(e.to_string())
// }
// }
+2 -6
View File
@@ -1,6 +1,5 @@
use common::error::{Error, Result};
use crate::error::{Error, Result};
use ecstore::store::ECStore;
use error::Error as IamError;
use manager::IamCache;
use policy::auth::Credentials;
use std::sync::{Arc, OnceLock};
@@ -62,8 +61,5 @@ pub async fn init_iam_sys(ecstore: Arc<ECStore>) -> Result<()> {
#[inline]
pub fn get() -> Result<Arc<IamSys<ObjectStore>>> {
IAM_SYS
.get()
.map(Arc::clone)
.ok_or(Error::new(IamError::IamSysNotInitialized))
IAM_SYS.get().map(Arc::clone).ok_or(Error::IamSysNotInitialized)
}
+47 -52
View File
@@ -1,3 +1,4 @@
use crate::error::{is_err_config_not_found, Error, Result};
use crate::{
cache::{Cache, CacheEntity},
error::{is_err_no_such_group, is_err_no_such_policy, is_err_no_such_user, Error as IamError},
@@ -8,7 +9,6 @@ use crate::{
STATUS_DISABLED, STATUS_ENABLED,
},
};
use common::error::{Error, Result};
use ecstore::utils::{crypto::base64_encode, path::path_join_buf};
use madmin::{AccountStatus, AddOrUpdateUserReq, GroupDesc};
use policy::{
@@ -182,7 +182,7 @@ where
pub async fn get_policy(&self, name: &str) -> Result<Policy> {
if name.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let policies = MappedPolicy::new(name).to_slice();
@@ -199,13 +199,13 @@ where
.load()
.get(&policy)
.cloned()
.ok_or(Error::new(IamError::NoSuchPolicy))?;
.ok_or(Error::NoSuchPolicy)?;
to_merge.push(v.policy);
}
if to_merge.is_empty() {
return Err(Error::new(IamError::NoSuchPolicy));
return Err(Error::NoSuchPolicy);
}
Ok(Policy::merge_policies(to_merge))
@@ -213,20 +213,15 @@ where
pub async fn get_policy_doc(&self, name: &str) -> Result<PolicyDoc> {
if name.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
self.cache
.policy_docs
.load()
.get(name)
.cloned()
.ok_or(Error::new(IamError::NoSuchPolicy))
self.cache.policy_docs.load().get(name).cloned().ok_or(Error::NoSuchPolicy)
}
pub async fn delete_policy(&self, name: &str, is_from_notify: bool) -> Result<()> {
if name.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
if is_from_notify {
@@ -254,7 +249,7 @@ where
});
if !users.is_empty() || !groups.is_empty() {
return Err(IamError::PolicyInUse.into());
return Err(Error::PolicyInUse);
}
if let Err(err) = self.api.delete_policy_doc(name).await {
@@ -274,7 +269,7 @@ where
pub async fn set_policy(&self, name: &str, policy: Policy) -> Result<OffsetDateTime> {
if name.is_empty() || policy.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let policy_doc = self
@@ -406,7 +401,7 @@ where
}
if !user_exists {
return Err(Error::new(IamError::NoSuchUser(access_key.to_string())));
return Err(Error::NoSuchUser(access_key.to_string()));
}
Ok(ret)
@@ -452,13 +447,13 @@ where
/// create a service account and update cache
pub async fn add_service_account(&self, cred: Credentials) -> Result<OffsetDateTime> {
if cred.access_key.is_empty() || cred.parent_user.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let users = self.cache.users.load();
if let Some(x) = users.get(&cred.access_key) {
if x.credentials.is_service_account() {
return Err(Error::new(IamError::IAMActionNotAllowed));
return Err(Error::IAMActionNotAllowed);
}
}
@@ -475,11 +470,11 @@ where
pub async fn update_service_account(&self, name: &str, opts: UpdateServiceAccountOpts) -> Result<OffsetDateTime> {
let Some(ui) = self.cache.users.load().get(name).cloned() else {
return Err(IamError::NoSuchServiceAccount(name.to_string()).into());
return Err(Error::NoSuchServiceAccount(name.to_string()));
};
if !ui.credentials.is_service_account() {
return Err(IamError::NoSuchServiceAccount(name.to_string()).into());
return Err(Error::NoSuchServiceAccount(name.to_string()));
}
let mut cr = ui.credentials.clone();
@@ -487,7 +482,7 @@ where
if let Some(secret) = opts.secret_key {
if !is_secret_key_valid(&secret) {
return Err(IamError::InvalidSecretKeyLength.into());
return Err(Error::InvalidSecretKeyLength);
}
cr.secret_key = secret;
}
@@ -534,7 +529,7 @@ where
if !session_policy.version.is_empty() && !session_policy.statements.is_empty() {
let policy_buf = serde_json::to_vec(&session_policy)?;
if policy_buf.len() > MAX_SVCSESSION_POLICY_SIZE {
return Err(IamError::PolicyTooLarge.into());
return Err(Error::PolicyTooLarge);
}
m.insert(SESSION_POLICY_NAME.to_owned(), serde_json::Value::String(base64_encode(&policy_buf)));
@@ -557,7 +552,7 @@ where
pub async fn policy_db_get(&self, name: &str, groups: &Option<Vec<String>>) -> Result<Vec<String>> {
if name.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let (mut policies, _) = self.policy_db_get_internal(name, false, false).await?;
@@ -593,7 +588,7 @@ where
Cache::add_or_update(&self.cache.groups, name, p, OffsetDateTime::now_utc());
}
m.get(name).cloned().ok_or(IamError::NoSuchGroup(name.to_string()))?
m.get(name).cloned().ok_or(Error::NoSuchGroup(name.to_string()))?
}
};
@@ -736,7 +731,7 @@ where
}
pub async fn policy_db_set(&self, name: &str, user_type: UserType, is_group: bool, policy: &str) -> Result<OffsetDateTime> {
if name.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
if policy.is_empty() {
@@ -762,7 +757,7 @@ where
let policy_docs_cache = self.cache.policy_docs.load();
for p in mp.to_slice() {
if !policy_docs_cache.contains_key(&p) {
return Err(Error::new(IamError::NoSuchPolicy));
return Err(Error::NoSuchPolicy);
}
}
@@ -790,14 +785,14 @@ where
cred.is_expired(),
cred.parent_user.is_empty()
);
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
if let Some(policy) = policy_name {
let mp = MappedPolicy::new(policy);
let (_, combined_policy_stmt) = filter_policies(&self.cache, &mp.policies, "temp");
if combined_policy_stmt.is_empty() {
return Err(Error::msg(format!("need poliy not found {}", IamError::NoSuchPolicy)));
return Err(Error::other(format!("need poliy not found {}", IamError::NoSuchPolicy)));
}
self.api
@@ -824,11 +819,11 @@ where
let u = match users.get(name) {
Some(u) => u,
None => return Err(Error::new(IamError::NoSuchUser(name.to_string()))),
None => return Err(Error::NoSuchUser(name.to_string())),
};
if u.credentials.is_temp() || u.credentials.is_service_account() {
return Err(Error::new(IamError::IAMActionNotAllowed));
return Err(Error::IAMActionNotAllowed);
}
let mut uinfo = madmin::UserInfo {
@@ -960,7 +955,7 @@ where
if let Some(x) = users.get(access_key) {
warn!("user already exists: {:?}", x);
if x.credentials.is_temp() {
return Err(IamError::IAMActionNotAllowed.into());
return Err(Error::IAMActionNotAllowed);
}
}
@@ -988,7 +983,7 @@ where
pub async fn delete_user(&self, access_key: &str, utype: UserType) -> Result<()> {
if access_key.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
if utype == UserType::Reg {
@@ -1040,13 +1035,13 @@ where
pub async fn update_user_secret_key(&self, access_key: &str, secret_key: &str) -> Result<()> {
if access_key.is_empty() || secret_key.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let users = self.cache.users.load();
let u = match users.get(access_key) {
Some(u) => u,
None => return Err(Error::new(IamError::NoSuchUser(access_key.to_string()))),
None => return Err(Error::NoSuchUser(access_key.to_string())),
};
let mut cred = u.credentials.clone();
@@ -1063,21 +1058,21 @@ where
pub async fn set_user_status(&self, access_key: &str, status: AccountStatus) -> Result<OffsetDateTime> {
if access_key.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
if !access_key.is_empty() && status != AccountStatus::Enabled && status != AccountStatus::Disabled {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let users = self.cache.users.load();
let u = match users.get(access_key) {
Some(u) => u,
None => return Err(Error::new(IamError::NoSuchUser(access_key.to_string()))),
None => return Err(Error::NoSuchUser(access_key.to_string())),
};
if u.credentials.is_temp() || u.credentials.is_service_account() {
return Err(Error::new(IamError::IAMActionNotAllowed));
return Err(Error::IAMActionNotAllowed);
}
let status = {
@@ -1122,7 +1117,7 @@ where
let users = self.cache.users.load();
let u = match users.get(access_key) {
Some(u) => u,
None => return Err(Error::new(IamError::NoSuchUser(access_key.to_string()))),
None => return Err(Error::NoSuchUser(access_key.to_string())),
};
if u.credentials.is_temp() {
@@ -1134,7 +1129,7 @@ where
pub async fn add_users_to_group(&self, group: &str, members: Vec<String>) -> Result<OffsetDateTime> {
if group.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let users_cache = self.cache.users.load();
@@ -1142,10 +1137,10 @@ where
for member in members.iter() {
if let Some(u) = users_cache.get(member) {
if u.credentials.is_temp() || u.credentials.is_service_account() {
return Err(Error::new(IamError::IAMActionNotAllowed));
return Err(Error::IAMActionNotAllowed);
}
} else {
return Err(Error::new(IamError::NoSuchUser(member.to_string())));
return Err(Error::NoSuchUser(member.to_string()));
}
}
@@ -1180,13 +1175,13 @@ where
pub async fn set_group_status(&self, name: &str, enable: bool) -> Result<OffsetDateTime> {
if name.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let groups = self.cache.groups.load();
let mut gi = match groups.get(name) {
Some(gi) => gi.clone(),
None => return Err(Error::new(IamError::NoSuchGroup(name.to_string()))),
None => return Err(Error::NoSuchGroup(name.to_string())),
};
if enable {
@@ -1212,7 +1207,7 @@ where
.load()
.get(name)
.cloned()
.ok_or(Error::new(IamError::NoSuchGroup(name.to_string())))?;
.ok_or(Error::NoSuchGroup(name.to_string()))?;
Ok(GroupDesc {
name: name.to_string(),
@@ -1239,7 +1234,7 @@ where
.load()
.get(name)
.cloned()
.ok_or(Error::new(IamError::NoSuchGroup(name.to_string())))?;
.ok_or(Error::NoSuchGroup(name.to_string()))?;
let s: HashSet<&String> = HashSet::from_iter(gi.members.iter());
let d: HashSet<&String> = HashSet::from_iter(members.iter());
@@ -1265,7 +1260,7 @@ where
pub async fn remove_users_from_group(&self, group: &str, members: Vec<String>) -> Result<OffsetDateTime> {
if group.is_empty() {
return Err(Error::new(IamError::InvalidArgument));
return Err(Error::InvalidArgument);
}
let users_cache = self.cache.users.load();
@@ -1273,10 +1268,10 @@ where
for member in members.iter() {
if let Some(u) = users_cache.get(member) {
if u.credentials.is_temp() || u.credentials.is_service_account() {
return Err(Error::new(IamError::IAMActionNotAllowed));
return Err(Error::IAMActionNotAllowed);
}
} else {
return Err(Error::new(IamError::NoSuchUser(member.to_string())));
return Err(Error::NoSuchUser(member.to_string()));
}
}
@@ -1286,10 +1281,10 @@ where
.load()
.get(group)
.cloned()
.ok_or(Error::new(IamError::NoSuchGroup(group.to_string())))?;
.ok_or(Error::NoSuchGroup(group.to_string()))?;
if members.is_empty() && !gi.members.is_empty() {
return Err(IamError::GroupNotEmpty.into());
return Err(Error::GroupNotEmpty);
}
if members.is_empty() {
@@ -1588,7 +1583,7 @@ pub fn get_token_signing_key() -> Option<String> {
pub fn extract_jwt_claims(u: &UserIdentity) -> Result<HashMap<String, Value>> {
let Some(sys_key) = get_token_signing_key() else {
return Err(Error::msg("global active sk not init"));
return Err(Error::other("global active sk not init"));
};
let keys = vec![&sys_key, &u.credentials.secret_key];
@@ -1598,7 +1593,7 @@ pub fn extract_jwt_claims(u: &UserIdentity) -> Result<HashMap<String, Value>> {
return Ok(claims);
}
}
Err(Error::msg("unable to extract claims"))
Err(Error::other("unable to extract claims"))
}
fn filter_policies(cache: &Cache, policy_name: &str, bucket_name: &str) -> (String, Policy) {
+1 -1
View File
@@ -1,7 +1,7 @@
pub mod object;
use crate::cache::Cache;
use common::error::Result;
use crate::error::Result;
use policy::{auth::UserIdentity, policy::PolicyDoc};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
+24 -23
View File
@@ -1,15 +1,14 @@
use super::{GroupInfo, MappedPolicy, Store, UserType};
use crate::error::{is_err_config_not_found, Error, Result};
use crate::{
cache::{Cache, CacheEntity},
error::{is_err_no_such_policy, is_err_no_such_user},
get_global_action_cred,
manager::{extract_jwt_claims, get_default_policyes},
};
use common::error::{Error, Result};
use ecstore::{
config::{
com::{delete_config, read_config, read_config_with_metadata, save_config},
error::is_err_config_not_found,
RUSTFS_CONFIG_PREFIX,
},
store::ECStore,
@@ -153,7 +152,7 @@ impl ObjectStore {
let _ = sender
.send(StringOrErr {
item: None,
err: Some(err),
err: Some(err.into()),
})
.await;
return;
@@ -213,7 +212,7 @@ impl ObjectStore {
Ok(p) => Ok(p),
Err(err) => {
if !is_err_no_such_policy(&err) {
Err(Error::msg(std::format!("load policy doc failed: {}", err)))
Err(Error::other(format!("load policy doc failed: {}", err)))
} else {
Ok(PolicyDoc::default())
}
@@ -245,7 +244,7 @@ impl ObjectStore {
Ok(res) => Ok(res),
Err(err) => {
if !is_err_no_such_user(&err) {
Err(Error::msg(std::format!("load user failed: {}", err)))
Err(Error::other(format!("load user failed: {}", err)))
} else {
Ok(UserIdentity::default())
}
@@ -272,7 +271,7 @@ impl ObjectStore {
.await
.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchPolicy)
Error::NoSuchPolicy
} else {
err
}
@@ -296,7 +295,7 @@ impl ObjectStore {
Ok(p) => Ok(p),
Err(err) => {
if !is_err_no_such_policy(&err) {
Err(Error::msg(std::format!("load mapped policy failed: {}", err)))
Err(Error::other(format!("load mapped policy failed: {}", err)))
} else {
Ok(MappedPolicy::default())
}
@@ -369,10 +368,12 @@ impl Store for ObjectStore {
let mut data = serde_json::to_vec(&item)?;
data = Self::encrypt_data(&data)?;
save_config(self.object_api.clone(), path.as_ref(), data).await
save_config(self.object_api.clone(), path.as_ref(), data).await?;
Ok(())
}
async fn delete_iam_config(&self, path: impl AsRef<str> + Send) -> Result<()> {
delete_config(self.object_api.clone(), path.as_ref()).await
delete_config(self.object_api.clone(), path.as_ref()).await?;
Ok(())
}
async fn save_user_identity(
@@ -390,7 +391,7 @@ impl Store for ObjectStore {
.await
.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchPolicy)
Error::NoSuchPolicy
} else {
err
}
@@ -403,7 +404,7 @@ impl Store for ObjectStore {
.await
.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchUser(name.to_owned()))
Error::NoSuchUser(name.to_owned())
} else {
err
}
@@ -412,7 +413,7 @@ impl Store for ObjectStore {
if u.credentials.is_expired() {
let _ = self.delete_iam_config(get_user_identity_path(name, user_type)).await;
let _ = self.delete_iam_config(get_mapped_policy_path(name, user_type, false)).await;
return Err(Error::new(crate::error::Error::NoSuchUser(name.to_owned())));
return Err(Error::NoSuchUser(name.to_owned()));
}
if u.credentials.access_key.is_empty() {
@@ -430,7 +431,7 @@ impl Store for ObjectStore {
let _ = self.delete_iam_config(get_mapped_policy_path(name, user_type, false)).await;
}
warn!("extract_jwt_claims failed: {}", err);
return Err(Error::new(crate::error::Error::NoSuchUser(name.to_owned())));
return Err(Error::NoSuchUser(name.to_owned()));
}
}
}
@@ -476,7 +477,7 @@ impl Store for ObjectStore {
.await
.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchUser(name.to_owned()))
Error::NoSuchUser(name.to_owned())
} else {
err
}
@@ -491,7 +492,7 @@ impl Store for ObjectStore {
async fn delete_group_info(&self, name: &str) -> Result<()> {
self.delete_iam_config(get_group_info_path(name)).await.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchPolicy)
Error::NoSuchPolicy
} else {
err
}
@@ -501,7 +502,7 @@ impl Store for ObjectStore {
async fn load_group(&self, name: &str, m: &mut HashMap<String, GroupInfo>) -> Result<()> {
let u: GroupInfo = self.load_iam_config(get_group_info_path(name)).await.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchPolicy)
Error::NoSuchPolicy
} else {
err
}
@@ -539,7 +540,7 @@ impl Store for ObjectStore {
async fn delete_policy_doc(&self, name: &str) -> Result<()> {
self.delete_iam_config(get_policy_doc_path(name)).await.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchPolicy)
Error::NoSuchPolicy
} else {
err
}
@@ -552,7 +553,7 @@ impl Store for ObjectStore {
.await
.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchPolicy)
Error::NoSuchPolicy
} else {
err
}
@@ -613,7 +614,7 @@ impl Store for ObjectStore {
.await
.map_err(|err| {
if is_err_config_not_found(&err) {
Error::new(crate::error::Error::NoSuchPolicy)
Error::NoSuchPolicy
} else {
err
}
@@ -766,7 +767,7 @@ impl Store for ObjectStore {
let name = ecstore::utils::path::dir(item);
info!("load group: {}", name);
if let Err(err) = self.load_group(&name, &mut items_cache).await {
return Err(Error::msg(std::format!("load group failed: {}", err)));
return Err(Error::other(format!("load group failed: {}", err)));
};
}
@@ -827,7 +828,7 @@ impl Store for ObjectStore {
info!("load group policy: {}", name);
if let Err(err) = self.load_mapped_policy(name, UserType::Reg, true, &mut items_cache).await {
if !is_err_no_such_policy(&err) {
return Err(Error::msg(std::format!("load group policy failed: {}", err)));
return Err(Error::other(format!("load group policy failed: {}", err)));
}
};
}
@@ -846,7 +847,7 @@ impl Store for ObjectStore {
info!("load svc user: {}", name);
if let Err(err) = self.load_user(&name, UserType::Svc, &mut items_cache).await {
if !is_err_no_such_user(&err) {
return Err(Error::msg(std::format!("load svc user failed: {}", err)));
return Err(Error::other(format!("load svc user failed: {}", err)));
}
};
}
@@ -860,7 +861,7 @@ impl Store for ObjectStore {
.await
{
if !is_err_no_such_policy(&err) {
return Err(Error::msg(std::format!("load_mapped_policy failed: {}", err)));
return Err(Error::other(format!("load_mapped_policy failed: {}", err)));
}
}
}
+25 -25
View File
@@ -1,6 +1,7 @@
use crate::error::is_err_no_such_account;
use crate::error::is_err_no_such_temp_account;
use crate::error::Error as IamError;
use crate::error::{Error, Result};
use crate::get_global_action_cred;
use crate::manager::extract_jwt_claims;
use crate::manager::get_default_policyes;
@@ -8,7 +9,6 @@ use crate::manager::IamCache;
use crate::store::MappedPolicy;
use crate::store::Store;
use crate::store::UserType;
use common::error::{Error, Result};
use ecstore::utils::crypto::base64_decode;
use ecstore::utils::crypto::base64_encode;
use madmin::AddOrUpdateUserReq;
@@ -81,7 +81,7 @@ impl<T: Store> IamSys<T> {
pub async fn delete_policy(&self, name: &str, notify: bool) -> Result<()> {
for k in get_default_policyes().keys() {
if k == name {
return Err(Error::msg("system policy can not be deleted"));
return Err(Error::other("system policy can not be deleted"));
}
}
@@ -123,11 +123,11 @@ impl<T: Store> IamSys<T> {
pub async fn get_role_policy(&self, arn_str: &str) -> Result<(ARN, String)> {
let Some(arn) = ARN::parse(arn_str).ok() else {
return Err(Error::msg("Invalid ARN"));
return Err(Error::other("Invalid ARN"));
};
let Some(policy) = self.roles_map.get(&arn) else {
return Err(Error::msg("No such role"));
return Err(Error::other("No such role"));
};
Ok((arn, policy.clone()))
@@ -157,7 +157,7 @@ impl<T: Store> IamSys<T> {
pub async fn is_temp_user(&self, name: &str) -> Result<(bool, String)> {
let Some(u) = self.store.get_user(name).await else {
return Err(IamError::NoSuchUser(name.to_string()).into());
return Err(IamError::NoSuchUser(name.to_string()));
};
if u.credentials.is_temp() {
Ok((true, u.credentials.parent_user))
@@ -167,7 +167,7 @@ impl<T: Store> IamSys<T> {
}
pub async fn is_service_account(&self, name: &str) -> Result<(bool, String)> {
let Some(u) = self.store.get_user(name).await else {
return Err(IamError::NoSuchUser(name.to_string()).into());
return Err(IamError::NoSuchUser(name.to_string()));
};
if u.credentials.is_service_account() {
@@ -193,22 +193,22 @@ impl<T: Store> IamSys<T> {
opts: NewServiceAccountOpts,
) -> Result<(Credentials, OffsetDateTime)> {
if parent_user.is_empty() {
return Err(IamError::InvalidArgument.into());
return Err(IamError::InvalidArgument);
}
if !opts.access_key.is_empty() && opts.secret_key.is_empty() {
return Err(IamError::NoSecretKeyWithAccessKey.into());
return Err(IamError::NoSecretKeyWithAccessKey);
}
if !opts.secret_key.is_empty() && opts.access_key.is_empty() {
return Err(IamError::NoAccessKeyWithSecretKey.into());
return Err(IamError::NoAccessKeyWithSecretKey);
}
if parent_user == opts.access_key {
return Err(IamError::IAMActionNotAllowed.into());
return Err(IamError::IAMActionNotAllowed);
}
if opts.expiration.is_none() {
return Err(IamError::InvalidExpiration.into());
return Err(IamError::InvalidExpiration);
}
// TODO: check allow_site_replicator_account
@@ -217,7 +217,7 @@ impl<T: Store> IamSys<T> {
policy.validate()?;
let buf = serde_json::to_vec(&policy)?;
if buf.len() > MAX_SVCSESSION_POLICY_SIZE {
return Err(IamError::PolicyTooLarge.into());
return Err(IamError::PolicyTooLarge);
}
buf
@@ -304,7 +304,7 @@ impl<T: Store> IamSys<T> {
Ok(res) => res,
Err(err) => {
if is_err_no_such_account(&err) {
return Err(IamError::NoSuchServiceAccount(access_key.to_string()).into());
return Err(IamError::NoSuchServiceAccount(access_key.to_string()));
}
return Err(err);
@@ -312,7 +312,7 @@ impl<T: Store> IamSys<T> {
};
if !sa.credentials.is_service_account() {
return Err(IamError::NoSuchServiceAccount(access_key.to_string()).into());
return Err(IamError::NoSuchServiceAccount(access_key.to_string()));
}
let op_pt = claims.get(&iam_policy_claim_name_sa());
@@ -329,7 +329,7 @@ impl<T: Store> IamSys<T> {
async fn get_account_with_claims(&self, access_key: &str) -> Result<(UserIdentity, HashMap<String, Value>)> {
let Some(acc) = self.store.get_user(access_key).await else {
return Err(IamError::NoSuchAccount(access_key.to_string()).into());
return Err(IamError::NoSuchAccount(access_key.to_string()));
};
let m = extract_jwt_claims(&acc)?;
@@ -363,7 +363,7 @@ impl<T: Store> IamSys<T> {
Ok(res) => res,
Err(err) => {
if is_err_no_such_account(&err) {
return Err(IamError::NoSuchTempAccount(access_key.to_string()).into());
return Err(IamError::NoSuchTempAccount(access_key.to_string()));
}
return Err(err);
@@ -371,7 +371,7 @@ impl<T: Store> IamSys<T> {
};
if !sa.credentials.is_temp() {
return Err(IamError::NoSuchTempAccount(access_key.to_string()).into());
return Err(IamError::NoSuchTempAccount(access_key.to_string()));
}
let op_pt = claims.get(&iam_policy_claim_name_sa());
@@ -388,11 +388,11 @@ impl<T: Store> IamSys<T> {
pub async fn get_claims_for_svc_acc(&self, access_key: &str) -> Result<HashMap<String, Value>> {
let Some(u) = self.store.get_user(access_key).await else {
return Err(IamError::NoSuchServiceAccount(access_key.to_string()).into());
return Err(IamError::NoSuchServiceAccount(access_key.to_string()));
};
if u.credentials.is_service_account() {
return Err(IamError::NoSuchServiceAccount(access_key.to_string()).into());
return Err(IamError::NoSuchServiceAccount(access_key.to_string()));
}
extract_jwt_claims(&u)
@@ -414,15 +414,15 @@ impl<T: Store> IamSys<T> {
pub async fn create_user(&self, access_key: &str, args: &AddOrUpdateUserReq) -> Result<OffsetDateTime> {
if !is_access_key_valid(access_key) {
return Err(IamError::InvalidAccessKeyLength.into());
return Err(IamError::InvalidAccessKeyLength);
}
if contains_reserved_chars(access_key) {
return Err(IamError::ContainsReservedChars.into());
return Err(IamError::ContainsReservedChars);
}
if !is_secret_key_valid(&args.secret_key) {
return Err(IamError::InvalidSecretKeyLength.into());
return Err(IamError::InvalidSecretKeyLength);
}
self.store.add_user(access_key, args).await
@@ -431,11 +431,11 @@ impl<T: Store> IamSys<T> {
pub async fn set_user_secret_key(&self, access_key: &str, secret_key: &str) -> Result<()> {
if !is_access_key_valid(access_key) {
return Err(IamError::InvalidAccessKeyLength.into());
return Err(IamError::InvalidAccessKeyLength);
}
if !is_secret_key_valid(secret_key) {
return Err(IamError::InvalidSecretKeyLength.into());
return Err(IamError::InvalidSecretKeyLength);
}
self.store.update_user_secret_key(access_key, secret_key).await
@@ -467,7 +467,7 @@ impl<T: Store> IamSys<T> {
pub async fn add_users_to_group(&self, group: &str, users: Vec<String>) -> Result<OffsetDateTime> {
if contains_reserved_chars(group) {
return Err(IamError::GroupNameContainsReservedChars.into());
return Err(IamError::GroupNameContainsReservedChars);
}
self.store.add_users_to_group(group, users).await
// TODO: notification
+5 -5
View File
@@ -1,7 +1,7 @@
use common::error::{Error, Result};
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header};
use rand::{Rng, RngCore};
use serde::{de::DeserializeOwned, Serialize};
use std::io::{Error, Result};
pub fn gen_access_key(length: usize) -> Result<String> {
const ALPHA_NUMERIC_TABLE: [char; 36] = [
@@ -10,7 +10,7 @@ pub fn gen_access_key(length: usize) -> Result<String> {
];
if length < 3 {
return Err(Error::msg("access key length is too short"));
return Err(Error::other("access key length is too short"));
}
let mut result = String::with_capacity(length);
@@ -27,7 +27,7 @@ pub fn gen_secret_key(length: usize) -> Result<String> {
use base64_simd::URL_SAFE_NO_PAD;
if length < 8 {
return Err(Error::msg("secret key length is too short"));
return Err(Error::other("secret key length is too short"));
}
let mut rng = rand::thread_rng();
@@ -40,7 +40,7 @@ pub fn gen_secret_key(length: usize) -> Result<String> {
Ok(key_str)
}
pub fn generate_jwt<T: Serialize>(claims: &T, secret: &str) -> Result<String, jsonwebtoken::errors::Error> {
pub fn generate_jwt<T: Serialize>(claims: &T, secret: &str) -> std::result::Result<String, jsonwebtoken::errors::Error> {
let header = Header::new(Algorithm::HS512);
jsonwebtoken::encode(&header, &claims, &EncodingKey::from_secret(secret.as_bytes()))
}
@@ -48,7 +48,7 @@ pub fn generate_jwt<T: Serialize>(claims: &T, secret: &str) -> Result<String, js
pub fn extract_claims<T: DeserializeOwned>(
token: &str,
secret: &str,
) -> Result<jsonwebtoken::TokenData<T>, jsonwebtoken::errors::Error> {
) -> std::result::Result<jsonwebtoken::TokenData<T>, jsonwebtoken::errors::Error> {
jsonwebtoken::decode::<T>(
token,
&DecodingKey::from_secret(secret.as_bytes()),