mirror of
https://github.com/rustfs/rustfs.git
synced 2026-01-17 01:30:33 +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";
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,9 @@ pub enum Error {
|
||||
#[error("action not allowed")]
|
||||
IAMActionNotAllowed,
|
||||
|
||||
#[error("invalid expiration")]
|
||||
InvalidExpiration,
|
||||
|
||||
#[error("no secret key with access key")]
|
||||
NoSecretKeyWithAccessKey,
|
||||
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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(());
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user