kanidm_proto/scim_v1/
client.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//! These are types that a client will send to the server.
use super::ScimEntryGetQuery;
use super::ScimOauth2ClaimMapJoinChar;
use crate::attribute::{Attribute, SubAttribute};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use serde_with::formats::PreferMany;
use serde_with::OneOrMany;
use serde_with::{base64, formats, serde_as, skip_serializing_none};
use sshkey_attest::proto::PublicKey as SshPublicKey;
use std::collections::{BTreeMap, BTreeSet};
use time::format_description::well_known::Rfc3339;
use time::OffsetDateTime;
use uuid::Uuid;

pub type ScimSshPublicKeys = Vec<ScimSshPublicKey>;

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct ScimSshPublicKey {
    pub label: String,
    pub value: SshPublicKey,
}

#[serde_as]
#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct ScimReference {
    pub uuid: Option<Uuid>,
    pub value: Option<String>,
}

pub type ScimReferences = Vec<ScimReference>;

#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(transparent)]
pub struct ScimDateTime {
    #[serde_as(as = "Rfc3339")]
    pub date_time: OffsetDateTime,
}

#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ScimCertificate {
    #[serde_as(as = "base64::Base64<base64::UrlSafe, formats::Unpadded>")]
    pub der: Vec<u8>,
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ScimAddress {
    pub street_address: String,
    pub locality: String,
    pub region: String,
    pub postal_code: String,
    pub country: String,
}

#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2ClaimMap {
    pub group: Option<String>,
    pub group_uuid: Option<Uuid>,
    pub claim: String,
    pub join_char: ScimOauth2ClaimMapJoinChar,
    pub values: BTreeSet<String>,
}

#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ScimOAuth2ScopeMap {
    pub group: Option<String>,
    pub group_uuid: Option<Uuid>,
    pub scopes: BTreeSet<String>,
}

#[derive(Serialize, Debug, Clone)]
pub struct ScimEntryPutKanidm {
    pub id: Uuid,
    #[serde(flatten)]
    pub attrs: BTreeMap<Attribute, Option<super::server::ScimValueKanidm>>,
}

#[serde_as]
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ScimStrings(#[serde_as(as = "OneOrMany<_, PreferMany>")] pub Vec<String>);

#[derive(Debug, Clone, Deserialize, Default)]
pub struct ScimEntryPutGeneric {
    // id is only used to target the entry in question
    pub id: Uuid,

    #[serde(flatten)]
    /// Non-standard extension - allow query options to be set in a put request. This
    /// is because a put request also returns the entry state post put, so we want
    /// to allow putters to adjust and control what is returned here.
    pub query: ScimEntryGetQuery,

    // external_id can't be set by put
    // meta is skipped on put
    // Schemas are decoded as part of "attrs".
    /// Update an attribute to contain the following value state.
    /// If the attribute is None, it is removed.
    #[serde(flatten)]
    pub attrs: BTreeMap<Attribute, Option<JsonValue>>,
}

impl TryFrom<ScimEntryPutKanidm> for ScimEntryPutGeneric {
    type Error = serde_json::Error;

    fn try_from(value: ScimEntryPutKanidm) -> Result<Self, Self::Error> {
        let ScimEntryPutKanidm { id, attrs } = value;

        let attrs = attrs
            .into_iter()
            .map(|(attr, value)| {
                if let Some(v) = value {
                    serde_json::to_value(v).map(|json_value| (attr, Some(json_value)))
                } else {
                    Ok((attr, None))
                }
            })
            .collect::<Result<_, _>>()?;

        Ok(ScimEntryPutGeneric {
            id,
            attrs,
            query: Default::default(),
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct AttrPath {
    pub a: Attribute,
    pub s: Option<SubAttribute>,
}

impl From<Attribute> for AttrPath {
    fn from(a: Attribute) -> Self {
        Self { a, s: None }
    }
}

impl From<(Attribute, SubAttribute)> for AttrPath {
    fn from((a, s): (Attribute, SubAttribute)) -> Self {
        Self { a, s: Some(s) }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub enum ScimFilter {
    Or(Box<ScimFilter>, Box<ScimFilter>),
    And(Box<ScimFilter>, Box<ScimFilter>),
    Not(Box<ScimFilter>),

    Present(AttrPath),
    Equal(AttrPath, JsonValue),
    NotEqual(AttrPath, JsonValue),
    Contains(AttrPath, JsonValue),
    StartsWith(AttrPath, JsonValue),
    EndsWith(AttrPath, JsonValue),
    Greater(AttrPath, JsonValue),
    Less(AttrPath, JsonValue),
    GreaterOrEqual(AttrPath, JsonValue),
    LessOrEqual(AttrPath, JsonValue),

    Complex(Attribute, Box<ScimComplexFilter>),
}

#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub enum ScimComplexFilter {
    Or(Box<ScimComplexFilter>, Box<ScimComplexFilter>),
    And(Box<ScimComplexFilter>, Box<ScimComplexFilter>),
    Not(Box<ScimComplexFilter>),

    Present(SubAttribute),
    Equal(SubAttribute, JsonValue),
    NotEqual(SubAttribute, JsonValue),
    Contains(SubAttribute, JsonValue),
    StartsWith(SubAttribute, JsonValue),
    EndsWith(SubAttribute, JsonValue),
    Greater(SubAttribute, JsonValue),
    Less(SubAttribute, JsonValue),
    GreaterOrEqual(SubAttribute, JsonValue),
    LessOrEqual(SubAttribute, JsonValue),
}