use crate::core::assertion::attribute::{Attribute, AttributeValue};
use crate::profiles::error::ProfileError;
pub const X500_NAME_FORMAT: &str = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri";
pub const OID_PREFIX: &str = "urn:oid:";
pub const OID_CN: &str = "urn:oid:2.5.4.3";
pub const OID_SN: &str = "urn:oid:2.5.4.4";
pub const OID_GIVEN_NAME: &str = "urn:oid:2.5.4.42";
pub const OID_MAIL: &str = "urn:oid:0.9.2342.19200300.100.1.3";
pub const OID_UID: &str = "urn:oid:0.9.2342.19200300.100.1.1";
pub const OID_EPPN: &str = "urn:oid:1.3.6.1.4.1.5923.1.1.1.6";
pub const OID_EPA: &str = "urn:oid:1.3.6.1.4.1.5923.1.1.1.1";
pub const OID_EPE: &str = "urn:oid:1.3.6.1.4.1.5923.1.1.1.7";
pub const OID_EPTID: &str = "urn:oid:1.3.6.1.4.1.5923.1.1.1.10";
pub const OID_DISPLAY_NAME: &str = "urn:oid:2.16.840.1.113730.3.1.241";
pub fn validate_x500_attribute(attr: &Attribute) -> Result<(), ProfileError> {
if let Some(ref fmt) = attr.name_format {
if fmt != X500_NAME_FORMAT {
return Err(ProfileError::InvalidAttributeNameFormat {
expected: X500_NAME_FORMAT.to_string(),
actual: fmt.clone(),
});
}
}
if !attr.name.starts_with(OID_PREFIX) {
return Err(ProfileError::InvalidAttributeNameFormat {
expected: format!("name starting with {OID_PREFIX}"),
actual: attr.name.clone(),
});
}
Ok(())
}
pub fn x500_string_attribute(oid: &str, friendly_name: &str, values: &[&str]) -> Attribute {
Attribute {
name: oid.to_string(),
name_format: Some(X500_NAME_FORMAT.to_string()),
friendly_name: Some(friendly_name.to_string()),
values: values
.iter()
.map(|v| AttributeValue::String(v.to_string()))
.collect(),
}
}
pub fn mail_attribute(values: &[&str]) -> Attribute {
x500_string_attribute(OID_MAIL, "mail", values)
}
pub fn cn_attribute(values: &[&str]) -> Attribute {
x500_string_attribute(OID_CN, "cn", values)
}
pub fn given_name_attribute(values: &[&str]) -> Attribute {
x500_string_attribute(OID_GIVEN_NAME, "givenName", values)
}
pub fn sn_attribute(values: &[&str]) -> Attribute {
x500_string_attribute(OID_SN, "sn", values)
}
pub fn uid_attribute(values: &[&str]) -> Attribute {
x500_string_attribute(OID_UID, "uid", values)
}
pub fn eppn_attribute(value: &str) -> Attribute {
x500_string_attribute(OID_EPPN, "eduPersonPrincipalName", &[value])
}
pub fn epa_attribute(values: &[&str]) -> Attribute {
x500_string_attribute(OID_EPA, "eduPersonAffiliation", values)
}
pub fn epe_attribute(values: &[&str]) -> Attribute {
x500_string_attribute(OID_EPE, "eduPersonEntitlement", values)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_x500_attribute_ok() {
let attr = mail_attribute(&["user@example.com"]);
assert!(validate_x500_attribute(&attr).is_ok());
}
#[test]
fn test_validate_x500_attribute_wrong_format() {
let attr = Attribute {
name: OID_MAIL.to_string(),
name_format: Some("urn:oasis:names:tc:SAML:2.0:attrname-format:basic".to_string()),
friendly_name: None,
values: vec![],
};
assert!(validate_x500_attribute(&attr).is_err());
}
#[test]
fn test_validate_x500_attribute_wrong_name() {
let attr = Attribute {
name: "email".to_string(), name_format: Some(X500_NAME_FORMAT.to_string()),
friendly_name: None,
values: vec![],
};
assert!(validate_x500_attribute(&attr).is_err());
}
#[test]
fn test_x500_string_attribute() {
let attr = x500_string_attribute(OID_CN, "cn", &["John Doe"]);
assert_eq!(attr.name, OID_CN);
assert_eq!(attr.name_format, Some(X500_NAME_FORMAT.to_string()));
assert_eq!(attr.friendly_name, Some("cn".to_string()));
assert_eq!(attr.values.len(), 1);
}
#[test]
fn test_mail_attribute() {
let attr = mail_attribute(&["user@example.com", "admin@example.com"]);
assert_eq!(attr.name, OID_MAIL);
assert_eq!(attr.values.len(), 2);
}
#[test]
fn test_eppn_attribute() {
let attr = eppn_attribute("user@example.com");
assert_eq!(attr.name, OID_EPPN);
assert_eq!(
attr.friendly_name,
Some("eduPersonPrincipalName".to_string())
);
}
}