init group

This commit is contained in:
weisd
2025-01-13 20:46:18 +08:00
parent 4d9eca1667
commit 133a294024
11 changed files with 235 additions and 21 deletions
+12 -12
View File
@@ -11,7 +11,7 @@ use time::OffsetDateTime;
use crate::{
auth::UserIdentity,
policy::{Args, MappedPolicy, Policy, PolicyDoc},
policy::{Args, GroupInfo, MappedPolicy, Policy, PolicyDoc},
Error,
};
@@ -21,7 +21,7 @@ pub struct Cache {
pub user_policies: ArcSwap<CacheEntity<MappedPolicy>>,
pub sts_accounts: ArcSwap<CacheEntity<UserIdentity>>,
pub sts_policies: ArcSwap<CacheEntity<MappedPolicy>>,
pub groups: ArcSwap<CacheEntity<String>>,
pub groups: ArcSwap<CacheEntity<GroupInfo>>,
pub user_group_memeberships: ArcSwap<CacheEntity<HashSet<String>>>,
pub group_policies: ArcSwap<CacheEntity<MappedPolicy>>,
}
@@ -89,7 +89,7 @@ impl Cache {
impl CacheInner {
#[inline]
pub fn get_user<'a>(&self, user_name: &'a str) -> Option<&UserIdentity> {
pub fn get_user(&self, user_name: &str) -> Option<&UserIdentity> {
self.users.get(user_name).or_else(|| self.sts_accounts.get(user_name))
}
@@ -99,7 +99,7 @@ impl CacheInner {
/// 如果是临时用户,返回Ok(Some(partent_name)))
/// 如果不是临时用户,返回Ok(None)
fn is_temp_user<'a>(&self, user_name: &'a str) -> crate::Result<Option<&str>> {
fn is_temp_user(&self, user_name: &str) -> crate::Result<Option<&str>> {
let user = self
.get_user(user_name)
.ok_or_else(|| Error::NoSuchUser(user_name.to_owned()))?;
@@ -113,7 +113,7 @@ impl CacheInner {
/// 如果是临时用户,返回Ok(Some(partent_name)))
/// 如果不是临时用户,返回Ok(None)
fn is_service_account<'a>(&self, user_name: &'a str) -> crate::Result<Option<&str>> {
fn is_service_account(&self, user_name: &str) -> crate::Result<Option<&str>> {
let user = self
.get_user(user_name)
.ok_or_else(|| Error::NoSuchUser(user_name.to_owned()))?;
@@ -137,7 +137,7 @@ impl CacheInner {
false
}
pub fn is_allowed(&self, args: Args) -> bool {
pub fn is_allowed(&self, _args: Args) -> bool {
todo!()
}
@@ -199,7 +199,7 @@ pub struct CacheInner {
pub user_policies: G<MappedPolicy>,
pub sts_accounts: G<UserIdentity>,
pub sts_policies: G<MappedPolicy>,
pub groups: G<String>,
pub groups: G<GroupInfo>,
pub user_group_memeberships: G<HashSet<String>>,
pub group_policies: G<MappedPolicy>,
}
@@ -239,7 +239,7 @@ mod tests {
for (index, key) in (0..100).map(|x| x.to_string()).enumerate() {
let c = &cache;
f.push(async move {
Cache::add_or_update(&c, &key, &index, OffsetDateTime::now_utc());
Cache::add_or_update(c, &key, &index, OffsetDateTime::now_utc());
});
}
join_all(f).await;
@@ -259,7 +259,7 @@ mod tests {
for (index, key) in (0..100).map(|x| x.to_string()).enumerate() {
let c = &cache;
f.push(async move {
Cache::add_or_update(&c, &key, &index, OffsetDateTime::now_utc());
Cache::add_or_update(c, &key, &index, OffsetDateTime::now_utc());
});
}
join_all(f).await;
@@ -274,7 +274,7 @@ mod tests {
for (index, key) in (0..100).map(|x| x.to_string()).enumerate() {
let c = &cache;
f.push(async move {
Cache::add_or_update(&c, &key, &(index * 1000), OffsetDateTime::now_utc());
Cache::add_or_update(c, &key, &(index * 1000), OffsetDateTime::now_utc());
});
}
join_all(f).await;
@@ -294,7 +294,7 @@ mod tests {
for (index, key) in (0..100).map(|x| x.to_string()).enumerate() {
let c = &cache;
f.push(async move {
Cache::add_or_update(&c, &key, &index, OffsetDateTime::now_utc());
Cache::add_or_update(c, &key, &index, OffsetDateTime::now_utc());
});
}
join_all(f).await;
@@ -309,7 +309,7 @@ mod tests {
for key in (0..100).map(|x| x.to_string()) {
let c = &cache;
f.push(async move {
Cache::delete(&c, &key, OffsetDateTime::now_utc());
Cache::delete(c, &key, OffsetDateTime::now_utc());
});
}
join_all(f).await;
+10
View File
@@ -17,6 +17,12 @@ pub enum Error {
#[error("user '{0}' does not exist")]
NoSuchUser(String),
#[error("group '{0}' does not exist")]
NoSuchGroup(String),
#[error("group not empty")]
GroupNotEmpty,
#[error("invalid arguments specified")]
InvalidArgument,
@@ -57,3 +63,7 @@ pub enum Error {
}
pub type Result<T> = std::result::Result<T, Error>;
pub fn is_err_no_such_user(e: &Error) -> bool {
matches!(e, Error::NoSuchUser(_))
}
+5 -5
View File
@@ -128,11 +128,7 @@ pub async fn delete_user(ak: &str, _notify: bool) -> crate::Result<()> {
}
pub async fn is_temp_user(ak: &str) -> crate::Result<(bool, String)> {
if let Some(user) = get()?.get_user(ak).await? {
Ok((user.credentials.is_temp(), user.credentials.parent_user))
} else {
Err(Error::NoSuchUser(ak.to_string()))
}
get()?.is_temp_user(ak).await
}
pub async fn get_user_info(ak: &str) -> crate::Result<madmin::UserInfo> {
@@ -146,3 +142,7 @@ pub async fn set_user_status(ak: &str, status: AccountStatus) -> crate::Result<O
pub async fn list_service_accounts(ak: &str) -> crate::Result<Vec<Credentials>> {
get()?.list_service_accounts(ak).await
}
pub async fn remove_users_from_group(group: &str, members: Vec<String>) -> crate::Result<OffsetDateTime> {
get()?.remove_users_from_group(group, members).await
}
+61 -2
View File
@@ -94,7 +94,7 @@ where
Ok(())
}
async fn notify(&self) {
async fn _notify(&self) {
self.send_chan.send(OffsetDateTime::now_utc().unix_timestamp()).await.unwrap();
}
@@ -354,7 +354,7 @@ where
Ok(user_entiry.update_at.unwrap_or(OffsetDateTime::now_utc()))
}
pub async fn delete_user(&self, access_key: &str, utype: UserType) -> crate::Result<()> {
pub async fn delete_user(&self, access_key: &str, _utype: UserType) -> crate::Result<()> {
let users = self.cache.users.load();
if let Some(x) = users.get(access_key) {
if x.credentials.is_temp() {
@@ -363,6 +363,7 @@ where
}
// if utype == UserType::Reg {}
// TODO: Delete user from group memberships
let path = format!("config/iam/{}{}/identity.json", UserType::Reg.prefix(), access_key);
debug!("delete object: {path:?}");
@@ -467,4 +468,62 @@ where
Ok(user_entiry.update_at.unwrap_or(OffsetDateTime::now_utc()))
}
pub async fn is_temp_user(&self, access_key: &str) -> crate::Result<(bool, String)> {
let users = self.cache.users.load();
let u = match users.get(access_key) {
Some(u) => u,
None => return Err(Error::NoSuchUser(access_key.to_string())),
};
if u.credentials.is_temp() {
Ok((true, u.credentials.parent_user.clone()))
} else {
Ok((false, String::new()))
}
}
pub async fn remove_users_from_group(&self, group: &str, members: Vec<String>) -> crate::Result<OffsetDateTime> {
if group.is_empty() {
return Err(Error::InvalidArgument);
}
let users = self.cache.users.load();
let groups = self.cache.groups.load();
let group_members_cache = self.cache.user_group_memeberships.load();
for member in members.iter() {
let u = users.get(member).ok_or(Error::NoSuchUser(member.to_string()))?;
if u.credentials.is_temp() || u.credentials.is_service_account() {
return Err(Error::IAMActionNotAllowed);
}
}
let group_info = groups.get(group).ok_or(Error::NoSuchGroup(group.to_string()))?;
let mut group_members = match group_members_cache.get(group) {
Some(m) => m.clone(),
None => return Err(Error::NoSuchGroup(group.to_string())),
};
if members.is_empty() && !group_members.is_empty() {
return Err(Error::GroupNotEmpty);
}
if members.is_empty() {
group_members.clear();
} else {
for member in members.iter() {
group_members.remove(member);
}
}
let path = format!("config/iam/group/{}.json", group);
debug!("save object: {path:?}");
self.api.save_iam_config(&members, path).await?;
Cache::add_or_update(&self.cache.user_group_memeberships, group, &group_members, OffsetDateTime::now_utc());
Ok(OffsetDateTime::now_utc())
}
}
+2 -1
View File
@@ -23,7 +23,8 @@ pub trait Store: Clone + Send + Sync + 'static {
async fn load_all(&self, cache: &Cache) -> crate::Result<()>;
fn get_default_policyes() -> HashMap<String, PolicyDoc> {
DEFAULT_POLICIES
let default_policies = DEFAULT_POLICIES;
default_policies
.iter()
.map(|(n, p)| {
(
+1 -1
View File
@@ -1,7 +1,7 @@
use crate::Error;
use jsonwebtoken::{encode, Algorithm, DecodingKey, EncodingKey, Header};
use rand::{Rng, RngCore};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde::{de::DeserializeOwned, Serialize};
pub fn gen_access_key(length: usize) -> crate::Result<String> {
const ALPHA_NUMERIC_TABLE: [char; 36] = [