mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-28 07:57:01 +00:00
fix(admin): accept IAM service account exports (#2249)
Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
@@ -12,11 +12,12 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use serde_json::value::RawValue;
|
use serde_json::value::RawValue;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
use time::format_description::well_known::Rfc3339;
|
||||||
|
|
||||||
use crate::BackendInfo;
|
use crate::BackendInfo;
|
||||||
|
|
||||||
@@ -492,6 +493,30 @@ impl<'de> Deserialize<'de> for SRSessionPolicy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_vec_or_default<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Ok(Option::<Vec<String>>::deserialize(deserializer)?.unwrap_or_default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_optional_service_account_expiration<'de, D>(deserializer: D) -> Result<Option<OffsetDateTime>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let expiration = Option::<String>::deserialize(deserializer)?;
|
||||||
|
let Some(expiration) = expiration else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let expiration = OffsetDateTime::parse(&expiration, &Rfc3339).map_err(D::Error::custom)?;
|
||||||
|
if expiration.unix_timestamp() == 0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(expiration))
|
||||||
|
}
|
||||||
|
|
||||||
/// SRSvcAccCreate - create operation
|
/// SRSvcAccCreate - create operation
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SRSvcAccCreate {
|
pub struct SRSvcAccCreate {
|
||||||
@@ -503,6 +528,7 @@ pub struct SRSvcAccCreate {
|
|||||||
#[serde(rename = "secretKey")]
|
#[serde(rename = "secretKey")]
|
||||||
pub secret_key: String,
|
pub secret_key: String,
|
||||||
|
|
||||||
|
#[serde(default, deserialize_with = "deserialize_vec_or_default")]
|
||||||
pub groups: Vec<String>,
|
pub groups: Vec<String>,
|
||||||
|
|
||||||
pub claims: HashMap<String, serde_json::Value>,
|
pub claims: HashMap<String, serde_json::Value>,
|
||||||
@@ -516,7 +542,11 @@ pub struct SRSvcAccCreate {
|
|||||||
|
|
||||||
pub description: String,
|
pub description: String,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none",
|
||||||
|
deserialize_with = "deserialize_optional_service_account_expiration"
|
||||||
|
)]
|
||||||
pub expiration: Option<OffsetDateTime>,
|
pub expiration: Option<OffsetDateTime>,
|
||||||
|
|
||||||
#[serde(rename = "apiVersion", skip_serializing_if = "Option::is_none")]
|
#[serde(rename = "apiVersion", skip_serializing_if = "Option::is_none")]
|
||||||
|
|||||||
@@ -1120,6 +1120,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use rustfs_credentials::{Credentials, IAM_POLICY_CLAIM_NAME_SA};
|
use rustfs_credentials::{Credentials, IAM_POLICY_CLAIM_NAME_SA};
|
||||||
use rustfs_iam::error::Error as IamError;
|
use rustfs_iam::error::Error as IamError;
|
||||||
|
use rustfs_madmin::user::SRSvcAccCreate;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@@ -1205,6 +1206,57 @@ mod tests {
|
|||||||
assert!(imported_service_account_status("unknown").is_none());
|
assert!(imported_service_account_status("unknown").is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_service_account_import_accepts_null_groups_and_epoch_expiration() {
|
||||||
|
let payload = r#"{
|
||||||
|
"svcalpha": {
|
||||||
|
"parent": "useralpha",
|
||||||
|
"accessKey": "svcalpha",
|
||||||
|
"secretKey": "svcAlphaSecret123",
|
||||||
|
"groups": null,
|
||||||
|
"claims": {
|
||||||
|
"accessKey": "svcalpha",
|
||||||
|
"parent": "useralpha",
|
||||||
|
"sa-policy": "inherited-policy"
|
||||||
|
},
|
||||||
|
"sessionPolicy": null,
|
||||||
|
"status": "on",
|
||||||
|
"name": "uploaderKey",
|
||||||
|
"description": "alpha upload key",
|
||||||
|
"expiration": "1970-01-01T00:00:00Z"
|
||||||
|
}
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let svc_accts: HashMap<String, SRSvcAccCreate> = serde_json::from_str(payload).unwrap();
|
||||||
|
let svc = svc_accts.get("svcalpha").unwrap();
|
||||||
|
|
||||||
|
assert!(svc.groups.is_empty());
|
||||||
|
assert!(svc.expiration.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_service_account_import_preserves_non_zero_expiration() {
|
||||||
|
let payload = r#"{
|
||||||
|
"svcalpha": {
|
||||||
|
"parent": "useralpha",
|
||||||
|
"accessKey": "svcalpha",
|
||||||
|
"secretKey": "svcAlphaSecret123",
|
||||||
|
"groups": [],
|
||||||
|
"claims": {},
|
||||||
|
"sessionPolicy": null,
|
||||||
|
"status": "on",
|
||||||
|
"name": "uploaderKey",
|
||||||
|
"description": "alpha upload key",
|
||||||
|
"expiration": "2030-01-02T03:04:05Z"
|
||||||
|
}
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let svc_accts: HashMap<String, SRSvcAccCreate> = serde_json::from_str(payload).unwrap();
|
||||||
|
let svc = svc_accts.get("svcalpha").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(svc.expiration.map(|expiration| expiration.unix_timestamp()), Some(1893553445));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_group_policy_mappings_use_regular_user_type() {
|
fn test_group_policy_mappings_use_regular_user_type() {
|
||||||
assert_eq!(GROUP_POLICY_MAPPING_USER_TYPE, rustfs_iam::store::UserType::Reg);
|
assert_eq!(GROUP_POLICY_MAPPING_USER_TYPE, rustfs_iam::store::UserType::Reg);
|
||||||
|
|||||||
Reference in New Issue
Block a user