mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-17 18:27:49 +00:00
fix iam service_account bugs
This commit is contained in:
@@ -152,10 +152,7 @@ impl Credentials {
|
|||||||
const IAM_POLICY_CLAIM_NAME_SA: &str = "sa-policy";
|
const IAM_POLICY_CLAIM_NAME_SA: &str = "sa-policy";
|
||||||
self.claims
|
self.claims
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|x| {
|
.map(|x| x.get(IAM_POLICY_CLAIM_NAME_SA).is_some_and(|_| !self.parent_user.is_empty()))
|
||||||
x.get(IAM_POLICY_CLAIM_NAME_SA)
|
|
||||||
.map_or(false, |_| !self.parent_user.is_empty())
|
|
||||||
})
|
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,10 +161,7 @@ impl Credentials {
|
|||||||
return self
|
return self
|
||||||
.claims
|
.claims
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|x| {
|
.map(|x| x.get(&iam_policy_claim_name_sa()).is_some_and(|v| v == INHERITED_POLICY_TYPE))
|
||||||
x.get(&iam_policy_claim_name_sa())
|
|
||||||
.map_or(false, |v| v == INHERITED_POLICY_TYPE)
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ pub enum Error {
|
|||||||
#[error("action not allowed")]
|
#[error("action not allowed")]
|
||||||
IAMActionNotAllowed,
|
IAMActionNotAllowed,
|
||||||
|
|
||||||
|
#[error("invalid expiration")]
|
||||||
|
InvalidExpiration,
|
||||||
|
|
||||||
#[error("no secret key with access key")]
|
#[error("no secret key with access key")]
|
||||||
NoSecretKeyWithAccessKey,
|
NoSecretKeyWithAccessKey,
|
||||||
|
|
||||||
|
|||||||
@@ -846,7 +846,9 @@ impl Store for ObjectStore {
|
|||||||
let name = ecstore::utils::path::dir(item);
|
let name = ecstore::utils::path::dir(item);
|
||||||
info!("load svc user: {}", name);
|
info!("load svc user: {}", name);
|
||||||
if let Err(err) = self.load_user(&name, UserType::Svc, &mut items_cache).await {
|
if let Err(err) = self.load_user(&name, UserType::Svc, &mut items_cache).await {
|
||||||
return Err(Error::msg(std::format!("load_user failed: {}", err)));
|
if !is_err_no_such_user(&err) {
|
||||||
|
return Err(Error::msg(std::format!("load svc user failed: {}", err)));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-2
@@ -197,6 +197,10 @@ impl<T: Store> IamSys<T> {
|
|||||||
return Err(IamError::IAMActionNotAllowed.into());
|
return Err(IamError::IAMActionNotAllowed.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.expiration.is_none() {
|
||||||
|
return Err(IamError::InvalidExpiration.into());
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: check allow_site_replicator_account
|
// TODO: check allow_site_replicator_account
|
||||||
|
|
||||||
let policy_buf = if let Some(policy) = opts.session_policy {
|
let policy_buf = if let Some(policy) = opts.session_policy {
|
||||||
@@ -229,9 +233,13 @@ impl<T: Store> IamSys<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set expiration time default to 1 hour
|
||||||
m.insert(
|
m.insert(
|
||||||
"exp".to_string(),
|
"exp".to_string(),
|
||||||
serde_json::Value::Number(serde_json::Number::from(opts.expiration.map_or(0, |t| t.unix_timestamp()))),
|
serde_json::Value::Number(serde_json::Number::from(
|
||||||
|
opts.expiration
|
||||||
|
.map_or(OffsetDateTime::now_utc().unix_timestamp() + 3600, |t| t.unix_timestamp()),
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let (access_key, secret_key) = if !opts.access_key.is_empty() || !opts.secret_key.is_empty() {
|
let (access_key, secret_key) = if !opts.access_key.is_empty() || !opts.secret_key.is_empty() {
|
||||||
@@ -385,7 +393,7 @@ impl<T: Store> IamSys<T> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
if u.credentials.is_service_account() {
|
if !u.credentials.is_service_account() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-3
@@ -1,5 +1,5 @@
|
|||||||
use ecstore::error::{Error, Result};
|
use ecstore::error::{Error, Result};
|
||||||
use jsonwebtoken::{encode, Algorithm, DecodingKey, EncodingKey, Header};
|
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header};
|
||||||
use rand::{Rng, RngCore};
|
use rand::{Rng, RngCore};
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ pub fn gen_secret_key(length: usize) -> crate::Result<String> {
|
|||||||
|
|
||||||
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) -> Result<String, jsonwebtoken::errors::Error> {
|
||||||
let header = Header::new(Algorithm::HS512);
|
let header = Header::new(Algorithm::HS512);
|
||||||
encode(&header, &claims, &EncodingKey::from_secret(secret.as_bytes()))
|
jsonwebtoken::encode(&header, &claims, &EncodingKey::from_secret(secret.as_bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_claims<T: DeserializeOwned>(
|
pub fn extract_claims<T: DeserializeOwned>(
|
||||||
@@ -58,7 +58,8 @@ pub fn extract_claims<T: DeserializeOwned>(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{gen_access_key, gen_secret_key};
|
use super::{gen_access_key, gen_secret_key, generate_jwt};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_gen_access_key() {
|
fn test_gen_access_key() {
|
||||||
@@ -76,4 +77,34 @@ mod tests {
|
|||||||
let b = gen_secret_key(10).unwrap();
|
let b = gen_secret_key(10).unwrap();
|
||||||
assert_ne!(a, b);
|
assert_ne!(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
struct Claims {
|
||||||
|
sub: String,
|
||||||
|
company: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_jwt() {
|
||||||
|
let claims = Claims {
|
||||||
|
sub: "user1".to_string(),
|
||||||
|
company: "example".to_string(),
|
||||||
|
};
|
||||||
|
let secret = "my_secret";
|
||||||
|
let token = generate_jwt(&claims, secret).unwrap();
|
||||||
|
|
||||||
|
assert!(!token.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_extract_claims() {
|
||||||
|
// let claims = Claims {
|
||||||
|
// sub: "user1".to_string(),
|
||||||
|
// company: "example".to_string(),
|
||||||
|
// };
|
||||||
|
// let secret = "my_secret";
|
||||||
|
// let token = generate_jwt(&claims, secret).unwrap();
|
||||||
|
// let decoded_claims = extract_claims::<Claims>(&token, secret).unwrap();
|
||||||
|
// assert_eq!(decoded_claims.claims, claims);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ pub struct UpdateServiceAccountReq {
|
|||||||
pub new_description: Option<String>,
|
pub new_description: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "newExpiration", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "newExpiration", skip_serializing_if = "Option::is_none")]
|
||||||
|
#[serde(with = "time::serde::rfc3339::option")]
|
||||||
pub new_expiration: Option<OffsetDateTime>,
|
pub new_expiration: Option<OffsetDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,16 @@ impl Operation for AddServiceAccount {
|
|||||||
.validate()
|
.validate()
|
||||||
.map_err(|e| S3Error::with_message(InvalidRequest, e.to_string()))?;
|
.map_err(|e| S3Error::with_message(InvalidRequest, e.to_string()))?;
|
||||||
|
|
||||||
|
let session_policy = if let Some(policy) = &create_req.policy {
|
||||||
|
let p = Policy::parse_config(policy.as_bytes()).map_err(|e| {
|
||||||
|
debug!("parse policy failed, e: {:?}", e);
|
||||||
|
s3_error!(InvalidArgument, "parse policy failed")
|
||||||
|
})?;
|
||||||
|
Some(p)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let Some(sys_cred) = get_global_action_cred() else {
|
let Some(sys_cred) = get_global_action_cred() else {
|
||||||
return Err(s3_error!(InvalidRequest, "get sys cred failed"));
|
return Err(s3_error!(InvalidRequest, "get sys cred failed"));
|
||||||
};
|
};
|
||||||
@@ -95,7 +105,7 @@ impl Operation for AddServiceAccount {
|
|||||||
name: create_req.name,
|
name: create_req.name,
|
||||||
description: create_req.description,
|
description: create_req.description,
|
||||||
expiration: create_req.expiration,
|
expiration: create_req.expiration,
|
||||||
session_policy: create_req.policy.and_then(|p| Policy::parse_config(p.as_bytes()).ok()),
|
session_policy,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user