authly_common/
document.rs1use std::collections::BTreeMap;
4
5use serde::Deserialize;
6use toml::Spanned;
7use uuid::Uuid;
8
9use crate::{id::EntityId, property::QualifiedAttributeName};
10
11#[derive(Deserialize)]
13#[serde(deny_unknown_fields)]
14#[allow(missing_docs)]
15pub struct Document {
16 #[serde(rename = "authly-document")]
18 pub authly_document: AuthlyDocument,
19
20 #[serde(default, rename = "local-settings")]
22 pub local_settings: Option<BTreeMap<Spanned<String>, Spanned<String>>>,
23
24 #[serde(default)]
25 pub entity: Vec<Entity>,
26
27 #[serde(default, rename = "service-entity")]
28 pub service_entity: Vec<Entity>,
29
30 #[serde(default)]
31 pub domain: Vec<Domain>,
32
33 #[serde(default, rename = "service-domain")]
34 pub service_domain: Vec<ServiceDomain>,
35
36 #[serde(default)]
37 pub email: Vec<Email>,
38
39 #[serde(default, rename = "password-hash")]
40 pub password_hash: Vec<PasswordHash>,
41
42 #[serde(default)]
43 pub members: Vec<Members>,
44
45 #[serde(default, rename = "entity-attribute-assignment")]
46 pub entity_attribute_assignment: Vec<EntityAttributeAssignment>,
47
48 #[serde(default, rename = "entity-property")]
49 pub entity_property: Vec<EntityProperty>,
50
51 #[serde(default, rename = "resource-property")]
52 pub resource_property: Vec<ResourceProperty>,
53
54 #[serde(default)]
55 pub policy: Vec<Policy>,
56
57 #[serde(default, rename = "policy-binding")]
58 pub policy_binding: Vec<PolicyBinding>,
59}
60
61#[derive(Deserialize)]
63#[serde(deny_unknown_fields)]
64pub struct AuthlyDocument {
65 pub id: Spanned<Uuid>,
67}
68
69pub type DynamicObject = serde_json::Map<String, serde_json::Value>;
71
72#[derive(Deserialize, Debug)]
74#[serde(deny_unknown_fields)]
75pub struct Entity {
76 pub eid: Spanned<EntityId>,
78
79 #[serde(default)]
81 pub label: Option<Spanned<String>>,
82
83 #[serde(default)]
86 pub metadata: Option<Spanned<DynamicObject>>,
87
88 #[serde(default)]
90 pub attributes: Vec<Spanned<QualifiedAttributeName>>,
91
92 #[serde(default)]
94 pub username: Option<Spanned<String>>,
95
96 #[serde(default)]
98 pub email: Vec<Spanned<String>>,
99
100 #[serde(default, rename = "password-hash")]
102 pub password_hash: Vec<String>,
103
104 #[serde(default)]
106 pub hosts: Vec<String>,
107
108 #[serde(default, rename = "kubernetes-account")]
110 pub kubernetes_account: Option<KubernetesAccount>,
111}
112
113#[derive(Deserialize, Debug)]
115#[serde(deny_unknown_fields)]
116pub struct Domain {
117 pub label: Spanned<String>,
119
120 #[serde(default)]
123 pub metadata: Option<Spanned<DynamicObject>>,
124}
125
126#[derive(Deserialize, Debug)]
128#[serde(deny_unknown_fields)]
129pub struct ServiceDomain {
130 pub service: Spanned<String>,
132
133 pub domain: Spanned<String>,
135}
136
137#[derive(Deserialize, Debug)]
139#[serde(deny_unknown_fields)]
140pub struct Email {
141 pub entity: Spanned<String>,
143
144 pub value: Spanned<String>,
146}
147
148#[derive(Deserialize, Debug)]
150#[serde(deny_unknown_fields)]
151pub struct PasswordHash {
152 pub entity: Spanned<String>,
154
155 pub hash: String,
157}
158
159#[derive(Deserialize, Debug)]
163#[serde(deny_unknown_fields)]
164pub struct Members {
165 pub entity: Spanned<String>,
167
168 pub members: Vec<Spanned<String>>,
170}
171
172#[derive(Deserialize)]
174#[serde(deny_unknown_fields)]
175pub struct EntityProperty {
176 pub namespace: Spanned<String>,
178
179 pub label: Spanned<String>,
181
182 #[serde(default)]
184 pub attributes: Vec<Spanned<String>>,
185}
186
187#[derive(Default, Deserialize, Debug)]
189#[serde(deny_unknown_fields)]
190pub struct KubernetesAccount {
191 #[serde(default)]
195 pub namespace: Option<String>,
196
197 pub name: String,
199}
200
201#[derive(Deserialize)]
203#[serde(deny_unknown_fields)]
204pub struct ResourceProperty {
205 pub namespace: Spanned<String>,
207
208 pub label: Spanned<String>,
210
211 #[serde(default)]
213 pub attributes: Vec<Spanned<String>>,
214}
215
216#[derive(Deserialize)]
220#[serde(deny_unknown_fields)]
221pub struct Policy {
222 pub label: Spanned<String>,
224
225 #[serde(default)]
227 pub allow: Option<Spanned<String>>,
228
229 #[serde(default)]
231 pub deny: Option<Spanned<String>>,
232}
233
234#[derive(Deserialize)]
236pub struct PolicyBinding {
237 pub attributes: Vec<Spanned<QualifiedAttributeName>>,
239
240 pub policies: Vec<Spanned<String>>,
242}
243
244#[derive(Deserialize)]
246pub struct EntityAttributeAssignment {
247 pub entity: Spanned<String>,
249
250 pub attributes: Vec<Spanned<QualifiedAttributeName>>,
252}
253
254impl Document {
255 pub fn from_toml(toml: &str) -> anyhow::Result<Self> {
257 Ok(preprocess(toml::from_str(toml)?))
258 }
259}
260
261fn preprocess(mut doc: Document) -> Document {
262 for user in &mut doc.entity {
263 let label = user
264 .label
265 .get_or_insert_with(|| Spanned::new(0..0, Uuid::new_v4().to_string()));
266
267 for email in std::mem::take(&mut user.email) {
268 doc.email.push(Email {
269 entity: label.clone(),
270 value: email,
271 });
272 }
273
274 for pw_hash in std::mem::take(&mut user.password_hash) {
275 doc.password_hash.push(PasswordHash {
276 entity: label.clone(),
277 hash: pw_hash,
278 });
279 }
280 }
281
282 doc
283}