fix iam service_account bugs

This commit is contained in:
weisd
2025-03-03 15:53:56 +08:00
parent c8fbb54fac
commit 4ff452ffd2
7 changed files with 64 additions and 15 deletions

View File

@@ -152,10 +152,7 @@ impl Credentials {
const IAM_POLICY_CLAIM_NAME_SA: &str = "sa-policy";
self.claims
.as_ref()
.map(|x| {
x.get(IAM_POLICY_CLAIM_NAME_SA)
.map_or(false, |_| !self.parent_user.is_empty())
})
.map(|x| x.get(IAM_POLICY_CLAIM_NAME_SA).is_some_and(|_| !self.parent_user.is_empty()))
.unwrap_or_default()
}
@@ -164,10 +161,7 @@ impl Credentials {
return self
.claims
.as_ref()
.map(|x| {
x.get(&iam_policy_claim_name_sa())
.map_or(false, |v| v == INHERITED_POLICY_TYPE)
})
.map(|x| x.get(&iam_policy_claim_name_sa()).is_some_and(|v| v == INHERITED_POLICY_TYPE))
.unwrap_or_default();
}

View File

@@ -79,6 +79,9 @@ pub enum Error {
#[error("action not allowed")]
IAMActionNotAllowed,
#[error("invalid expiration")]
InvalidExpiration,
#[error("no secret key with access key")]
NoSecretKeyWithAccessKey,

View File

@@ -846,7 +846,9 @@ impl Store for ObjectStore {
let name = ecstore::utils::path::dir(item);
info!("load svc user: {}", name);
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)));
}
};
}

View File

@@ -197,6 +197,10 @@ impl<T: Store> IamSys<T> {
return Err(IamError::IAMActionNotAllowed.into());
}
if opts.expiration.is_none() {
return Err(IamError::InvalidExpiration.into());
}
// TODO: check allow_site_replicator_account
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(
"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() {
@@ -385,7 +393,7 @@ impl<T: Store> IamSys<T> {
return Ok(());
};
if u.credentials.is_service_account() {
if !u.credentials.is_service_account() {
return Ok(());
}

View File

@@ -1,5 +1,5 @@
use ecstore::error::{Error, Result};
use jsonwebtoken::{encode, Algorithm, DecodingKey, EncodingKey, Header};
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header};
use rand::{Rng, RngCore};
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> {
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>(
@@ -58,7 +58,8 @@ pub fn extract_claims<T: DeserializeOwned>(
#[cfg(test)]
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]
fn test_gen_access_key() {
@@ -76,4 +77,34 @@ mod tests {
let b = gen_secret_key(10).unwrap();
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);
// }
}

View File

@@ -211,6 +211,7 @@ pub struct UpdateServiceAccountReq {
pub new_description: Option<String>,
#[serde(rename = "newExpiration", skip_serializing_if = "Option::is_none")]
#[serde(with = "time::serde::rfc3339::option")]
pub new_expiration: Option<OffsetDateTime>,
}

View File

@@ -53,6 +53,16 @@ impl Operation for AddServiceAccount {
.validate()
.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 {
return Err(s3_error!(InvalidRequest, "get sys cred failed"));
};
@@ -95,7 +105,7 @@ impl Operation for AddServiceAccount {
name: create_req.name,
description: create_req.description,
expiration: create_req.expiration,
session_policy: create_req.policy.and_then(|p| Policy::parse_config(p.as_bytes()).ok()),
session_policy,
..Default::default()
};