mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-20 19:42:17 +00:00
fix(user): service account expiration handling with RFC3339 (#3078)
fix(user): enhance service account expiration handling with RFC3339 support Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
@@ -500,6 +500,22 @@ where
|
|||||||
Ok(Option::<Vec<String>>::deserialize(deserializer)?.unwrap_or_default())
|
Ok(Option::<Vec<String>>::deserialize(deserializer)?.unwrap_or_default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_service_account_expiration(expiration: &str) -> Result<OffsetDateTime, time::Error> {
|
||||||
|
const LEGACY_SERVICE_ACCOUNT_EXPIRATION_FORMAT: &[time::format_description::BorrowedFormatItem<'_>] = time::macros::format_description!(
|
||||||
|
"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond] [offset_hour sign:mandatory]:[offset_minute]:[offset_second]"
|
||||||
|
);
|
||||||
|
|
||||||
|
OffsetDateTime::parse(expiration, &Rfc3339)
|
||||||
|
.or_else(|_| OffsetDateTime::parse(expiration, LEGACY_SERVICE_ACCOUNT_EXPIRATION_FORMAT).map_err(Into::into))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_optional_service_account_expiration<S>(expiration: &Option<OffsetDateTime>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
time::serde::rfc3339::option::serialize(expiration, serializer)
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_optional_service_account_expiration<'de, D>(deserializer: D) -> Result<Option<OffsetDateTime>, D::Error>
|
fn deserialize_optional_service_account_expiration<'de, D>(deserializer: D) -> Result<Option<OffsetDateTime>, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
@@ -513,7 +529,7 @@ where
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let expiration = OffsetDateTime::parse(expiration, &Rfc3339).map_err(D::Error::custom)?;
|
let expiration = parse_service_account_expiration(expiration).map_err(D::Error::custom)?;
|
||||||
if expiration.unix_timestamp() == 0 {
|
if expiration.unix_timestamp() == 0 {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
@@ -549,6 +565,7 @@ pub struct SRSvcAccCreate {
|
|||||||
#[serde(
|
#[serde(
|
||||||
default,
|
default,
|
||||||
skip_serializing_if = "Option::is_none",
|
skip_serializing_if = "Option::is_none",
|
||||||
|
serialize_with = "serialize_optional_service_account_expiration",
|
||||||
deserialize_with = "deserialize_optional_service_account_expiration"
|
deserialize_with = "deserialize_optional_service_account_expiration"
|
||||||
)]
|
)]
|
||||||
pub expiration: Option<OffsetDateTime>,
|
pub expiration: Option<OffsetDateTime>,
|
||||||
@@ -706,6 +723,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
use time::macros::datetime;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_account_status_default() {
|
fn test_account_status_default() {
|
||||||
@@ -1295,4 +1313,50 @@ mod tests {
|
|||||||
let svc: SRSvcAccCreate = serde_json::from_str(payload).unwrap();
|
let svc: SRSvcAccCreate = serde_json::from_str(payload).unwrap();
|
||||||
assert!(svc.expiration.is_none());
|
assert!(svc.expiration.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sr_svc_acc_create_serializes_expiration_as_rfc3339() {
|
||||||
|
let svc = SRSvcAccCreate {
|
||||||
|
parent: "useralpha".to_string(),
|
||||||
|
access_key: "svcalpha".to_string(),
|
||||||
|
secret_key: "svcAlphaSecret123".to_string(),
|
||||||
|
groups: Vec::new(),
|
||||||
|
claims: HashMap::new(),
|
||||||
|
session_policy: SRSessionPolicy::default(),
|
||||||
|
status: "on".to_string(),
|
||||||
|
name: "uploaderKey".to_string(),
|
||||||
|
description: "alpha upload key".to_string(),
|
||||||
|
expiration: Some(datetime!(9999-01-01 00:00:00 UTC)),
|
||||||
|
api_version: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let json = serde_json::to_string(&svc).unwrap();
|
||||||
|
assert!(
|
||||||
|
json.contains(r#""expiration":"9999-01-01T00:00:00Z""#),
|
||||||
|
"service account export expiration should be RFC3339; got: {json}"
|
||||||
|
);
|
||||||
|
assert!(!json.contains("+00:00:00"), "export must not use the legacy offset format: {json}");
|
||||||
|
|
||||||
|
let decoded: SRSvcAccCreate = serde_json::from_str(&json).unwrap();
|
||||||
|
assert_eq!(decoded.expiration, svc.expiration);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sr_svc_acc_create_deserializes_legacy_exported_expiration() {
|
||||||
|
let payload = r#"{
|
||||||
|
"parent": "useralpha",
|
||||||
|
"accessKey": "svcalpha",
|
||||||
|
"secretKey": "svcAlphaSecret123",
|
||||||
|
"groups": [],
|
||||||
|
"claims": {},
|
||||||
|
"sessionPolicy": null,
|
||||||
|
"status": "on",
|
||||||
|
"name": "uploaderKey",
|
||||||
|
"description": "alpha upload key",
|
||||||
|
"expiration": "9999-01-01 00:00:00.0 +00:00:00"
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let svc: SRSvcAccCreate = serde_json::from_str(payload).unwrap();
|
||||||
|
assert_eq!(svc.expiration, Some(datetime!(9999-01-01 00:00:00 UTC)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user