mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-28 07:57:01 +00:00
iam add_user
This commit is contained in:
@@ -100,7 +100,7 @@ pub struct Credentials {
|
|||||||
pub status: String,
|
pub status: String,
|
||||||
pub parent_user: String,
|
pub parent_user: String,
|
||||||
pub groups: Option<Vec<String>>,
|
pub groups: Option<Vec<String>>,
|
||||||
pub claims: Option<HashMap<String, Vec<String>>>,
|
pub claims: Option<HashMap<String, String>>,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -20,7 +20,7 @@ use tokio::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arn::ARN,
|
arn::ARN,
|
||||||
auth::{Credentials, UserIdentity},
|
auth::{self, Credentials, UserIdentity},
|
||||||
cache::Cache,
|
cache::Cache,
|
||||||
format::Format,
|
format::Format,
|
||||||
handler::Handler,
|
handler::Handler,
|
||||||
@@ -309,4 +309,16 @@ where
|
|||||||
|
|
||||||
Ok(m)
|
Ok(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn add_user(&self, access_key: &str, secret_key: &str, status: &str) -> crate::Result<()> {
|
||||||
|
let status = {
|
||||||
|
match status {
|
||||||
|
"disabled" => auth::ACCOUNT_ON,
|
||||||
|
auth::ACCOUNT_ON => auth::ACCOUNT_ON,
|
||||||
|
_ => auth::ACCOUNT_OFF,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ use ecstore::utils::path::path_join;
|
|||||||
use ecstore::utils::xml;
|
use ecstore::utils::xml;
|
||||||
use ecstore::GLOBAL_Endpoints;
|
use ecstore::GLOBAL_Endpoints;
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
use http::Uri;
|
use http::{HeaderMap, Uri};
|
||||||
use hyper::StatusCode;
|
use hyper::StatusCode;
|
||||||
use iam::auth::create_new_credentials_with_metadata;
|
use iam::auth::{create_new_credentials_with_metadata, get_claims_from_token_with_secret};
|
||||||
use iam::{auth, get_global_action_cred};
|
use iam::{auth, get_global_action_cred};
|
||||||
use madmin::metrics::RealtimeMetrics;
|
use madmin::metrics::RealtimeMetrics;
|
||||||
use madmin::utils::parse_duration;
|
use madmin::utils::parse_duration;
|
||||||
@@ -93,11 +93,21 @@ pub struct AssumeRoleRequest {
|
|||||||
// pub parent_user: String,
|
// pub parent_user: String,
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Default)]
|
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||||
pub struct STSClaims {
|
pub struct STSClaims {
|
||||||
parent: String,
|
pub parent: String,
|
||||||
exp: usize,
|
pub exp: usize,
|
||||||
access_key: String,
|
pub access_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl STSClaims {
|
||||||
|
pub fn to_map(&self) -> HashMap<String, String> {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
m.insert("parent".to_string(), self.parent.clone());
|
||||||
|
m.insert("exp".to_string(), self.exp.to_string());
|
||||||
|
m.insert("access_key".to_string(), self.access_key.clone());
|
||||||
|
m
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_token_signing_key() -> Option<String> {
|
fn get_token_signing_key() -> Option<String> {
|
||||||
@@ -108,11 +118,13 @@ fn get_token_signing_key() -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_key_valid(st: &str, ak: &str) -> S3Result<(auth::Credentials, bool)> {
|
pub async fn check_key_valid(token: Option<String>, ak: &str) -> S3Result<(auth::Credentials, bool)> {
|
||||||
let Some(mut cred) = get_global_action_cred() else {
|
let Some(mut cred) = get_global_action_cred() else {
|
||||||
return Err(s3_error!(InternalError, "action cred not init"));
|
return Err(s3_error!(InternalError, "action cred not init"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let sys_cred = cred.clone();
|
||||||
|
|
||||||
if cred.access_key != ak {
|
if cred.access_key != ak {
|
||||||
let Ok(iam_store) = iam::get() else { return Err(s3_error!(InternalError, "iam not init")) };
|
let Ok(iam_store) = iam::get() else { return Err(s3_error!(InternalError, "iam not init")) };
|
||||||
|
|
||||||
@@ -135,34 +147,67 @@ pub async fn check_key_valid(st: &str, ak: &str) -> S3Result<(auth::Credentials,
|
|||||||
return Err(s3_error!(InvalidRequest, "check key failed"));
|
return Err(s3_error!(InvalidRequest, "check key failed"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok((cred, true));
|
|
||||||
}
|
}
|
||||||
unimplemented!()
|
|
||||||
|
if let Some(st) = token {
|
||||||
|
let claims = check_claims_from_token(&st, &cred)
|
||||||
|
.map_err(|e| S3Error::with_message(S3ErrorCode::InternalError, format!("check claims failed {}", e)))?;
|
||||||
|
cred.claims = Some(claims.to_map());
|
||||||
|
}
|
||||||
|
|
||||||
|
let owner = sys_cred.access_key == cred.access_key || cred.parent_user == sys_cred.access_key;
|
||||||
|
|
||||||
|
// permitRootAccess
|
||||||
|
// SessionPolicyName
|
||||||
|
Ok((cred, owner))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_claims_from_token(token: &str, cred: &auth::Credentials) -> crate::Result<HashMap<String, Vec<String>>> {
|
pub fn check_claims_from_token(token: &str, cred: &auth::Credentials) -> S3Result<STSClaims> {
|
||||||
// if !token.is_empty() && cred.access_key.is_empty() {
|
if !token.is_empty() && cred.access_key.is_empty() {
|
||||||
// return Err(Error::NoAccessKey);
|
return Err(s3_error!(InvalidRequest, "no access key"));
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if token.is_empty() && cred.is_temp() && !cred.is_service_account() {
|
if token.is_empty() && cred.is_temp() && !cred.is_service_account() {
|
||||||
// return Err(Error::InvalidToken);
|
return Err(s3_error!(InvalidRequest, "invalid token"));
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if !token.is_empty() && !cred.is_temp() {
|
if !token.is_empty() && !cred.is_temp() {
|
||||||
// return Err(Error::InvalidToken);
|
return Err(s3_error!(InvalidRequest, "invalid token"));
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if !cred.is_service_account() && cred.is_temp() && token != cred.session_token {
|
if !cred.is_service_account() && cred.is_temp() && token != cred.session_token {
|
||||||
// return Err(Error::InvalidToken);
|
return Err(s3_error!(InvalidRequest, "invalid token"));
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if cred.is_temp() || cred.is_expired() {
|
if cred.is_temp() || cred.is_expired() {
|
||||||
// return Err(Error::InvalidAccessKey);
|
return Err(s3_error!(InvalidRequest, "invalid access key"));
|
||||||
// }
|
}
|
||||||
|
|
||||||
unimplemented!()
|
let Some(sys_cred) = get_global_action_cred() else {
|
||||||
|
return Err(s3_error!(InternalError, "action cred not init"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut secret = sys_cred.secret_key;
|
||||||
|
|
||||||
|
let mut token = token;
|
||||||
|
|
||||||
|
if cred.is_service_account() {
|
||||||
|
token = cred.session_token.as_str();
|
||||||
|
secret = cred.secret_key.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !token.is_empty() {
|
||||||
|
let claims: STSClaims =
|
||||||
|
get_claims_from_token_with_secret(token, &secret).map_err(|_e| s3_error!(InvalidRequest, "invalid token"))?;
|
||||||
|
return Ok(claims);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(STSClaims::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_session_token(hds: &HeaderMap) -> Option<String> {
|
||||||
|
hds.get("x-amz-security-token")
|
||||||
|
.map(|v| v.to_str().unwrap_or_default().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AssumeRoleHandle {}
|
pub struct AssumeRoleHandle {}
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ use serde::Deserialize;
|
|||||||
use serde_urlencoded::from_bytes;
|
use serde_urlencoded::from_bytes;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::admin::router::Operation;
|
use crate::admin::{
|
||||||
|
handlers::{check_key_valid, get_session_token},
|
||||||
|
router::Operation,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Default)]
|
#[derive(Debug, Deserialize, Default)]
|
||||||
pub struct AddUserQuery {
|
pub struct AddUserQuery {
|
||||||
@@ -29,6 +32,10 @@ impl Operation for AddUser {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let Some(input_cred) = req.credentials else {
|
||||||
|
return Err(s3_error!(InvalidRequest, "get cred failed"));
|
||||||
|
};
|
||||||
|
|
||||||
let ak = query.access_key.as_deref().unwrap_or_default();
|
let ak = query.access_key.as_deref().unwrap_or_default();
|
||||||
|
|
||||||
if let Some(sys_cred) = get_global_action_cred() {
|
if let Some(sys_cred) = get_global_action_cred() {
|
||||||
@@ -46,6 +53,14 @@ impl Operation for AddUser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let token = get_session_token(&req.headers);
|
||||||
|
|
||||||
|
let (cred, _) = check_key_valid(token, &input_cred.access_key).await?;
|
||||||
|
|
||||||
|
if (cred.is_temp() || cred.is_service_account()) && cred.parent_user == input_cred.access_key {
|
||||||
|
return Err(s3_error!(InvalidArgument, "can't create user with service account access key"));
|
||||||
|
}
|
||||||
|
|
||||||
warn!("handle AddUser");
|
warn!("handle AddUser");
|
||||||
return Err(s3_error!(NotImplemented));
|
return Err(s3_error!(NotImplemented));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user