use super::ScimMail;
use super::ScimOauth2ClaimMapJoinChar;
use super::ScimSshPublicKey;
use crate::attribute::Attribute;
use crate::internal::UiHint;
use scim_proto::ScimEntryHeader;
use serde::Serialize;
use serde_with::{base64, formats, hex::Hex, serde_as, skip_serializing_none};
use std::collections::{BTreeMap, BTreeSet};
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;
use url::Url;
use utoipa::ToSchema;
use uuid::Uuid;
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Debug, Clone, ToSchema)]
pub struct ScimEntryKanidm {
#[serde(flatten)]
pub header: ScimEntryHeader,
pub ext_access_check: Option<ScimEffectiveAccess>,
#[serde(flatten)]
pub attrs: BTreeMap<Attribute, ScimValueKanidm>,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
pub enum ScimAttributeEffectiveAccess {
Grant,
Denied,
Allow(BTreeSet<Attribute>),
}
impl ScimAttributeEffectiveAccess {
pub fn check(&self, attr: &Attribute) -> bool {
match self {
Self::Grant => true,
Self::Denied => false,
Self::Allow(set) => set.contains(attr),
}
}
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimEffectiveAccess {
pub ident: Uuid,
pub delete: bool,
pub search: ScimAttributeEffectiveAccess,
pub modify_present: ScimAttributeEffectiveAccess,
pub modify_remove: ScimAttributeEffectiveAccess,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimAddress {
pub formatted: String,
pub street_address: String,
pub locality: String,
pub region: String,
pub postal_code: String,
pub country: String,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimApplicationPassword {
pub uuid: Uuid,
pub application_uuid: Uuid,
pub label: String,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimBinary {
pub label: String,
#[serde_as(as = "base64::Base64<base64::UrlSafe, formats::Unpadded>")]
pub value: Vec<u8>,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimCertificate {
#[serde_as(as = "Hex")]
pub s256: Vec<u8>,
#[serde_as(as = "base64::Base64<base64::UrlSafe, formats::Unpadded>")]
pub der: Vec<u8>,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimAuditString {
#[serde_as(as = "Rfc3339")]
pub date_time: OffsetDateTime,
pub value: String,
}
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub enum ScimIntentTokenState {
Valid,
InProgress,
Consumed,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimIntentToken {
pub token_id: String,
pub state: ScimIntentTokenState,
#[serde_as(as = "Rfc3339")]
pub expires: OffsetDateTime,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimKeyInternal {
pub key_id: String,
pub status: String,
pub usage: String,
#[serde_as(as = "Rfc3339")]
pub valid_from: OffsetDateTime,
}
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimAuthSession {
pub id: Uuid,
#[serde_as(as = "Option<Rfc3339>")]
pub expires: Option<OffsetDateTime>,
#[serde_as(as = "Option<Rfc3339>")]
pub revoked: Option<OffsetDateTime>,
#[serde_as(as = "Rfc3339")]
pub issued_at: OffsetDateTime,
pub issued_by: Uuid,
pub credential_id: Uuid,
pub auth_type: String,
pub session_scope: String,
}
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2Session {
pub id: Uuid,
pub parent_id: Option<Uuid>,
pub client_id: Uuid,
#[serde_as(as = "Rfc3339")]
pub issued_at: OffsetDateTime,
#[serde_as(as = "Option<Rfc3339>")]
pub expires: Option<OffsetDateTime>,
#[serde_as(as = "Option<Rfc3339>")]
pub revoked: Option<OffsetDateTime>,
}
#[serde_as]
#[skip_serializing_none]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimApiToken {
pub id: Uuid,
pub label: String,
#[serde_as(as = "Option<Rfc3339>")]
pub expires: Option<OffsetDateTime>,
#[serde_as(as = "Rfc3339")]
pub issued_at: OffsetDateTime,
pub issued_by: Uuid,
pub scope: String,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2ScopeMap {
pub group: String,
pub group_uuid: Uuid,
pub scopes: BTreeSet<String>,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2ClaimMap {
pub group: String,
pub group_uuid: Uuid,
pub claim: String,
pub join_char: ScimOauth2ClaimMapJoinChar,
pub values: BTreeSet<String>,
}
#[derive(Serialize, Debug, Clone, PartialEq, Eq, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct ScimReference {
pub uuid: Uuid,
pub value: String,
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
#[serde(untagged)]
pub enum ScimValueKanidm {
Bool(bool),
Uint32(u32),
Integer(i64),
Decimal(f64),
String(String),
DateTime(#[serde_as(as = "Rfc3339")] OffsetDateTime),
Reference(Url),
Uuid(Uuid),
EntryReference(ScimReference),
EntryReferences(Vec<ScimReference>),
ArrayString(Vec<String>),
ArrayDateTime(#[serde_as(as = "Vec<Rfc3339>")] Vec<OffsetDateTime>),
ArrayUuid(Vec<Uuid>),
ArrayBinary(Vec<ScimBinary>),
ArrayCertificate(Vec<ScimCertificate>),
Address(Vec<ScimAddress>),
Mail(Vec<ScimMail>),
ApplicationPassword(Vec<ScimApplicationPassword>),
AuditString(Vec<ScimAuditString>),
SshPublicKey(Vec<ScimSshPublicKey>),
AuthSession(Vec<ScimAuthSession>),
OAuth2Session(Vec<ScimOAuth2Session>),
ApiToken(Vec<ScimApiToken>),
IntentToken(Vec<ScimIntentToken>),
OAuth2ScopeMap(Vec<ScimOAuth2ScopeMap>),
OAuth2ClaimMap(Vec<ScimOAuth2ClaimMap>),
KeyInternal(Vec<ScimKeyInternal>),
UiHints(Vec<UiHint>),
}
#[serde_as]
#[derive(Serialize, Debug, Clone, ToSchema)]
pub struct ScimPerson {
pub uuid: Uuid,
pub name: String,
pub displayname: String,
pub spn: String,
pub description: Option<String>,
pub mails: Vec<ScimMail>,
pub managed_by: Option<ScimReference>,
pub groups: Vec<ScimReference>,
}
impl TryFrom<ScimEntryKanidm> for ScimPerson {
type Error = ();
fn try_from(scim_entry: ScimEntryKanidm) -> Result<Self, Self::Error> {
let uuid = scim_entry.header.id;
let name = scim_entry
.attrs
.get(&Attribute::Name)
.and_then(|v| match v {
ScimValueKanidm::String(s) => Some(s.clone()),
_ => None,
})
.ok_or(())?;
let displayname = scim_entry
.attrs
.get(&Attribute::DisplayName)
.and_then(|v| match v {
ScimValueKanidm::String(s) => Some(s.clone()),
_ => None,
})
.ok_or(())?;
let spn = scim_entry
.attrs
.get(&Attribute::Spn)
.and_then(|v| match v {
ScimValueKanidm::String(s) => Some(s.clone()),
_ => None,
})
.ok_or(())?;
let description = scim_entry
.attrs
.get(&Attribute::Description)
.and_then(|v| match v {
ScimValueKanidm::String(s) => Some(s.clone()),
_ => None,
});
let mails = scim_entry
.attrs
.get(&Attribute::Mail)
.and_then(|v| match v {
ScimValueKanidm::Mail(m) => Some(m.clone()),
_ => None,
})
.unwrap_or_default();
let groups = scim_entry
.attrs
.get(&Attribute::DirectMemberOf)
.and_then(|v| match v {
ScimValueKanidm::EntryReferences(v) => Some(v.clone()),
_ => None,
})
.unwrap_or_default();
let managed_by = scim_entry
.attrs
.get(&Attribute::EntryManagedBy)
.and_then(|v| match v {
ScimValueKanidm::EntryReference(v) => Some(v.clone()),
_ => None,
});
Ok(ScimPerson {
uuid,
name,
displayname,
spn,
description,
mails,
managed_by,
groups,
})
}
}
impl From<bool> for ScimValueKanidm {
fn from(b: bool) -> Self {
Self::Bool(b)
}
}
impl From<OffsetDateTime> for ScimValueKanidm {
fn from(odt: OffsetDateTime) -> Self {
Self::DateTime(odt)
}
}
impl From<Vec<UiHint>> for ScimValueKanidm {
fn from(set: Vec<UiHint>) -> Self {
Self::UiHints(set)
}
}
impl From<Vec<OffsetDateTime>> for ScimValueKanidm {
fn from(set: Vec<OffsetDateTime>) -> Self {
Self::ArrayDateTime(set)
}
}
impl From<String> for ScimValueKanidm {
fn from(s: String) -> Self {
Self::String(s)
}
}
impl From<&str> for ScimValueKanidm {
fn from(s: &str) -> Self {
Self::String(s.to_string())
}
}
impl From<Vec<String>> for ScimValueKanidm {
fn from(set: Vec<String>) -> Self {
Self::ArrayString(set)
}
}
impl From<Uuid> for ScimValueKanidm {
fn from(u: Uuid) -> Self {
Self::Uuid(u)
}
}
impl From<Vec<Uuid>> for ScimValueKanidm {
fn from(set: Vec<Uuid>) -> Self {
Self::ArrayUuid(set)
}
}
impl From<u32> for ScimValueKanidm {
fn from(u: u32) -> Self {
Self::Uint32(u)
}
}
impl From<Vec<ScimAddress>> for ScimValueKanidm {
fn from(set: Vec<ScimAddress>) -> Self {
Self::Address(set)
}
}
impl From<Vec<ScimMail>> for ScimValueKanidm {
fn from(set: Vec<ScimMail>) -> Self {
Self::Mail(set)
}
}
impl From<Vec<ScimApplicationPassword>> for ScimValueKanidm {
fn from(set: Vec<ScimApplicationPassword>) -> Self {
Self::ApplicationPassword(set)
}
}
impl From<Vec<ScimAuditString>> for ScimValueKanidm {
fn from(set: Vec<ScimAuditString>) -> Self {
Self::AuditString(set)
}
}
impl From<Vec<ScimBinary>> for ScimValueKanidm {
fn from(set: Vec<ScimBinary>) -> Self {
Self::ArrayBinary(set)
}
}
impl From<Vec<ScimCertificate>> for ScimValueKanidm {
fn from(set: Vec<ScimCertificate>) -> Self {
Self::ArrayCertificate(set)
}
}
impl From<Vec<ScimSshPublicKey>> for ScimValueKanidm {
fn from(set: Vec<ScimSshPublicKey>) -> Self {
Self::SshPublicKey(set)
}
}
impl From<Vec<ScimAuthSession>> for ScimValueKanidm {
fn from(set: Vec<ScimAuthSession>) -> Self {
Self::AuthSession(set)
}
}
impl From<Vec<ScimOAuth2Session>> for ScimValueKanidm {
fn from(set: Vec<ScimOAuth2Session>) -> Self {
Self::OAuth2Session(set)
}
}
impl From<Vec<ScimApiToken>> for ScimValueKanidm {
fn from(set: Vec<ScimApiToken>) -> Self {
Self::ApiToken(set)
}
}
impl From<Vec<ScimIntentToken>> for ScimValueKanidm {
fn from(set: Vec<ScimIntentToken>) -> Self {
Self::IntentToken(set)
}
}
impl From<Vec<ScimOAuth2ScopeMap>> for ScimValueKanidm {
fn from(set: Vec<ScimOAuth2ScopeMap>) -> Self {
Self::OAuth2ScopeMap(set)
}
}
impl From<Vec<ScimOAuth2ClaimMap>> for ScimValueKanidm {
fn from(set: Vec<ScimOAuth2ClaimMap>) -> Self {
Self::OAuth2ClaimMap(set)
}
}
impl From<Vec<ScimKeyInternal>> for ScimValueKanidm {
fn from(set: Vec<ScimKeyInternal>) -> Self {
Self::KeyInternal(set)
}
}