mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-03 20:07:42 +00:00
Merge branch 'main' of github.com:rustfs/s3-rustfs into feature/observability-metrics
# Conflicts: # .github/workflows/build.yml # .github/workflows/ci.yml # Cargo.lock # Cargo.toml # appauth/src/token.rs # crates/config/src/config.rs # crates/event-notifier/examples/simple.rs # crates/event-notifier/src/global.rs # crates/event-notifier/src/lib.rs # crates/event-notifier/src/notifier.rs # crates/event-notifier/src/store.rs # crates/filemeta/src/filemeta.rs # crates/notify/examples/webhook.rs # crates/utils/Cargo.toml # ecstore/Cargo.toml # ecstore/src/cmd/bucket_replication.rs # ecstore/src/config/com.rs # ecstore/src/disk/error.rs # ecstore/src/disk/mod.rs # ecstore/src/set_disk.rs # ecstore/src/store_api.rs # ecstore/src/store_list_objects.rs # iam/Cargo.toml # iam/src/manager.rs # policy/Cargo.toml # rustfs/src/admin/rpc.rs # rustfs/src/main.rs # rustfs/src/storage/mod.rs
This commit is contained in:
+311
-52
@@ -1,15 +1,12 @@
|
||||
use ecstore::disk::error::clone_disk_err;
|
||||
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),
|
||||
|
||||
@@ -92,71 +89,333 @@ pub enum Error {
|
||||
|
||||
#[error("policy too large")]
|
||||
PolicyTooLarge,
|
||||
|
||||
#[error("config not found")]
|
||||
ConfigNotFound,
|
||||
|
||||
#[error("io error: {0}")]
|
||||
Io(std::io::Error),
|
||||
}
|
||||
|
||||
impl PartialEq for Error {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Error::StringError(a), Error::StringError(b)) => a == b,
|
||||
(Error::NoSuchUser(a), Error::NoSuchUser(b)) => a == b,
|
||||
(Error::NoSuchAccount(a), Error::NoSuchAccount(b)) => a == b,
|
||||
(Error::NoSuchServiceAccount(a), Error::NoSuchServiceAccount(b)) => a == b,
|
||||
(Error::NoSuchTempAccount(a), Error::NoSuchTempAccount(b)) => a == b,
|
||||
(Error::NoSuchGroup(a), Error::NoSuchGroup(b)) => a == b,
|
||||
(Error::InvalidServiceType(a), Error::InvalidServiceType(b)) => a == b,
|
||||
(Error::Io(a), Error::Io(b)) => a.kind() == b.kind() && a.to_string() == b.to_string(),
|
||||
// For complex types like PolicyError, CryptoError, JWTError, compare string representations
|
||||
(a, b) => std::mem::discriminant(a) == std::mem::discriminant(b) && a.to_string() == b.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Error {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Error::PolicyError(e) => Error::StringError(e.to_string()), // Convert to string since PolicyError may not be cloneable
|
||||
Error::StringError(s) => Error::StringError(s.clone()),
|
||||
Error::CryptoError(e) => Error::StringError(format!("crypto: {}", e)), // Convert to string
|
||||
Error::NoSuchUser(s) => Error::NoSuchUser(s.clone()),
|
||||
Error::NoSuchAccount(s) => Error::NoSuchAccount(s.clone()),
|
||||
Error::NoSuchServiceAccount(s) => Error::NoSuchServiceAccount(s.clone()),
|
||||
Error::NoSuchTempAccount(s) => Error::NoSuchTempAccount(s.clone()),
|
||||
Error::NoSuchGroup(s) => Error::NoSuchGroup(s.clone()),
|
||||
Error::NoSuchPolicy => Error::NoSuchPolicy,
|
||||
Error::PolicyInUse => Error::PolicyInUse,
|
||||
Error::GroupNotEmpty => Error::GroupNotEmpty,
|
||||
Error::InvalidArgument => Error::InvalidArgument,
|
||||
Error::IamSysNotInitialized => Error::IamSysNotInitialized,
|
||||
Error::InvalidServiceType(s) => Error::InvalidServiceType(s.clone()),
|
||||
Error::ErrCredMalformed => Error::ErrCredMalformed,
|
||||
Error::CredNotInitialized => Error::CredNotInitialized,
|
||||
Error::InvalidAccessKeyLength => Error::InvalidAccessKeyLength,
|
||||
Error::InvalidSecretKeyLength => Error::InvalidSecretKeyLength,
|
||||
Error::ContainsReservedChars => Error::ContainsReservedChars,
|
||||
Error::GroupNameContainsReservedChars => Error::GroupNameContainsReservedChars,
|
||||
Error::JWTError(e) => Error::StringError(format!("jwt err {}", e)), // Convert to string
|
||||
Error::NoAccessKey => Error::NoAccessKey,
|
||||
Error::InvalidToken => Error::InvalidToken,
|
||||
Error::InvalidAccessKey => Error::InvalidAccessKey,
|
||||
Error::IAMActionNotAllowed => Error::IAMActionNotAllowed,
|
||||
Error::InvalidExpiration => Error::InvalidExpiration,
|
||||
Error::NoSecretKeyWithAccessKey => Error::NoSecretKeyWithAccessKey,
|
||||
Error::NoAccessKeyWithSecretKey => Error::NoAccessKeyWithSecretKey,
|
||||
Error::PolicyTooLarge => Error::PolicyTooLarge,
|
||||
Error::ConfigNotFound => Error::ConfigNotFound,
|
||||
Error::Io(e) => Error::Io(std::io::Error::new(e.kind(), e.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<Error> for ecstore::error::StorageError {
|
||||
fn from(e: Error) -> Self {
|
||||
match e {
|
||||
Error::ConfigNotFound => ecstore::error::StorageError::ConfigNotFound,
|
||||
_ => ecstore::error::StorageError::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<Error> for std::io::Error {
|
||||
fn from(e: Error) -> Self {
|
||||
std::io::Error::other(e)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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))
|
||||
} else {
|
||||
common::error::Error::new(std::io::Error::new(e.kind(), e.to_string()))
|
||||
// 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() {
|
||||
// Error::new(std::io::Error::from_raw_os_error(code))
|
||||
// } else {
|
||||
// Error::new(std::io::Error::new(e.kind(), e.to_string()))
|
||||
// }
|
||||
// } else {
|
||||
// //TODO: Optimize other types
|
||||
// Error::msg(e.to_string())
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::io::{Error as IoError, ErrorKind};
|
||||
|
||||
#[test]
|
||||
fn test_iam_error_to_io_error_conversion() {
|
||||
let iam_errors = vec![
|
||||
Error::NoSuchUser("testuser".to_string()),
|
||||
Error::NoSuchAccount("testaccount".to_string()),
|
||||
Error::InvalidArgument,
|
||||
Error::IAMActionNotAllowed,
|
||||
Error::PolicyTooLarge,
|
||||
Error::ConfigNotFound,
|
||||
];
|
||||
|
||||
for iam_error in iam_errors {
|
||||
let io_error: std::io::Error = iam_error.clone().into();
|
||||
|
||||
// Check that conversion creates an io::Error
|
||||
assert_eq!(io_error.kind(), ErrorKind::Other);
|
||||
|
||||
// Check that the error message is preserved
|
||||
assert!(io_error.to_string().contains(&iam_error.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iam_error_from_storage_error() {
|
||||
// Test conversion from StorageError
|
||||
let storage_error = ecstore::error::StorageError::ConfigNotFound;
|
||||
let iam_error: Error = storage_error.into();
|
||||
assert_eq!(iam_error, Error::ConfigNotFound);
|
||||
|
||||
// Test reverse conversion
|
||||
let back_to_storage: ecstore::error::StorageError = iam_error.into();
|
||||
assert_eq!(back_to_storage, ecstore::error::StorageError::ConfigNotFound);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iam_error_from_policy_error() {
|
||||
use policy::error::Error as PolicyError;
|
||||
|
||||
let policy_errors = vec![
|
||||
(PolicyError::NoSuchUser("user1".to_string()), Error::NoSuchUser("user1".to_string())),
|
||||
(PolicyError::NoSuchPolicy, Error::NoSuchPolicy),
|
||||
(PolicyError::InvalidArgument, Error::InvalidArgument),
|
||||
(PolicyError::PolicyTooLarge, Error::PolicyTooLarge),
|
||||
];
|
||||
|
||||
for (policy_error, expected_iam_error) in policy_errors {
|
||||
let converted_iam_error: Error = policy_error.into();
|
||||
assert_eq!(converted_iam_error, expected_iam_error);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iam_error_other_function() {
|
||||
let custom_error = "Custom IAM error";
|
||||
let iam_error = Error::other(custom_error);
|
||||
|
||||
match iam_error {
|
||||
Error::Io(io_error) => {
|
||||
assert!(io_error.to_string().contains(custom_error));
|
||||
assert_eq!(io_error.kind(), ErrorKind::Other);
|
||||
}
|
||||
_ => panic!("Expected Io variant"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iam_error_from_serde_json() {
|
||||
// Test conversion from serde_json::Error
|
||||
let invalid_json = r#"{"invalid": json}"#;
|
||||
let json_error = serde_json::from_str::<serde_json::Value>(invalid_json).unwrap_err();
|
||||
let iam_error: Error = json_error.into();
|
||||
|
||||
match iam_error {
|
||||
Error::Io(io_error) => {
|
||||
assert_eq!(io_error.kind(), ErrorKind::Other);
|
||||
}
|
||||
_ => panic!("Expected Io variant"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_helper_functions() {
|
||||
// Test helper functions for error type checking
|
||||
assert!(is_err_config_not_found(&Error::ConfigNotFound));
|
||||
assert!(!is_err_config_not_found(&Error::NoSuchPolicy));
|
||||
|
||||
assert!(is_err_no_such_policy(&Error::NoSuchPolicy));
|
||||
assert!(!is_err_no_such_policy(&Error::ConfigNotFound));
|
||||
|
||||
assert!(is_err_no_such_user(&Error::NoSuchUser("test".to_string())));
|
||||
assert!(!is_err_no_such_user(&Error::NoSuchAccount("test".to_string())));
|
||||
|
||||
assert!(is_err_no_such_account(&Error::NoSuchAccount("test".to_string())));
|
||||
assert!(!is_err_no_such_account(&Error::NoSuchUser("test".to_string())));
|
||||
|
||||
assert!(is_err_no_such_temp_account(&Error::NoSuchTempAccount("test".to_string())));
|
||||
assert!(!is_err_no_such_temp_account(&Error::NoSuchAccount("test".to_string())));
|
||||
|
||||
assert!(is_err_no_such_group(&Error::NoSuchGroup("test".to_string())));
|
||||
assert!(!is_err_no_such_group(&Error::NoSuchUser("test".to_string())));
|
||||
|
||||
assert!(is_err_no_such_service_account(&Error::NoSuchServiceAccount("test".to_string())));
|
||||
assert!(!is_err_no_such_service_account(&Error::NoSuchAccount("test".to_string())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iam_error_io_preservation() {
|
||||
// Test that Io variant preserves original io::Error
|
||||
let original_io = IoError::new(ErrorKind::PermissionDenied, "access denied");
|
||||
let iam_error = Error::Io(original_io);
|
||||
|
||||
let converted_io: std::io::Error = iam_error.into();
|
||||
// Note: Our clone implementation creates a new io::Error with the same kind and message
|
||||
// but it becomes ErrorKind::Other when cloned
|
||||
assert_eq!(converted_io.kind(), ErrorKind::Other);
|
||||
assert!(converted_io.to_string().contains("access denied"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error_display_format() {
|
||||
let test_cases = vec![
|
||||
(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::IAMActionNotAllowed, "action not allowed"),
|
||||
(Error::ConfigNotFound, "config not found"),
|
||||
];
|
||||
|
||||
for (error, expected_message) in test_cases {
|
||||
assert_eq!(error.to_string(), expected_message);
|
||||
}
|
||||
} else {
|
||||
//TODO: Optimize other types
|
||||
common::error::Error::msg(e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
+2
-6
@@ -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)
|
||||
}
|
||||
|
||||
+112
-110
@@ -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,9 +9,7 @@ use crate::{
|
||||
STATUS_DISABLED, STATUS_ENABLED,
|
||||
},
|
||||
};
|
||||
use common::error::{Error, Result};
|
||||
use ecstore::config::error::is_err_config_not_found;
|
||||
use ecstore::utils::{crypto::base64_encode, path::path_join_buf};
|
||||
// use ecstore::utils::crypto::base64_encode;
|
||||
use madmin::{AccountStatus, AddOrUpdateUserReq, GroupDesc};
|
||||
use policy::{
|
||||
arn::ARN,
|
||||
@@ -20,6 +19,8 @@ use policy::{
|
||||
default::DEFAULT_POLICIES, iam_policy_claim_name_sa, Policy, PolicyDoc, EMBEDDED_POLICY_TYPE, INHERITED_POLICY_TYPE,
|
||||
},
|
||||
};
|
||||
use rustfs_utils::crypto::base64_encode;
|
||||
use rustfs_utils::path::path_join_buf;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::{
|
||||
@@ -75,7 +76,7 @@ where
|
||||
T: Store,
|
||||
{
|
||||
pub(crate) async fn new(api: T) -> Arc<Self> {
|
||||
let (sender, receiver) = mpsc::channel::<i64>(100);
|
||||
let (sender, reciver) = mpsc::channel::<i64>(100);
|
||||
|
||||
let sys = Arc::new(Self {
|
||||
api,
|
||||
@@ -86,46 +87,53 @@ where
|
||||
last_timestamp: AtomicI64::new(0),
|
||||
});
|
||||
|
||||
sys.clone().init(receiver).await.unwrap();
|
||||
sys.clone().init(reciver).await.unwrap();
|
||||
sys
|
||||
}
|
||||
|
||||
async fn init(self: Arc<Self>, receiver: Receiver<i64>) -> Result<()> {
|
||||
async fn init(self: Arc<Self>, reciver: Receiver<i64>) -> Result<()> {
|
||||
self.clone().save_iam_formatter().await?;
|
||||
self.clone().load().await?;
|
||||
|
||||
// Background thread starts periodic updates or receives signal updates
|
||||
tokio::spawn({
|
||||
let s = Arc::clone(&self);
|
||||
async move {
|
||||
let ticker = tokio::time::interval(Duration::from_secs(120));
|
||||
tokio::pin!(ticker, receiver);
|
||||
loop {
|
||||
select! {
|
||||
_ = ticker.tick() => {
|
||||
if let Err(err) =s.clone().load().await{
|
||||
error!("iam load err {:?}", err);
|
||||
}
|
||||
},
|
||||
i = receiver.recv() => {
|
||||
match i {
|
||||
Some(t) => {
|
||||
let last = s.last_timestamp.load(Ordering::Relaxed);
|
||||
if last <= t {
|
||||
// 检查环境变量是否设置
|
||||
let skip_background_task = std::env::var("RUSTFS_SKIP_BACKGROUND_TASK").is_ok();
|
||||
|
||||
if let Err(err) =s.clone().load().await{
|
||||
error!("iam load err {:?}", err);
|
||||
if !skip_background_task {
|
||||
// Background thread starts periodic updates or receives signal updates
|
||||
tokio::spawn({
|
||||
let s = Arc::clone(&self);
|
||||
async move {
|
||||
let ticker = tokio::time::interval(Duration::from_secs(120));
|
||||
tokio::pin!(ticker, reciver);
|
||||
loop {
|
||||
select! {
|
||||
_ = ticker.tick() => {
|
||||
warn!("iam load ticker");
|
||||
if let Err(err) =s.clone().load().await{
|
||||
error!("iam load err {:?}", err);
|
||||
}
|
||||
},
|
||||
i = reciver.recv() => {
|
||||
warn!("iam load reciver");
|
||||
match i {
|
||||
Some(t) => {
|
||||
let last = s.last_timestamp.load(Ordering::Relaxed);
|
||||
if last <= t {
|
||||
warn!("iam load reciver load");
|
||||
if let Err(err) =s.clone().load().await{
|
||||
error!("iam load err {:?}", err);
|
||||
}
|
||||
ticker.reset();
|
||||
}
|
||||
ticker.reset();
|
||||
}
|
||||
},
|
||||
None => return,
|
||||
},
|
||||
None => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -183,7 +191,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();
|
||||
@@ -200,13 +208,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))
|
||||
@@ -214,20 +222,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 {
|
||||
@@ -255,7 +258,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 {
|
||||
@@ -275,7 +278,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
|
||||
@@ -407,7 +410,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)
|
||||
@@ -453,13 +456,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,11 +479,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();
|
||||
@@ -488,7 +491,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;
|
||||
}
|
||||
@@ -535,7 +538,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)));
|
||||
@@ -558,7 +561,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?;
|
||||
@@ -594,7 +597,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()))?
|
||||
}
|
||||
};
|
||||
|
||||
@@ -639,7 +642,7 @@ where
|
||||
Cache::add_or_update(&self.cache.user_policies, name, p, OffsetDateTime::now_utc());
|
||||
p.clone()
|
||||
} else {
|
||||
let mp = match self.cache.sts_policies.load().get(name) {
|
||||
match self.cache.sts_policies.load().get(name) {
|
||||
Some(p) => p.clone(),
|
||||
None => {
|
||||
let mut m = HashMap::new();
|
||||
@@ -651,8 +654,7 @@ where
|
||||
MappedPolicy::default()
|
||||
}
|
||||
}
|
||||
};
|
||||
mp
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -696,7 +698,7 @@ where
|
||||
|
||||
for group in self
|
||||
.cache
|
||||
.user_group_memberships
|
||||
.user_group_memeberships
|
||||
.load()
|
||||
.get(name)
|
||||
.cloned()
|
||||
@@ -737,7 +739,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() {
|
||||
@@ -763,7 +765,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,14 +793,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 policy not found {}", IamError::NoSuchPolicy)));
|
||||
return Err(Error::other(format!("need poliy not found {}", IamError::NoSuchPolicy)));
|
||||
}
|
||||
|
||||
self.api
|
||||
@@ -821,15 +823,15 @@ where
|
||||
pub async fn get_user_info(&self, name: &str) -> Result<madmin::UserInfo> {
|
||||
let users = self.cache.users.load();
|
||||
let policies = self.cache.user_policies.load();
|
||||
let group_members = self.cache.user_group_memberships.load();
|
||||
let group_members = self.cache.user_group_memeberships.load();
|
||||
|
||||
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 {
|
||||
@@ -860,7 +862,7 @@ where
|
||||
|
||||
let users = self.cache.users.load();
|
||||
let policies = self.cache.user_policies.load();
|
||||
let group_members = self.cache.user_group_memberships.load();
|
||||
let group_members = self.cache.user_group_memeberships.load();
|
||||
|
||||
for (k, v) in users.iter() {
|
||||
if v.credentials.is_temp() || v.credentials.is_service_account() {
|
||||
@@ -894,7 +896,7 @@ where
|
||||
pub async fn get_bucket_users(&self, bucket_name: &str) -> Result<HashMap<String, madmin::UserInfo>> {
|
||||
let users = self.cache.users.load();
|
||||
let policies_cache = self.cache.user_policies.load();
|
||||
let group_members = self.cache.user_group_memberships.load();
|
||||
let group_members = self.cache.user_group_memeberships.load();
|
||||
let group_policy_cache = self.cache.group_policies.load();
|
||||
|
||||
let mut ret = HashMap::new();
|
||||
@@ -961,7 +963,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,7 +973,7 @@ where
|
||||
_ => auth::ACCOUNT_OFF,
|
||||
}
|
||||
};
|
||||
let user_entity = UserIdentity::from(Credentials {
|
||||
let user_entiry = UserIdentity::from(Credentials {
|
||||
access_key: access_key.to_string(),
|
||||
secret_key: args.secret_key.to_string(),
|
||||
status: status.to_owned(),
|
||||
@@ -979,21 +981,21 @@ where
|
||||
});
|
||||
|
||||
self.api
|
||||
.save_user_identity(access_key, UserType::Reg, user_entity.clone(), None)
|
||||
.save_user_identity(access_key, UserType::Reg, user_entiry.clone(), None)
|
||||
.await?;
|
||||
|
||||
self.update_user_with_claims(access_key, user_entity)?;
|
||||
self.update_user_with_claims(access_key, user_entiry)?;
|
||||
|
||||
Ok(OffsetDateTime::now_utc())
|
||||
}
|
||||
|
||||
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 {
|
||||
if let Some(member_of) = self.cache.user_group_memberships.load().get(access_key) {
|
||||
if let Some(member_of) = self.cache.user_group_memeberships.load().get(access_key) {
|
||||
for member in member_of.iter() {
|
||||
let _ = self
|
||||
.remove_members_from_group(member, vec![access_key.to_string()], false)
|
||||
@@ -1041,13 +1043,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();
|
||||
@@ -1064,21 +1066,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 = {
|
||||
@@ -1088,7 +1090,7 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let user_entity = UserIdentity::from(Credentials {
|
||||
let user_entiry = UserIdentity::from(Credentials {
|
||||
access_key: access_key.to_string(),
|
||||
secret_key: u.credentials.secret_key.clone(),
|
||||
status: status.to_owned(),
|
||||
@@ -1096,10 +1098,10 @@ where
|
||||
});
|
||||
|
||||
self.api
|
||||
.save_user_identity(access_key, UserType::Reg, user_entity.clone(), None)
|
||||
.save_user_identity(access_key, UserType::Reg, user_entiry.clone(), None)
|
||||
.await?;
|
||||
|
||||
self.update_user_with_claims(access_key, user_entity)?;
|
||||
self.update_user_with_claims(access_key, user_entiry)?;
|
||||
|
||||
Ok(OffsetDateTime::now_utc())
|
||||
}
|
||||
@@ -1123,7 +1125,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() {
|
||||
@@ -1135,7 +1137,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();
|
||||
@@ -1143,10 +1145,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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1167,12 +1169,12 @@ where
|
||||
|
||||
Cache::add_or_update(&self.cache.groups, group, &gi, OffsetDateTime::now_utc());
|
||||
|
||||
let user_group_memberships = self.cache.user_group_memberships.load();
|
||||
let user_group_memeberships = self.cache.user_group_memeberships.load();
|
||||
members.iter().for_each(|member| {
|
||||
if let Some(m) = user_group_memberships.get(member) {
|
||||
if let Some(m) = user_group_memeberships.get(member) {
|
||||
let mut m = m.clone();
|
||||
m.insert(group.to_string());
|
||||
Cache::add_or_update(&self.cache.user_group_memberships, member, &m, OffsetDateTime::now_utc());
|
||||
Cache::add_or_update(&self.cache.user_group_memeberships, member, &m, OffsetDateTime::now_utc());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1181,13 +1183,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 {
|
||||
@@ -1213,7 +1215,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(),
|
||||
@@ -1240,7 +1242,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());
|
||||
@@ -1252,12 +1254,12 @@ where
|
||||
|
||||
Cache::add_or_update(&self.cache.groups, name, &gi, OffsetDateTime::now_utc());
|
||||
|
||||
let user_group_memberships = self.cache.user_group_memberships.load();
|
||||
let user_group_memeberships = self.cache.user_group_memeberships.load();
|
||||
members.iter().for_each(|member| {
|
||||
if let Some(m) = user_group_memberships.get(member) {
|
||||
if let Some(m) = user_group_memeberships.get(member) {
|
||||
let mut m = m.clone();
|
||||
m.remove(name);
|
||||
Cache::add_or_update(&self.cache.user_group_memberships, member, &m, OffsetDateTime::now_utc());
|
||||
Cache::add_or_update(&self.cache.user_group_memeberships, member, &m, OffsetDateTime::now_utc());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1266,7 +1268,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();
|
||||
@@ -1274,10 +1276,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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1287,10 +1289,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() {
|
||||
@@ -1308,23 +1310,23 @@ where
|
||||
}
|
||||
|
||||
fn remove_group_from_memberships_map(&self, group: &str) {
|
||||
let user_group_memberships = self.cache.user_group_memberships.load();
|
||||
for (k, v) in user_group_memberships.iter() {
|
||||
let user_group_memeberships = self.cache.user_group_memeberships.load();
|
||||
for (k, v) in user_group_memeberships.iter() {
|
||||
if v.contains(group) {
|
||||
let mut m = v.clone();
|
||||
m.remove(group);
|
||||
Cache::add_or_update(&self.cache.user_group_memberships, k, &m, OffsetDateTime::now_utc());
|
||||
Cache::add_or_update(&self.cache.user_group_memeberships, k, &m, OffsetDateTime::now_utc());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_group_memberships_map(&self, group: &str, gi: &GroupInfo) {
|
||||
let user_group_memberships = self.cache.user_group_memberships.load();
|
||||
let user_group_memeberships = self.cache.user_group_memeberships.load();
|
||||
for member in gi.members.iter() {
|
||||
if let Some(m) = user_group_memberships.get(member) {
|
||||
if let Some(m) = user_group_memeberships.get(member) {
|
||||
let mut m = m.clone();
|
||||
m.insert(group.to_string());
|
||||
Cache::add_or_update(&self.cache.user_group_memberships, member, &m, OffsetDateTime::now_utc());
|
||||
Cache::add_or_update(&self.cache.user_group_memeberships, member, &m, OffsetDateTime::now_utc());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1442,7 +1444,7 @@ where
|
||||
Cache::delete(&self.cache.users, name, OffsetDateTime::now_utc());
|
||||
}
|
||||
|
||||
let member_of = self.cache.user_group_memberships.load();
|
||||
let member_of = self.cache.user_group_memeberships.load();
|
||||
if let Some(m) = member_of.get(name) {
|
||||
for group in m.iter() {
|
||||
if let Err(err) = self.remove_members_from_group(group, vec![name.to_string()], true).await {
|
||||
@@ -1589,7 +1591,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];
|
||||
@@ -1599,7 +1601,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) {
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
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 serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@@ -49,7 +49,7 @@ pub trait Store: Clone + Send + Sync + 'static {
|
||||
m: &mut HashMap<String, MappedPolicy>,
|
||||
) -> Result<()>;
|
||||
async fn load_mapped_policys(&self, user_type: UserType, is_group: bool, m: &mut HashMap<String, MappedPolicy>)
|
||||
-> Result<()>;
|
||||
-> Result<()>;
|
||||
|
||||
async fn load_all(&self, cache: &Cache) -> Result<()>;
|
||||
}
|
||||
|
||||
+39
-38
@@ -1,26 +1,25 @@
|
||||
use super::{GroupInfo, MappedPolicy, Store, UserType};
|
||||
use crate::error::{Error, Result, is_err_config_not_found};
|
||||
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,
|
||||
com::{delete_config, read_config, read_config_with_metadata, save_config},
|
||||
},
|
||||
store::ECStore,
|
||||
store_api::{ObjectInfo, ObjectOptions},
|
||||
store_list_objects::{ObjectInfoOrErr, WalkOptions},
|
||||
utils::path::{path_join_buf, SLASH_SEPARATOR},
|
||||
};
|
||||
use futures::future::join_all;
|
||||
use lazy_static::lazy_static;
|
||||
use policy::{auth::UserIdentity, policy::PolicyDoc};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use rustfs_utils::path::{SLASH_SEPARATOR, path_join_buf};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tokio::sync::broadcast::{self, Receiver as B_Receiver};
|
||||
use tokio::sync::mpsc::{self, Sender};
|
||||
@@ -153,7 +152,7 @@ impl ObjectStore {
|
||||
let _ = sender
|
||||
.send(StringOrErr {
|
||||
item: None,
|
||||
err: Some(err),
|
||||
err: Some(err.into()),
|
||||
})
|
||||
.await;
|
||||
return;
|
||||
@@ -207,13 +206,13 @@ impl ObjectStore {
|
||||
let mut futures = Vec::with_capacity(names.len());
|
||||
|
||||
for name in names {
|
||||
let policy_name = ecstore::utils::path::dir(name);
|
||||
let policy_name = rustfs_utils::path::dir(name);
|
||||
futures.push(async move {
|
||||
match self.load_policy(&policy_name).await {
|
||||
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())
|
||||
}
|
||||
@@ -239,13 +238,13 @@ impl ObjectStore {
|
||||
let mut futures = Vec::with_capacity(names.len());
|
||||
|
||||
for name in names {
|
||||
let user_name = ecstore::utils::path::dir(name);
|
||||
let user_name = rustfs_utils::path::dir(name);
|
||||
futures.push(async move {
|
||||
match self.load_user_identity(&user_name, user_type).await {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,7 +464,7 @@ impl Store for ObjectStore {
|
||||
}
|
||||
|
||||
if let Some(item) = v.item {
|
||||
let name = ecstore::utils::path::dir(&item);
|
||||
let name = rustfs_utils::path::dir(&item);
|
||||
self.load_user(&name, user_type, m).await?;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -525,7 +526,7 @@ impl Store for ObjectStore {
|
||||
}
|
||||
|
||||
if let Some(item) = v.item {
|
||||
let name = ecstore::utils::path::dir(&item);
|
||||
let name = rustfs_utils::path::dir(&item);
|
||||
self.load_group(&name, m).await?;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -589,7 +590,7 @@ impl Store for ObjectStore {
|
||||
}
|
||||
|
||||
if let Some(item) = v.item {
|
||||
let name = ecstore::utils::path::dir(&item);
|
||||
let name = rustfs_utils::path::dir(&item);
|
||||
self.load_policy_doc(&name, m).await?;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -689,7 +690,7 @@ impl Store for ObjectStore {
|
||||
continue;
|
||||
}
|
||||
|
||||
let policy_name = ecstore::utils::path::dir(&policies_list[idx]);
|
||||
let policy_name = rustfs_utils::path::dir(&policies_list[idx]);
|
||||
|
||||
info!("load policy: {}", policy_name);
|
||||
|
||||
@@ -705,7 +706,7 @@ impl Store for ObjectStore {
|
||||
continue;
|
||||
}
|
||||
|
||||
let policy_name = ecstore::utils::path::dir(&policies_list[idx]);
|
||||
let policy_name = rustfs_utils::path::dir(&policies_list[idx]);
|
||||
info!("load policy: {}", policy_name);
|
||||
policy_docs_cache.insert(policy_name, p);
|
||||
}
|
||||
@@ -733,7 +734,7 @@ impl Store for ObjectStore {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = ecstore::utils::path::dir(&item_name_list[idx]);
|
||||
let name = rustfs_utils::path::dir(&item_name_list[idx]);
|
||||
info!("load reg user: {}", name);
|
||||
user_items_cache.insert(name, p);
|
||||
}
|
||||
@@ -747,7 +748,7 @@ impl Store for ObjectStore {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = ecstore::utils::path::dir(&item_name_list[idx]);
|
||||
let name = rustfs_utils::path::dir(&item_name_list[idx]);
|
||||
info!("load reg user: {}", name);
|
||||
user_items_cache.insert(name, p);
|
||||
}
|
||||
@@ -763,10 +764,10 @@ impl Store for ObjectStore {
|
||||
let mut items_cache = CacheEntity::default();
|
||||
|
||||
for item in item_name_list.iter() {
|
||||
let name = ecstore::utils::path::dir(item);
|
||||
let name = rustfs_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)));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -842,11 +843,11 @@ impl Store for ObjectStore {
|
||||
let mut items_cache = HashMap::default();
|
||||
|
||||
for item in item_name_list.iter() {
|
||||
let name = ecstore::utils::path::dir(item);
|
||||
let name = rustfs_utils::path::dir(item);
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -879,7 +880,7 @@ impl Store for ObjectStore {
|
||||
for item in item_name_list.iter() {
|
||||
info!("load sts user path: {}", item);
|
||||
|
||||
let name = ecstore::utils::path::dir(item);
|
||||
let name = rustfs_utils::path::dir(item);
|
||||
info!("load sts user: {}", name);
|
||||
if let Err(err) = self.load_user(&name, UserType::Sts, &mut sts_items_cache).await {
|
||||
info!("load sts user failed: {}", err);
|
||||
|
||||
+37
-36
@@ -1,35 +1,36 @@
|
||||
use crate::error::Error as IamError;
|
||||
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::IamCache;
|
||||
use crate::manager::extract_jwt_claims;
|
||||
use crate::manager::get_default_policyes;
|
||||
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 ecstore::utils::crypto::base64_decode;
|
||||
// use ecstore::utils::crypto::base64_encode;
|
||||
use madmin::AddOrUpdateUserReq;
|
||||
use madmin::GroupDesc;
|
||||
use policy::arn::ARN;
|
||||
use policy::auth::ACCOUNT_ON;
|
||||
use policy::auth::Credentials;
|
||||
use policy::auth::UserIdentity;
|
||||
use policy::auth::contains_reserved_chars;
|
||||
use policy::auth::create_new_credentials_with_metadata;
|
||||
use policy::auth::generate_credentials;
|
||||
use policy::auth::is_access_key_valid;
|
||||
use policy::auth::is_secret_key_valid;
|
||||
use policy::auth::Credentials;
|
||||
use policy::auth::UserIdentity;
|
||||
use policy::auth::ACCOUNT_ON;
|
||||
use policy::policy::iam_policy_claim_name_sa;
|
||||
use policy::policy::Args;
|
||||
use policy::policy::Policy;
|
||||
use policy::policy::PolicyDoc;
|
||||
use policy::policy::EMBEDDED_POLICY_TYPE;
|
||||
use policy::policy::INHERITED_POLICY_TYPE;
|
||||
use serde_json::json;
|
||||
use policy::policy::Policy;
|
||||
use policy::policy::PolicyDoc;
|
||||
use policy::policy::iam_policy_claim_name_sa;
|
||||
use rustfs_utils::crypto::{base64_decode, base64_encode};
|
||||
use serde_json::Value;
|
||||
use serde_json::json;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use time::OffsetDateTime;
|
||||
@@ -81,7 +82,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 +124,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 +158,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 +168,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 +194,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 +218,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 +305,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 +313,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 +330,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 +364,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 +372,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 +389,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 +415,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 +432,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 +468,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
|
||||
|
||||
+6
-6
@@ -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 serde::{Serialize, de::DeserializeOwned};
|
||||
use std::io::{Error, Result};
|
||||
|
||||
/// Generates a random access key of the specified length.
|
||||
///
|
||||
@@ -24,7 +24,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);
|
||||
@@ -55,7 +55,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::rng();
|
||||
|
||||
@@ -68,7 +68,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()))
|
||||
}
|
||||
@@ -76,7 +76,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()),
|
||||
|
||||
Reference in New Issue
Block a user