1use super::errors::WebError;
4use super::middleware::caching::{cache_me_short, dont_cache_me};
5use super::middleware::KOpId;
6use super::ServerState;
7use crate::https::apidocs::response_schema::{ApiResponseWithout200, DefaultApiResponse};
8use crate::https::extractors::{ClientConnInfo, VerifiedClientInformation};
9use axum::extract::{Path, State};
10use axum::http::{HeaderMap, HeaderValue};
11use axum::middleware::from_fn;
12use axum::response::{IntoResponse, Response};
13use axum::routing::{delete, get, post, put};
14use axum::{Extension, Json, Router};
15use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
16use compact_jwt::{Jwk, Jws, JwsSigner};
17use kanidm_proto::constants::uri::V1_AUTH_VALID;
18use kanidm_proto::internal::{
19    ApiToken, AppLink, CUIntentToken, CURequest, CUSessionToken, CUStatus, CreateRequest,
20    CredentialStatus, DeleteRequest, IdentifyUserRequest, IdentifyUserResponse, ModifyRequest,
21    RadiusAuthToken, SearchRequest, SearchResponse, UserAuthToken, COOKIE_AUTH_SESSION_ID,
22    COOKIE_BEARER_TOKEN,
23};
24use kanidm_proto::v1::{
25    AccountUnixExtend, ApiTokenGenerate, AuthIssueSession, AuthRequest, AuthResponse,
26    AuthState as ProtoAuthState, Entry as ProtoEntry, GroupUnixExtend, SingleStringRequest,
27    UatStatus, UnixGroupToken, UnixUserToken, WhoamiResponse,
28};
29use kanidmd_lib::idm::authentication::{AuthState, AuthStep};
30use kanidmd_lib::idm::event::AuthResult;
31use kanidmd_lib::prelude::*;
32use kanidmd_lib::value::PartialValue;
33use std::net::IpAddr;
34use uuid::Uuid;
35
36#[utoipa::path(
37    post,
38    path = "/v1/raw/create",
39    responses(
40        DefaultApiResponse,
41    ),
42    request_body=CreateRequest,
43    security(("token_jwt" = [])),
44    tag = "v1/raw",
45    operation_id="raw_create"
46)]
47pub async fn raw_create(
49    State(state): State<ServerState>,
50    Extension(kopid): Extension<KOpId>,
51    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
52    Json(msg): Json<CreateRequest>,
53) -> Result<Json<()>, WebError> {
54    state
55        .qe_w_ref
56        .handle_create(client_auth_info, msg, kopid.eventid)
57        .await
58        .map(Json::from)
59        .map_err(WebError::from)
60}
61
62#[utoipa::path(
63    post,
64    path = "/v1/raw/modify",
65    responses(
66        DefaultApiResponse,
67    ),
68    request_body=ModifyRequest,
69    security(("token_jwt" = [])),
70    tag = "v1/raw",
71    operation_id="raw_modify"
72)]
73pub async fn raw_modify(
75    State(state): State<ServerState>,
76    Extension(kopid): Extension<KOpId>,
77    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
78    Json(msg): Json<ModifyRequest>,
79) -> Result<Json<()>, WebError> {
80    state
81        .qe_w_ref
82        .handle_modify(client_auth_info, msg, kopid.eventid)
83        .await
84        .map(Json::from)
85        .map_err(WebError::from)
86}
87
88#[utoipa::path(
89    post,
90    path = "/v1/raw/delete",
91    responses(
92        DefaultApiResponse,
93    ),
94    request_body=DeleteRequest,
95    security(("token_jwt" = [])),
96    tag = "v1/raw",
97    operation_id = "raw_delete"
98)]
99pub async fn raw_delete(
101    State(state): State<ServerState>,
102    Extension(kopid): Extension<KOpId>,
103    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
104    Json(msg): Json<DeleteRequest>,
105) -> Result<Json<()>, WebError> {
106    state
107        .qe_w_ref
108        .handle_delete(client_auth_info, msg, kopid.eventid)
109        .await
110        .map(Json::from)
111        .map_err(WebError::from)
112}
113
114#[utoipa::path(
115    post,
116    path = "/v1/raw/search",
117    responses(
118        (status = 200, body=SearchResponse, content_type="application/json"),
119        ApiResponseWithout200,
120    ),
121    request_body=SearchRequest,
122    security(("token_jwt" = [])),
123    tag = "v1/raw",
124    operation_id="raw_search"
125)]
126pub async fn raw_search(
128    State(state): State<ServerState>,
129    Extension(kopid): Extension<KOpId>,
130    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
131    Json(msg): Json<SearchRequest>,
132) -> Result<Json<SearchResponse>, WebError> {
133    state
134        .qe_r_ref
135        .handle_search(client_auth_info, msg, kopid.eventid)
136        .await
137        .map(Json::from)
138        .map_err(WebError::from)
139}
140
141#[utoipa::path(
142    get,
143    path = "/v1/self",
144    responses(
145        (status = 200, body=WhoamiResponse, content_type="application/json"),
146        ApiResponseWithout200,
147    ),
148    security(("token_jwt" = [])),
149    tag = "v1/self",
150    operation_id="whoami"
151)]
152pub async fn whoami(
154    State(state): State<ServerState>,
155    Extension(kopid): Extension<KOpId>,
156    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
157) -> Result<Json<WhoamiResponse>, WebError> {
158    state
160        .qe_r_ref
161        .handle_whoami(client_auth_info, kopid.eventid)
162        .await
163        .map(Json::from)
164        .map_err(WebError::from)
165}
166
167#[utoipa::path(
168    get,
169    path = "/v1/self/_uat",
170    responses(
171        (status = 200, description = "Ok", body=UserAuthToken, content_type="application/json"),
172        ApiResponseWithout200,
173    ),
174    security(("token_jwt" = [])),
175    tag = "v1/self",
176    operation_id="whoami_uat"
177)]
178pub async fn whoami_uat(
179    State(state): State<ServerState>,
180    Extension(kopid): Extension<KOpId>,
181    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
182) -> Result<Json<UserAuthToken>, WebError> {
183    state
184        .qe_r_ref
185        .handle_whoami_uat(&client_auth_info, kopid.eventid)
186        .await
187        .map(Json::from)
188        .map_err(WebError::from)
189}
190
191#[utoipa::path(
192    get,
193    path = "/v1/logout",
194    responses(
195        DefaultApiResponse,
196    ),
197    security(("token_jwt" = [])),
198    tag = "v1/auth",
199    operation_id="logout"
200)]
201pub async fn logout(
202    State(state): State<ServerState>,
203    Extension(kopid): Extension<KOpId>,
204    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
205    jar: CookieJar,
206) -> Result<Response, WebError> {
207    state
208        .qe_w_ref
209        .handle_logout(client_auth_info, kopid.eventid)
210        .await
211        .map(Json::from)
212        .map(|json| (jar, json).into_response())
213        .map_err(WebError::from)
214}
215
216#[instrument(level = "trace", skip(state, kopid))]
219pub async fn json_rest_event_get(
220    state: ServerState,
221    attrs: Option<Vec<String>>,
222    filter: Filter<FilterInvalid>,
223    kopid: KOpId,
224    client_auth_info: ClientAuthInfo,
225) -> Result<Json<Vec<ProtoEntry>>, WebError> {
226    state
227        .qe_r_ref
228        .handle_internalsearch(client_auth_info, filter, attrs, kopid.eventid)
229        .await
230        .map(Json::from)
231        .map_err(WebError::from)
232}
233
234pub async fn json_rest_event_get_id(
237    state: ServerState,
238    id: String,
239    filter: Filter<FilterInvalid>,
240    attrs: Option<Vec<String>>,
241    kopid: KOpId,
242    client_auth_info: ClientAuthInfo,
243) -> Result<Json<Option<ProtoEntry>>, WebError> {
244    let filter = Filter::join_parts_and(filter, filter_all!(f_id(id.as_str())));
245
246    state
247        .qe_r_ref
248        .handle_internalsearch(client_auth_info, filter, attrs, kopid.eventid)
249        .await
250        .map(|mut r| r.pop())
251        .map(Json::from)
252        .map_err(WebError::from)
253}
254
255pub async fn json_rest_event_get_refers_id(
258    state: ServerState,
259    refers_id: String,
260    filter: Filter<FilterInvalid>,
261    attrs: Option<Vec<String>>,
262    kopid: KOpId,
263    client_auth_info: ClientAuthInfo,
264) -> Result<Json<Vec<ProtoEntry>>, WebError> {
265    state
266        .qe_r_ref
267        .handle_search_refers(client_auth_info, filter, refers_id, attrs, kopid.eventid)
268        .await
269        .map(Json::from)
270        .map_err(WebError::from)
271}
272
273pub async fn json_rest_event_delete_id(
274    state: ServerState,
275    id: String,
276    filter: Filter<FilterInvalid>,
277    kopid: KOpId,
278    client_auth_info: ClientAuthInfo,
279) -> Result<Json<()>, WebError> {
280    let filter = Filter::join_parts_and(filter, filter_all!(f_id(id.as_str())));
281    state
282        .qe_w_ref
283        .handle_internaldelete(client_auth_info, filter, kopid.eventid)
284        .await
285        .map(Json::from)
286        .map_err(WebError::from)
287}
288
289pub async fn json_rest_event_get_attr(
290    state: ServerState,
291    id: &str,
292    attr: String,
293    filter: Filter<FilterInvalid>,
294    kopid: KOpId,
295    client_auth_info: ClientAuthInfo,
296) -> Result<Json<Option<Vec<String>>>, WebError> {
297    let filter = Filter::join_parts_and(filter, filter_all!(f_id(id)));
298    let attrs = Some(vec![attr.clone()]);
299    state
300        .qe_r_ref
301        .handle_internalsearch(client_auth_info, filter, attrs, kopid.eventid)
302        .await
303        .map(|mut event_result| event_result.pop().and_then(|mut e| e.attrs.remove(&attr)))
304        .map(Json::from)
305        .map_err(WebError::from)
306}
307
308pub async fn json_rest_event_get_id_attr(
309    state: ServerState,
310    id: String,
311    attr: String,
312    filter: Filter<FilterInvalid>,
313    kopid: KOpId,
314    client_auth_info: ClientAuthInfo,
315) -> Result<Json<Option<Vec<String>>>, WebError> {
316    json_rest_event_get_attr(state, id.as_str(), attr, filter, kopid, client_auth_info).await
317}
318
319pub async fn json_rest_event_post(
320    state: ServerState,
321    classes: Vec<String>,
322    obj: ProtoEntry,
323    kopid: KOpId,
324    client_auth_info: ClientAuthInfo,
325) -> Result<Json<()>, WebError> {
326    debug_assert!(!classes.is_empty());
327
328    let mut obj = obj;
329    obj.attrs.insert(Attribute::Class.to_string(), classes);
330    let msg = CreateRequest {
331        entries: vec![obj.to_owned()],
332    };
333
334    state
335        .qe_w_ref
336        .handle_create(client_auth_info, msg, kopid.eventid)
337        .await
338        .map(Json::from)
339        .map_err(WebError::from)
340}
341
342pub async fn json_rest_event_post_id_attr(
343    state: ServerState,
344    id: String,
345    attr: String,
346    filter: Filter<FilterInvalid>,
347    values: Vec<String>,
348    kopid: KOpId,
349    client_auth_info: ClientAuthInfo,
350) -> Result<Json<()>, WebError> {
351    state
352        .qe_w_ref
353        .handle_appendattribute(client_auth_info, id, attr, values, filter, kopid.eventid)
354        .await
355        .map(Json::from)
356        .map_err(WebError::from)
357}
358
359pub async fn json_rest_event_put_attr(
369    state: ServerState,
370    id: String,
371    attr: String,
372    filter: Filter<FilterInvalid>,
373    values: Vec<String>,
374    kopid: KOpId,
375    client_auth_info: ClientAuthInfo,
376) -> Result<Json<()>, WebError> {
377    state
378        .qe_w_ref
379        .handle_setattribute(client_auth_info, id, attr, values, filter, kopid.eventid)
380        .await
381        .map_err(WebError::from)
382        .map(Json::from)
383}
384
385pub async fn json_rest_event_post_attr(
386    state: ServerState,
387    id: String,
388    attr: String,
389    filter: Filter<FilterInvalid>,
390    values: Vec<String>,
391    kopid: KOpId,
392    client_auth_info: ClientAuthInfo,
393) -> Result<Json<()>, WebError> {
394    state
395        .qe_w_ref
396        .handle_appendattribute(client_auth_info, id, attr, values, filter, kopid.eventid)
397        .await
398        .map(Json::from)
399        .map_err(WebError::from)
400}
401
402pub async fn json_rest_event_delete_id_attr(
403    state: ServerState,
404    id: String,
405    attr: String,
406    filter: Filter<FilterInvalid>,
407    values: Option<Vec<String>>,
408    kopid: KOpId,
409    client_auth_info: ClientAuthInfo,
410) -> Result<Json<()>, WebError> {
411    json_rest_event_delete_attr(state, id, attr, filter, values, kopid, client_auth_info).await
412}
413
414pub async fn json_rest_event_delete_attr(
415    state: ServerState,
416    uuid_or_name: String,
417    attr: String,
418    filter: Filter<FilterInvalid>,
419    values: Option<Vec<String>>,
420    kopid: KOpId,
421    client_auth_info: ClientAuthInfo,
422) -> Result<Json<()>, WebError> {
423    let values = values.unwrap_or_default();
424
425    if values.is_empty() {
426        state
427            .qe_w_ref
428            .handle_purgeattribute(client_auth_info, uuid_or_name, attr, filter, kopid.eventid)
429            .await
430    } else {
431        state
432            .qe_w_ref
433            .handle_removeattributevalues(
434                client_auth_info,
435                uuid_or_name,
436                attr,
437                values,
438                filter,
439                kopid.eventid,
440            )
441            .await
442    }
443    .map(Json::from)
444    .map_err(WebError::from)
445}
446
447#[utoipa::path(
448    get,
449    path = "/v1/schema",
450    responses(
451        (status=200, content_type="application/json", body=Vec<ProtoEntry>),
452        ApiResponseWithout200,
453    ),
454    security(("token_jwt" = [])),
455    tag = "v1/schema",
456    operation_id = "schema_get",
457)]
458pub async fn schema_get(
460    State(state): State<ServerState>,
461    Extension(kopid): Extension<KOpId>,
462    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
463) -> Result<Json<Vec<ProtoEntry>>, WebError> {
464    let filter = filter_all!(f_or!([
469        f_eq(Attribute::Class, EntryClass::AttributeType.into()),
470        f_eq(Attribute::Class, EntryClass::ClassType.into())
471    ]));
472    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
473}
474
475#[utoipa::path(
476    get,
477    path = "/v1/schema/attributetype",
478    responses(
479        (status=200, content_type="application/json", body=Vec<ProtoEntry>),
480        ApiResponseWithout200,
481    ),
482    security(("token_jwt" = [])),
483    tag = "v1/schema",
484    operation_id = "schema_attributetype_get",
485)]
486pub async fn schema_attributetype_get(
487    State(state): State<ServerState>,
488    Extension(kopid): Extension<KOpId>,
489    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
490) -> Result<Json<Vec<ProtoEntry>>, WebError> {
491    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::AttributeType.into()));
492    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
493}
494
495#[utoipa::path(
496    get,
497    path = "/v1/schema/attributetype/{id}",
498    responses(
499        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
500        ApiResponseWithout200,
501    ),
502    security(("token_jwt" = [])),
503    tag = "v1/schema",
504    operation_id = "schema_attributetype_get_id",
505)]
506pub async fn schema_attributetype_get_id(
507    State(state): State<ServerState>,
508    Path(id): Path<String>,
509    Extension(kopid): Extension<KOpId>,
510    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
511) -> Result<Json<Option<ProtoEntry>>, WebError> {
512    let filter = filter_all!(f_and!([
514        f_eq(Attribute::Class, EntryClass::AttributeType.into()),
515        f_eq(
516            Attribute::AttributeName,
517            PartialValue::new_iutf8(id.as_str())
518        )
519    ]));
520
521    state
522        .qe_r_ref
523        .handle_internalsearch(client_auth_info, filter, None, kopid.eventid)
524        .await
525        .map(|mut r| r.pop())
526        .map(Json::from)
527        .map_err(WebError::from)
528}
529
530#[utoipa::path(
531    get,
532    path = "/v1/schema/classtype",
533    responses(
534        (status=200, body=Vec<ProtoEntry>, content_type="application/json"),
535        ApiResponseWithout200,
536    ),
537    security(("token_jwt" = [])),
538    tag = "v1/schema",
539    operation_id="schema_classtype_get",
540)]
541pub async fn schema_classtype_get(
542    State(state): State<ServerState>,
543    Extension(kopid): Extension<KOpId>,
544    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
545) -> Result<Json<Vec<ProtoEntry>>, WebError> {
546    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::ClassType.into()));
547    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
548}
549
550#[utoipa::path(
551    get,
552    path = "/v1/schema/classtype/{id}",
553    responses(
554        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
555        ApiResponseWithout200,
556    ),
557    security(("token_jwt" = [])),
558    tag = "v1/schema",
559    operation_id="schema_classtype_get_id",
560)]
561pub async fn schema_classtype_get_id(
562    State(state): State<ServerState>,
563    Extension(kopid): Extension<KOpId>,
564    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
565    Path(id): Path<String>,
566) -> Result<Json<Option<ProtoEntry>>, WebError> {
567    let filter = filter_all!(f_and!([
569        f_eq(Attribute::Class, EntryClass::ClassType.into()),
570        f_eq(Attribute::ClassName, PartialValue::new_iutf8(id.as_str()))
571    ]));
572    state
573        .qe_r_ref
574        .handle_internalsearch(client_auth_info, filter, None, kopid.eventid)
575        .await
576        .map(|mut r| r.pop())
577        .map(Json::from)
578        .map_err(WebError::from)
579}
580
581#[utoipa::path(
582    get,
583    path = "/v1/person",
584    responses(
585        (status=200, body=Vec<ProtoEntry>, content_type="application/json"),
586        ApiResponseWithout200,
587    ),
588    security(("token_jwt" = [])),
589    tag = "v1/person",
590    operation_id = "person_get",
591)]
592pub async fn person_get(
593    State(state): State<ServerState>,
594    Extension(kopid): Extension<KOpId>,
595    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
596) -> Result<Json<Vec<ProtoEntry>>, WebError> {
597    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Person.into()));
598    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
599}
600
601#[utoipa::path(
602    post,
603    path = "/v1/person",
604    responses(
605        DefaultApiResponse,
606    ),
607    request_body=ProtoEntry,
608    security(("token_jwt" = [])),
609    tag = "v1/person",
610    operation_id = "person_post",
611)]
612pub async fn person_post(
614    State(state): State<ServerState>,
615    Extension(kopid): Extension<KOpId>,
616    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
617    Json(obj): Json<ProtoEntry>,
618) -> Result<Json<()>, WebError> {
619    let classes: Vec<String> = vec![
620        EntryClass::Person.into(),
621        EntryClass::Account.into(),
622        EntryClass::Object.into(),
623    ];
624    json_rest_event_post(state, classes, obj, kopid, client_auth_info).await
625}
626
627#[utoipa::path(
628    get,
629    path = "/v1/person/_search/{id}",
630    responses(
631        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
632        ApiResponseWithout200,
633    ),
634    security(("token_jwt" = [])),
635    tag = "v1/person",
636    operation_id = "person_search_id",
637)]
638pub async fn person_search_id(
639    State(state): State<ServerState>,
640    Path(id): Path<String>,
641    Extension(kopid): Extension<KOpId>,
642    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
643) -> Result<Json<Vec<ProtoEntry>>, WebError> {
644    let filter = filter_all!(f_and!([
645        f_eq(Attribute::Class, EntryClass::Person.into()),
646        f_sub(Attribute::Name, PartialValue::new_iname(&id))
647    ]));
648    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
649}
650
651#[utoipa::path(
652    get,
653    path = "/v1/person/{id}",
654    responses(
655        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
656        ApiResponseWithout200,
657    ),
658    security(("token_jwt" = [])),
659    tag = "v1/person",
660    operation_id = "person_id_get",
661)]
662pub async fn person_id_get(
663    State(state): State<ServerState>,
664    Path(id): Path<String>,
665    Extension(kopid): Extension<KOpId>,
666    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
667) -> Result<Json<Option<ProtoEntry>>, WebError> {
668    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Person.into()));
669    json_rest_event_get_id(state, id, filter, None, kopid, client_auth_info).await
670}
671
672#[utoipa::path(
673    delete,
674    path = "/v1/person/{id}",
675    responses(
676        DefaultApiResponse,
677    ),
678    security(("token_jwt" = [])),
679    tag = "v1/person",
680    operation_id = "person_id_delete",
681)]
682pub async fn person_id_delete(
683    State(state): State<ServerState>,
684    Path(id): Path<String>,
685    Extension(kopid): Extension<KOpId>,
686    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
687) -> Result<Json<()>, WebError> {
688    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Person.into()));
689    json_rest_event_delete_id(state, id, filter, kopid, client_auth_info).await
690}
691
692#[utoipa::path(
695    get,
696    path = "/v1/person/{id}/_certificate",
697    responses(
698        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
699        ApiResponseWithout200,
700    ),
701    security(("token_jwt" = [])),
702    tag = "v1/person/certificate",
703    operation_id = "person_get_id_certificate",
704)]
705pub async fn person_get_id_certificate(
706    State(state): State<ServerState>,
707    Path(id): Path<String>,
708    Extension(kopid): Extension<KOpId>,
709    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
710) -> Result<Json<Vec<ProtoEntry>>, WebError> {
711    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::ClientCertificate.into()));
712    json_rest_event_get_refers_id(state, id, filter, None, kopid, client_auth_info).await
713}
714
715#[utoipa::path(
716    post,
717    path = "/v1/person/{id}/_certificate",
718    responses(
719        DefaultApiResponse,
720    ),
721    request_body=ProtoEntry,
722    security(("token_jwt" = [])),
723    tag = "v1/person/certificate",
724    operation_id = "person_post_id_certificate",
725)]
726pub async fn person_post_id_certificate(
730    State(state): State<ServerState>,
731    Path(id): Path<String>,
732    Extension(kopid): Extension<KOpId>,
733    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
734    Json(mut obj): Json<ProtoEntry>,
735) -> Result<Json<()>, WebError> {
736    let classes: Vec<String> = vec![
737        EntryClass::ClientCertificate.into(),
738        EntryClass::Object.into(),
739    ];
740    obj.attrs.insert(Attribute::Refers.to_string(), vec![id]);
741
742    json_rest_event_post(state, classes, obj, kopid, client_auth_info).await
743}
744
745#[utoipa::path(
748    get,
749    path = "/v1/service_account",
750    responses(
751        (status=200, body=Vec<ProtoEntry>, content_type="application/json"),
752        ApiResponseWithout200,
753    ),
754    security(("token_jwt" = [])),
755    tag = "v1/service_account",
756    operation_id = "service_account_get",
757)]
758pub async fn service_account_get(
759    State(state): State<ServerState>,
760    Extension(kopid): Extension<KOpId>,
761    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
762) -> Result<Json<Vec<ProtoEntry>>, WebError> {
763    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::ServiceAccount.into()));
764    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
765}
766
767#[utoipa::path(
768    post,
769    path = "/v1/service_account",
770    request_body=ProtoEntry,
771    responses(
772        DefaultApiResponse,
773    ),
774    security(("token_jwt" = [])),
775    tag = "v1/service_account",
776    operation_id = "service_account_post",
777)]
778pub async fn service_account_post(
779    State(state): State<ServerState>,
780    Extension(kopid): Extension<KOpId>,
781    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
782    Json(obj): Json<ProtoEntry>,
783) -> Result<Json<()>, WebError> {
784    let classes: Vec<String> = vec![
785        EntryClass::ServiceAccount.into(),
786        EntryClass::Account.into(),
787        EntryClass::Object.into(),
788    ];
789    json_rest_event_post(state, classes, obj, kopid, client_auth_info).await
790}
791
792#[utoipa::path(
793    patch,
794    path = "/v1/service_account/{id}",
795    responses(
796        DefaultApiResponse,
797    ),
798    request_body=ProtoEntry,
799    security(("token_jwt" = [])),
800    tag = "v1/service_account",
801    operation_id = "service_account_id_patch",
802)]
803pub async fn service_account_id_patch(
804    State(state): State<ServerState>,
805    Extension(kopid): Extension<KOpId>,
806    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
807    Path(id): Path<String>,
808    Json(obj): Json<ProtoEntry>,
809) -> Result<Json<()>, WebError> {
810    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
812    let filter = Filter::join_parts_and(filter, filter_all!(f_id(id.as_str())));
813    state
814        .qe_w_ref
815        .handle_internalpatch(client_auth_info, filter, obj, kopid.eventid)
816        .await
817        .map(Json::from)
818        .map_err(WebError::from)
819}
820
821#[utoipa::path(
822    get,
823    path = "/v1/service_account/{id}",
824    responses(
825        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
826        ApiResponseWithout200,
827    ),
828    security(("token_jwt" = [])),
829    tag = "v1/service_account",
830    operation_id = "service_account_id_get",
831)]
832pub async fn service_account_id_get(
833    State(state): State<ServerState>,
834    Path(id): Path<String>,
835    Extension(kopid): Extension<KOpId>,
836    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
837) -> Result<Json<Option<ProtoEntry>>, WebError> {
838    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::ServiceAccount.into()));
839    json_rest_event_get_id(state, id, filter, None, kopid, client_auth_info).await
840}
841
842#[utoipa::path(
843    delete,
844    path = "/v1/service_account/{id}",
845    responses(
846        DefaultApiResponse,
847    ),
848    security(("token_jwt" = [])),
849    tag = "v1/service_account",
850)]
851pub async fn service_account_id_delete(
852    State(state): State<ServerState>,
853    Path(id): Path<String>,
854    Extension(kopid): Extension<KOpId>,
855    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
856) -> Result<Json<()>, WebError> {
857    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::ServiceAccount.into()));
858    json_rest_event_delete_id(state, id, filter, kopid, client_auth_info).await
859}
860
861#[utoipa::path(
862    get,
863    path = "/v1/service_account/{id}/_credential/_generate",
864    responses(
865        (status=200), ApiResponseWithout200,
867    ),
868    security(("token_jwt" = [])),
869    tag = "v1/service_account",
870)]
871pub async fn service_account_credential_generate(
872    State(state): State<ServerState>,
873    Path(id): Path<String>,
874    Extension(kopid): Extension<KOpId>,
875    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
876) -> Result<Json<String>, WebError> {
877    state
878        .qe_w_ref
879        .handle_service_account_credential_generate(client_auth_info, id, kopid.eventid)
880        .await
881        .map(Json::from)
882        .map_err(WebError::from)
883}
884
885#[utoipa::path(
886    post,
887    path = "/v1/service_account/{id}/_into_person",
888    responses(
889        DefaultApiResponse,
890    ),
891    security(("token_jwt" = [])),
892    tag = "v1/service_account",
893)]
894#[deprecated]
900pub async fn service_account_into_person(
901    State(state): State<ServerState>,
902    Extension(kopid): Extension<KOpId>,
903    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
904    Path(id): Path<String>,
905) -> Result<Json<()>, WebError> {
906    state
907        .qe_w_ref
908        .handle_service_account_into_person(client_auth_info, id, kopid.eventid)
909        .await
910        .map(Json::from)
911        .map_err(WebError::from)
912}
913
914#[utoipa::path(
915    get,
916    path = "/v1/service_account/{id}/_api_token",
917    responses(
918        (status=200, body=Vec<ApiToken>, content_type="application/json"),
919        ApiResponseWithout200,
920    ),
921    security(("token_jwt" = [])),
922    tag = "v1/service_account",
923    operation_id = "service_account_api_token_get",
924)]
925pub async fn service_account_api_token_get(
926    State(state): State<ServerState>,
927    Extension(kopid): Extension<KOpId>,
928    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
929    Path(id): Path<String>,
930) -> Result<Json<Vec<ApiToken>>, WebError> {
931    state
932        .qe_r_ref
933        .handle_service_account_api_token_get(client_auth_info, id, kopid.eventid)
934        .await
935        .map(Json::from)
936        .map_err(WebError::from)
937}
938
939#[utoipa::path(
940    post,
941    path = "/v1/service_account/{id}/_api_token",
942    request_body = ApiTokenGenerate,
943    responses(
944        (status=200, body=String, content_type="application/json"),
945        ApiResponseWithout200,
946    ),
947    security(("token_jwt" = [])),
948    tag = "v1/service_account",
949    operation_id = "service_account_api_token_post",
950)]
951pub async fn service_account_api_token_post(
952    State(state): State<ServerState>,
953    Extension(kopid): Extension<KOpId>,
954    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
955    Path(id): Path<String>,
956    Json(obj): Json<ApiTokenGenerate>,
957) -> Result<Json<String>, WebError> {
958    state
959        .qe_w_ref
960        .handle_service_account_api_token_generate(
961            client_auth_info,
962            id,
963            obj.label,
964            obj.expiry,
965            obj.read_write,
966            kopid.eventid,
967        )
968        .await
969        .map(Json::from)
970        .map_err(WebError::from)
971}
972
973#[utoipa::path(
974    delete,
975    path = "/v1/service_account/{id}/_api_token/{token_id}",
976    responses(
977        DefaultApiResponse,
978    ),
979    security(("token_jwt" = [])),
980    tag = "v1/service_account",
981    operation_id = "service_account_api_token_delete",
982)]
983pub async fn service_account_api_token_delete(
984    State(state): State<ServerState>,
985    Path((id, token_id)): Path<(String, Uuid)>,
986    Extension(kopid): Extension<KOpId>,
987    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
988) -> Result<Json<()>, WebError> {
989    state
990        .qe_w_ref
991        .handle_service_account_api_token_destroy(client_auth_info, id, token_id, kopid.eventid)
992        .await
993        .map(Json::from)
994        .map_err(WebError::from)
995}
996
997#[utoipa::path(
998    get,
999    path = "/v1/person/{id}/_attr/{attr}",
1000    responses(
1001        (status=200, body=Option<Vec<String>>, content_type="application/json"),
1002        ApiResponseWithout200,
1003    ),
1004    security(("token_jwt" = [])),
1005    tag = "v1/person/attr",
1006    operation_id = "person_id_get_attr",
1007)]
1008pub async fn person_id_get_attr(
1009    State(state): State<ServerState>,
1010    Path((id, attr)): Path<(String, String)>,
1011    Extension(kopid): Extension<KOpId>,
1012    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1013) -> Result<Json<Option<Vec<String>>>, WebError> {
1014    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1015    json_rest_event_get_attr(state, id.as_str(), attr, filter, kopid, client_auth_info).await
1016}
1017
1018#[utoipa::path(
1019    get,
1020    path = "/v1/service_account/{id}/_attr/{attr}",
1021    responses(
1022        (status=200, body=Option<Vec<String>>, content_type="application/json"),
1023        ApiResponseWithout200,
1024    ),
1025    security(("token_jwt" = [])),
1026    tag = "v1/service_account",
1027    operation_id = "service_account_id_get_attr",
1028)]
1029pub async fn service_account_id_get_attr(
1030    State(state): State<ServerState>,
1031    Path((id, attr)): Path<(String, String)>,
1032    Extension(kopid): Extension<KOpId>,
1033    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1034) -> Result<Json<Option<Vec<String>>>, WebError> {
1035    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1036    json_rest_event_get_attr(state, id.as_str(), attr, filter, kopid, client_auth_info).await
1037}
1038
1039#[utoipa::path(
1040    post,
1041    path = "/v1/person/{id}/_attr/{attr}",
1042    request_body= Vec<String>,
1043    responses(
1044        DefaultApiResponse,
1045    ),
1046    security(("token_jwt" = [])),
1047    tag = "v1/person/attr",
1048    operation_id = "person_id_post_attr",
1049)]
1050pub async fn person_id_post_attr(
1051    State(state): State<ServerState>,
1052    Path((id, attr)): Path<(String, String)>,
1053    Extension(kopid): Extension<KOpId>,
1054    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1055    Json(values): Json<Vec<String>>,
1056) -> Result<Json<()>, WebError> {
1057    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1058    json_rest_event_post_id_attr(state, id, attr, filter, values, kopid, client_auth_info).await
1059}
1060
1061#[utoipa::path(
1062    post,
1063    path = "/v1/service_account/{id}/_attr/{attr}",
1064    request_body=Vec<String>,
1065    responses(
1066        DefaultApiResponse,
1067    ),
1068    security(("token_jwt" = [])),
1069    tag = "v1/service_account",
1070    operation_id = "service_account_id_post_attr",
1071)]
1072pub async fn service_account_id_post_attr(
1073    State(state): State<ServerState>,
1074    Path((id, attr)): Path<(String, String)>,
1075    Extension(kopid): Extension<KOpId>,
1076    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1077    Json(values): Json<Vec<String>>,
1078) -> Result<Json<()>, WebError> {
1079    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1080    json_rest_event_post_id_attr(state, id, attr, filter, values, kopid, client_auth_info).await
1081}
1082
1083#[utoipa::path(
1084    delete,
1085    path = "/v1/person/{id}/_attr/{attr}",
1086    responses(
1087        DefaultApiResponse,
1088    ),
1089    security(("token_jwt" = [])),
1090    tag = "v1/person/attr",
1091    operation_id = "person_id_delete_attr",
1092)]
1093pub async fn person_id_delete_attr(
1094    State(state): State<ServerState>,
1095    Path((id, attr)): Path<(String, String)>,
1096    Extension(kopid): Extension<KOpId>,
1097    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1098) -> Result<Json<()>, WebError> {
1099    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1100    json_rest_event_delete_id_attr(state, id, attr, filter, None, kopid, client_auth_info).await
1101}
1102
1103#[utoipa::path(
1104    delete,
1105    path = "/v1/service_account/{id}/_attr/{attr}",
1106    responses(
1107        DefaultApiResponse,
1108    ),
1109    security(("token_jwt" = [])),
1110    tag = "v1/service_account",
1111    operation_id = "service_account_id_delete_attr",
1112)]
1113pub async fn service_account_id_delete_attr(
1114    State(state): State<ServerState>,
1115    Path((id, attr)): Path<(String, String)>,
1116    Extension(kopid): Extension<KOpId>,
1117    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1118) -> Result<Json<()>, WebError> {
1119    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1120    json_rest_event_delete_id_attr(state, id, attr, filter, None, kopid, client_auth_info).await
1121}
1122
1123#[utoipa::path(
1124    put,
1125    path = "/v1/person/{id}/_attr/{attr}",
1126    responses(
1127        DefaultApiResponse,
1128    ),
1129    security(("token_jwt" = [])),
1130    tag = "v1/person/attr",
1131    operation_id = "person_id_put_attr",
1132)]
1133pub async fn person_id_put_attr(
1134    State(state): State<ServerState>,
1135    Path((id, attr)): Path<(String, String)>,
1136    Extension(kopid): Extension<KOpId>,
1137    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1138    Json(values): Json<Vec<String>>,
1139) -> Result<Json<()>, WebError> {
1140    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1141    json_rest_event_put_attr(state, id, attr, filter, values, kopid, client_auth_info).await
1142}
1143
1144#[utoipa::path(
1145    put,
1146    path = "/v1/service_account/{id}/_attr/{attr}",
1147    request_body=Vec<String>,
1148    responses(
1149        DefaultApiResponse,
1150    ),
1151    security(("token_jwt" = [])),
1152    tag = "v1/service_account",
1153    operation_id = "service_account_id_put_attr",
1154)]
1155pub async fn service_account_id_put_attr(
1156    State(state): State<ServerState>,
1157    Path((id, attr)): Path<(String, String)>,
1158    Extension(kopid): Extension<KOpId>,
1159    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1160    Json(values): Json<Vec<String>>,
1161) -> Result<Json<()>, WebError> {
1162    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1163    json_rest_event_put_attr(state, id, attr, filter, values, kopid, client_auth_info).await
1164}
1165
1166#[utoipa::path(
1167    patch,
1168    path = "/v1/person/{id}",
1169    responses(
1170        DefaultApiResponse,
1171    ),
1172    request_body=ProtoEntry,
1173    security(("token_jwt" = [])),
1174    tag = "v1/person",
1175    operation_id = "person_id_patch",
1176)]
1177pub async fn person_id_patch(
1178    State(state): State<ServerState>,
1179    Extension(kopid): Extension<KOpId>,
1180    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1181    Path(id): Path<String>,
1182    Json(obj): Json<ProtoEntry>,
1183) -> Result<Json<()>, WebError> {
1184    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1186    let filter = Filter::join_parts_and(filter, filter_all!(f_id(id.as_str())));
1187    state
1188        .qe_w_ref
1189        .handle_internalpatch(client_auth_info, filter, obj, kopid.eventid)
1190        .await
1191        .map(Json::from)
1192        .map_err(WebError::from)
1193}
1194
1195#[utoipa::path(
1196    get,
1197    path = "/v1/person/{id}/_credential/_update",
1198    responses(
1199        (status=200), ApiResponseWithout200,
1201    ),
1202    security(("token_jwt" = [])),
1203    tag = "v1/person/credential",
1204)]
1205pub async fn person_id_credential_update_get(
1206    State(state): State<ServerState>,
1207    Extension(kopid): Extension<KOpId>,
1208    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1209    Path(id): Path<String>,
1210) -> Result<Json<(CUSessionToken, CUStatus)>, WebError> {
1211    state
1212        .qe_w_ref
1213        .handle_idmcredentialupdate(client_auth_info, id, kopid.eventid)
1214        .await
1215        .map(Json::from)
1216        .map_err(WebError::from)
1217}
1218
1219#[utoipa::path(
1220    get,
1221    path = "/v1/person/{id}/_credential/_update_intent/{ttl}",
1222    params(
1223        ("ttl" = u64, description="The new TTL for the credential?")
1224    ),
1225    responses(
1226        (status=200), ApiResponseWithout200,
1228    ),
1229    security(("token_jwt" = [])),
1230    tag = "v1/person/credential",
1231)]
1232#[instrument(level = "trace", skip(state, kopid))]
1234pub async fn person_id_credential_update_intent_ttl_get(
1235    State(state): State<ServerState>,
1236    Extension(kopid): Extension<KOpId>,
1237    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1238    Path((id, ttl)): Path<(String, u64)>,
1239) -> Result<Json<CUIntentToken>, WebError> {
1240    state
1241        .qe_w_ref
1242        .handle_idmcredentialupdateintent(
1243            client_auth_info,
1244            id,
1245            Some(Duration::from_secs(ttl)),
1246            kopid.eventid,
1247        )
1248        .await
1249        .map(Json::from)
1250        .map_err(WebError::from)
1251}
1252
1253#[utoipa::path(
1254    get,
1255    path = "/v1/person/{id}/_credential/_update_intent",
1256    responses(
1257        (status=200), ApiResponseWithout200,
1259    ),
1260    security(("token_jwt" = [])),
1261    tag = "v1/person/credential",
1262)]
1263#[instrument(level = "trace", skip(state, kopid))]
1264pub async fn person_id_credential_update_intent_get(
1265    State(state): State<ServerState>,
1266    Extension(kopid): Extension<KOpId>,
1267    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1268    Path(id): Path<String>,
1269) -> Result<Json<CUIntentToken>, WebError> {
1270    state
1271        .qe_w_ref
1272        .handle_idmcredentialupdateintent(client_auth_info, id, None, kopid.eventid)
1273        .await
1274        .map(Json::from)
1275        .map_err(WebError::from)
1276}
1277
1278#[utoipa::path(
1279    get,
1280    path = "/v1/account/{id}/_user_auth_token",
1281    responses(
1282        (status=200), ApiResponseWithout200,
1284    ),
1285    security(("token_jwt" = [])),
1286    tag = "v1/account",
1287)]
1288pub async fn account_id_user_auth_token_get(
1289    State(state): State<ServerState>,
1290    Path(id): Path<String>,
1291    Extension(kopid): Extension<KOpId>,
1292    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1293) -> Result<Json<Vec<UatStatus>>, WebError> {
1294    state
1295        .qe_r_ref
1296        .handle_account_user_auth_token_get(client_auth_info, id, kopid.eventid)
1297        .await
1298        .map(Json::from)
1299        .map_err(WebError::from)
1300}
1301
1302#[utoipa::path(
1303    get,
1304    path = "/v1/account/{id}/_user_auth_token/{token_id}",
1305    responses(
1306        DefaultApiResponse,
1307    ),
1308    security(("token_jwt" = [])),
1309    tag = "v1/account",
1310)]
1311pub async fn account_user_auth_token_delete(
1312    State(state): State<ServerState>,
1313    Path((id, token_id)): Path<(String, Uuid)>,
1314    Extension(kopid): Extension<KOpId>,
1315    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1316) -> Result<Json<()>, WebError> {
1317    state
1318        .qe_w_ref
1319        .handle_account_user_auth_token_destroy(client_auth_info, id, token_id, kopid.eventid)
1320        .await
1321        .map(Json::from)
1322        .map_err(WebError::from)
1323}
1324
1325#[utoipa::path(
1326    post,
1327    path = "/v1/credential/_exchange_intent",
1328    params(
1329    ),
1330    responses(
1331        (status=200), ApiResponseWithout200,
1333    ),
1334    security(("token_jwt" = [])),
1335    tag = "v1/credential",
1336)] pub async fn credential_update_exchange_intent(
1338    State(state): State<ServerState>,
1339    Extension(kopid): Extension<KOpId>,
1340    Json(intent_token): Json<String>,
1341) -> Result<Json<(CUSessionToken, CUStatus)>, WebError> {
1342    state
1343        .qe_w_ref
1344        .handle_idmcredentialexchangeintent(intent_token, kopid.eventid)
1345        .await
1346        .map(Json::from)
1347        .map_err(WebError::from)
1348}
1349
1350#[utoipa::path(
1351    post,
1352    path = "/v1/credential/_status",
1353    responses(
1354        (status=200), ApiResponseWithout200,
1356    ),
1357    security(("token_jwt" = [])),
1358    tag = "v1/credential",
1359)] pub async fn credential_update_status(
1361    State(state): State<ServerState>,
1362    Extension(kopid): Extension<KOpId>,
1363    Json(session_token): Json<CUSessionToken>,
1364) -> Result<Json<CUStatus>, WebError> {
1365    state
1366        .qe_r_ref
1367        .handle_idmcredentialupdatestatus(session_token, kopid.eventid)
1368        .await
1369        .map(Json::from)
1370        .map_err(WebError::from)
1371}
1372
1373#[utoipa::path(
1374    post,
1375    path = "/v1/credential/_update",
1376    responses(
1377        (status=200, body=CUStatus), ApiResponseWithout200,
1379    ),
1380    security(("token_jwt" = [])),
1381    tag = "v1/credential",
1382)] #[instrument(level = "debug", skip(state, kopid))]
1384pub async fn credential_update_update(
1385    State(state): State<ServerState>,
1386    Extension(kopid): Extension<KOpId>,
1387    Json(cubody): Json<Vec<serde_json::Value>>,
1388) -> Result<Json<CUStatus>, WebError> {
1389    let scr: CURequest = match serde_json::from_value(cubody[0].clone()) {
1390        Ok(val) => val,
1391        Err(err) => {
1392            let errmsg = format!("Failed to deserialize CURequest: {err:?}");
1393            error!("{}", errmsg);
1394            return Err(WebError::InternalServerError(errmsg));
1395        }
1396    };
1397
1398    let session_token = match serde_json::from_value(cubody[1].clone()) {
1399        Ok(val) => val,
1400        Err(err) => {
1401            let errmsg = format!("Failed to deserialize session token: {err:?}");
1402            error!("{}", errmsg);
1403            return Err(WebError::InternalServerError(errmsg));
1404        }
1405    };
1406    trace!("session_token: {:?}", session_token);
1407    debug!("scr: {:?}", scr);
1408
1409    state
1410        .qe_r_ref
1411        .handle_idmcredentialupdate(session_token, scr, kopid.eventid)
1412        .await
1413        .map(Json::from)
1414        .map_err(WebError::from)
1415}
1416
1417#[utoipa::path(
1418    post,
1419    path = "/v1/credential/_commit",
1420    responses(
1421        DefaultApiResponse,
1422    ),
1423    security(("token_jwt" = [])),
1424    tag = "v1/credential",
1425)] pub async fn credential_update_commit(
1427    State(state): State<ServerState>,
1428    Extension(kopid): Extension<KOpId>,
1429    Json(session_token): Json<CUSessionToken>,
1430) -> Result<Json<()>, WebError> {
1431    state
1432        .qe_w_ref
1433        .handle_idmcredentialupdatecommit(session_token, kopid.eventid)
1434        .await
1435        .map(Json::from)
1436        .map_err(WebError::from)
1437}
1438
1439#[utoipa::path(
1440    post,
1441    path = "/v1/credential/_cancel",
1442    request_body=CUSessionToken,
1443    responses(
1444        DefaultApiResponse,
1445    ),
1446    security(("token_jwt" = [])),
1447    tag = "v1/credential",
1448)]
1449pub async fn credential_update_cancel(
1450    State(state): State<ServerState>,
1451    Extension(kopid): Extension<KOpId>,
1452    Json(session_token): Json<CUSessionToken>,
1453) -> Result<Json<()>, WebError> {
1454    state
1455        .qe_w_ref
1456        .handle_idmcredentialupdatecancel(session_token, kopid.eventid)
1457        .await
1458        .map(Json::from)
1459        .map_err(WebError::from)
1460}
1461
1462#[utoipa::path(
1463    get,
1464    path = "/v1/service_account/{id}/_credential/_status",
1465    responses(
1466        (status=200), ApiResponseWithout200,
1468    ),
1469    security(("token_jwt" = [])),
1470    tag = "v1/service_account",
1471)]
1472pub async fn service_account_id_credential_status_get(
1473    State(state): State<ServerState>,
1474    Extension(kopid): Extension<KOpId>,
1475    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1476    Path(id): Path<String>,
1477) -> Result<Json<CredentialStatus>, WebError> {
1478    match state
1479        .qe_r_ref
1480        .handle_idmcredentialstatus(client_auth_info, id.clone(), kopid.eventid)
1481        .await
1482        .map(Json::from)
1483    {
1484        Ok(val) => Ok(val),
1485        Err(err) => {
1486            if let OperationError::NoMatchingAttributes = err {
1487                debug!("No credentials set on account {}, returning empty list", id);
1488                Ok(Json(CredentialStatus { creds: Vec::new() }))
1489            } else {
1490                Err(WebError::from(err))
1491            }
1492        }
1493    }
1494}
1495
1496#[utoipa::path(
1497    get,
1498    path = "/v1/person/{id}/_credential/_status",
1499    responses(
1500        (status=200), ApiResponseWithout200,
1502    ),
1503    security(("token_jwt" = [])),
1504    tag = "v1/person/credential",
1505)]
1506pub async fn person_get_id_credential_status(
1507    State(state): State<ServerState>,
1508    Extension(kopid): Extension<KOpId>,
1509    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1510    Path(id): Path<String>,
1511) -> Result<Json<CredentialStatus>, WebError> {
1512    match state
1513        .qe_r_ref
1514        .handle_idmcredentialstatus(client_auth_info, id.clone(), kopid.eventid)
1515        .await
1516        .map(Json::from)
1517    {
1518        Ok(val) => Ok(val),
1519        Err(err) => {
1520            if let OperationError::NoMatchingAttributes = err {
1521                debug!("No credentials set on person {}, returning empty list", id);
1522                Ok(Json(CredentialStatus { creds: Vec::new() }))
1523            } else {
1524                Err(WebError::from(err))
1525            }
1526        }
1527    }
1528}
1529
1530#[utoipa::path(
1531    get,
1532    path = "/v1/person/{id}/_ssh_pubkeys",
1533    responses(
1534        (status=200, body=Vec<String>, content_type="application/json"),
1535        ApiResponseWithout200,
1536    ),
1537    security(("token_jwt" = [])),
1538    tag = "v1/person/ssh_pubkeys",
1539    operation_id = "person_id_ssh_pubkeys_get",
1540)]
1541pub async fn person_id_ssh_pubkeys_get(
1542    State(state): State<ServerState>,
1543    Extension(kopid): Extension<KOpId>,
1544    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1545    Path(id): Path<String>,
1546) -> Result<Json<Vec<String>>, WebError> {
1547    state
1548        .qe_r_ref
1549        .handle_internalsshkeyread(client_auth_info, id, kopid.eventid)
1550        .await
1551        .map(Json::from)
1552        .map_err(WebError::from)
1553}
1554
1555#[utoipa::path(
1556    get,
1557    path = "/v1/account/{id}/_ssh_pubkeys",
1558    responses(
1559        (status=200, body=Vec<String>, content_type="application/json"),
1560        ApiResponseWithout200,
1561    ),
1562    security(("token_jwt" = [])),
1563    tag = "v1/account",
1564    operation_id = "account_id_ssh_pubkeys_get",
1565)]
1566#[deprecated]
1567pub async fn account_id_ssh_pubkeys_get(
1568    State(state): State<ServerState>,
1569    Extension(kopid): Extension<KOpId>,
1570    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1571    Path(id): Path<String>,
1572) -> Result<Json<Vec<String>>, WebError> {
1573    state
1574        .qe_r_ref
1575        .handle_internalsshkeyread(client_auth_info, id, kopid.eventid)
1576        .await
1577        .map(Json::from)
1578        .map_err(WebError::from)
1579}
1580
1581#[utoipa::path(
1582    get,
1583    path = "/v1/service_account/{id}/_ssh_pubkeys",
1584    responses(
1585        (status=200, body=Vec<String>, content_type="application/json"),
1586        ApiResponseWithout200,
1587    ),
1588    security(("token_jwt" = [])),
1589    tag = "v1/service_account",
1590    operation_id = "service_account_id_ssh_pubkeys_get",
1591)]
1592pub async fn service_account_id_ssh_pubkeys_get(
1593    State(state): State<ServerState>,
1594    Extension(kopid): Extension<KOpId>,
1595    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1596    Path(id): Path<String>,
1597) -> Result<Json<Vec<String>>, WebError> {
1598    state
1599        .qe_r_ref
1600        .handle_internalsshkeyread(client_auth_info, id, kopid.eventid)
1601        .await
1602        .map(Json::from)
1603        .map_err(WebError::from)
1604}
1605
1606#[utoipa::path(
1607    post,
1608    path = "/v1/person/{id}/_ssh_pubkeys",
1609    responses(
1610        DefaultApiResponse,
1611        (status=422, description="Unprocessable Entity", body=String, content_type="text/plain"),
1612    ),
1613    security(("token_jwt" = [])),
1614    tag = "v1/person/ssh_pubkeys",
1615    operation_id = "person_id_ssh_pubkeys_post",
1616)]
1617pub async fn person_id_ssh_pubkeys_post(
1618    State(state): State<ServerState>,
1619    Extension(kopid): Extension<KOpId>,
1620    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1621    Path(id): Path<String>,
1622    Json((tag, key)): Json<(String, String)>,
1623) -> Result<Json<()>, WebError> {
1624    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1625    state
1627        .qe_w_ref
1628        .handle_sshkeycreate(client_auth_info, id, &tag, &key, filter, kopid.eventid)
1629        .await
1630        .map(Json::from)
1631        .map_err(WebError::from)
1632}
1633
1634#[utoipa::path(
1635    post,
1636    path = "/v1/service_account/{id}/_ssh_pubkeys",
1637    request_body = (String, String),
1638    responses(
1639        DefaultApiResponse,
1640        (status=422, description="Unprocessable Entity", body=String, content_type="text/plain"),
1641    ),
1642    security(("token_jwt" = [])),
1643    tag = "v1/service_account",
1644    operation_id = "service_account_id_ssh_pubkeys_post",
1645)]
1646pub async fn service_account_id_ssh_pubkeys_post(
1647    State(state): State<ServerState>,
1648    Extension(kopid): Extension<KOpId>,
1649    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1650    Path(id): Path<String>,
1651    Json((tag, key)): Json<(String, String)>,
1652) -> Result<Json<()>, WebError> {
1653    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1654    state
1656        .qe_w_ref
1657        .handle_sshkeycreate(client_auth_info, id, &tag, &key, filter, kopid.eventid)
1658        .await
1659        .map(Json::from)
1660        .map_err(WebError::from)
1661}
1662
1663#[utoipa::path(
1664    get,
1665    path = "/v1/person/{id}/_ssh_pubkeys/{tag}",
1666    responses(
1667        (status=200, body=String, content_type="application/json"),
1668        ApiResponseWithout200,
1669    ),
1670    security(("token_jwt" = [])),
1671    tag = "v1/person/ssh_pubkeys",
1672    operation_id = "person_id_ssh_pubkeys_tag_get",
1673)]
1674pub async fn person_id_ssh_pubkeys_tag_get(
1675    State(state): State<ServerState>,
1676    Extension(kopid): Extension<KOpId>,
1677    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1678    Path((id, tag)): Path<(String, String)>,
1679) -> Result<Json<Option<String>>, WebError> {
1680    state
1681        .qe_r_ref
1682        .handle_internalsshkeytagread(client_auth_info, id, tag, kopid.eventid)
1683        .await
1684        .map(Json::from)
1685        .map_err(WebError::from)
1686}
1687#[utoipa::path(
1688    get,
1689    path = "/v1/account/{id}/_ssh_pubkeys/{tag}",
1690    responses(
1691        (status=200, body=String, content_type="application/json"),
1692        ApiResponseWithout200,
1693    ),
1694    security(("token_jwt" = [])),
1695    tag = "v1/account",
1696    operation_id = "account_id_ssh_pubkeys_tag_get",
1697)]
1698pub async fn account_id_ssh_pubkeys_tag_get(
1699    State(state): State<ServerState>,
1700    Extension(kopid): Extension<KOpId>,
1701    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1702    Path((id, tag)): Path<(String, String)>,
1703) -> Result<Json<Option<String>>, WebError> {
1704    state
1705        .qe_r_ref
1706        .handle_internalsshkeytagread(client_auth_info, id, tag, kopid.eventid)
1707        .await
1708        .map(Json::from)
1709        .map_err(WebError::from)
1710}
1711
1712#[utoipa::path(
1713    get,
1714    path = "/v1/service_account/{id}/_ssh_pubkeys/{tag}",
1715    responses(
1716        (status=200, body=String, content_type="application/json"),
1717        ApiResponseWithout200,
1718    ),
1719    security(("token_jwt" = [])),
1720    tag = "v1/service_account",
1721    operation_id = "service_account_id_ssh_pubkeys_tag_get",
1722)]
1723pub async fn service_account_id_ssh_pubkeys_tag_get(
1724    State(state): State<ServerState>,
1725    Extension(kopid): Extension<KOpId>,
1726    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1727    Path((id, tag)): Path<(String, String)>,
1728) -> Result<Json<Option<String>>, WebError> {
1729    state
1730        .qe_r_ref
1731        .handle_internalsshkeytagread(client_auth_info, id, tag, kopid.eventid)
1732        .await
1733        .map(Json::from)
1734        .map_err(WebError::from)
1735}
1736
1737#[utoipa::path(
1738    delete,
1739    path = "/v1/person/{id}/_ssh_pubkeys/{tag}",
1740    params(
1741        ("tag" = String, description="The tag of the SSH key"),
1742    ),
1743    responses(
1744        DefaultApiResponse,
1745    ),
1746    security(("token_jwt" = [])),
1747    tag = "v1/person/ssh_pubkeys",
1748    operation_id = "person_id_ssh_pubkeys_tag_delete",
1749)]
1750pub async fn person_id_ssh_pubkeys_tag_delete(
1751    State(state): State<ServerState>,
1752    Extension(kopid): Extension<KOpId>,
1753    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1754    Path((id, tag)): Path<(String, String)>,
1755) -> Result<Json<()>, WebError> {
1756    let values = vec![tag];
1757    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1758    state
1759        .qe_w_ref
1760        .handle_removeattributevalues(
1761            client_auth_info,
1762            id,
1763            Attribute::SshPublicKey.to_string(),
1764            values,
1765            filter,
1766            kopid.eventid,
1767        )
1768        .await
1769        .map(Json::from)
1770        .map_err(WebError::from)
1771}
1772
1773#[utoipa::path(
1774    delete,
1775    path = "/v1/service_account/{id}/_ssh_pubkeys/{tag}",
1776    params(
1777        ("tag" = String, description="The tag of the SSH key"),
1778    ),
1779    responses(
1780        DefaultApiResponse,
1781    ),
1782    security(("token_jwt" = [])),
1783    tag = "v1/service_account",
1784    operation_id = "service_account_id_ssh_pubkeys_tag_delete",
1785)]
1786pub async fn service_account_id_ssh_pubkeys_tag_delete(
1787    State(state): State<ServerState>,
1788    Extension(kopid): Extension<KOpId>,
1789    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1790    Path((id, tag)): Path<(String, String)>,
1791) -> Result<Json<()>, WebError> {
1792    let values = vec![tag];
1793    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1794    state
1795        .qe_w_ref
1796        .handle_removeattributevalues(
1797            client_auth_info,
1798            id,
1799            Attribute::SshPublicKey.to_string(),
1800            values,
1801            filter,
1802            kopid.eventid,
1803        )
1804        .await
1805        .map(Json::from)
1806        .map_err(WebError::from)
1807}
1808
1809#[utoipa::path(
1810    get,
1811    path = "/v1/person/{id}/_radius",
1812    responses(
1813        (status=200), ApiResponseWithout200,
1815    ),
1816    security(("token_jwt" = [])),
1817    tag = "v1/person/radius",
1818    operation_id = "person_id_radius_get"
1819)]
1820pub async fn person_id_radius_get(
1822    State(state): State<ServerState>,
1823    Extension(kopid): Extension<KOpId>,
1824    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1825    Path(id): Path<String>,
1826) -> Result<Json<Option<String>>, WebError> {
1827    state
1829        .qe_r_ref
1830        .handle_internalradiusread(client_auth_info, id, kopid.eventid)
1831        .await
1832        .map(Json::from)
1833        .map_err(WebError::from)
1834}
1835
1836#[utoipa::path(
1837    post,
1838    path = "/v1/person/{id}/_radius",
1839    responses(
1840        (status=200), ApiResponseWithout200,
1842    ),
1843    security(("token_jwt" = [])),
1844    tag = "v1/person/radius",
1845    operation_id = "person_id_radius_post"
1846)]
1847pub async fn person_id_radius_post(
1848    State(state): State<ServerState>,
1849    Extension(kopid): Extension<KOpId>,
1850    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1851    Path(id): Path<String>,
1852) -> Result<Json<String>, WebError> {
1853    state
1855        .qe_w_ref
1856        .handle_regenerateradius(client_auth_info, id, kopid.eventid)
1857        .await
1858        .map(Json::from)
1859        .map_err(WebError::from)
1860}
1861
1862#[utoipa::path(
1863    delete,
1864    path = "/v1/person/{id}/_radius",
1865    responses(
1866        DefaultApiResponse,
1867    ),
1868    security(("token_jwt" = [])),
1869    tag = "v1/person/radius",
1870    operation_id = "person_id_radius_delete"
1871)]
1872pub async fn person_id_radius_delete(
1873    State(state): State<ServerState>,
1874    Path(id): Path<String>,
1875    Extension(kopid): Extension<KOpId>,
1876    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1877) -> Result<Json<()>, WebError> {
1878    let attr = "radius_secret".to_string();
1879    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1880    json_rest_event_delete_id_attr(state, id, attr, filter, None, kopid, client_auth_info).await
1881}
1882
1883#[utoipa::path(
1884    get,
1885    path = "/v1/person/{id}/_radius/_token",
1886    responses(
1887        (status=200, body=RadiusAuthToken, content_type="application/json"),
1888        ApiResponseWithout200,
1889    ),
1890    security(("token_jwt" = [])),
1891    tag = "v1/person/radius",
1892    operation_id = "person_id_radius_token_get"
1893)]
1894pub async fn person_id_radius_token_get(
1895    State(state): State<ServerState>,
1896    Path(id): Path<String>,
1897    Extension(kopid): Extension<KOpId>,
1898    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1899) -> Result<Json<RadiusAuthToken>, WebError> {
1900    person_id_radius_handler(state, id, kopid, client_auth_info).await
1901}
1902
1903#[utoipa::path(
1904    get,
1905    path = "/v1/account/{id}/_radius/_token",
1906    responses(
1907        (status=200, body=RadiusAuthToken, content_type="application/json"),
1908        ApiResponseWithout200,
1909    ),
1910    security(("token_jwt" = [])),
1911    tag = "v1/account",
1912    operation_id = "account_id_radius_token_get"
1913)]
1914pub async fn account_id_radius_token_get(
1915    State(state): State<ServerState>,
1916    Path(id): Path<String>,
1917    Extension(kopid): Extension<KOpId>,
1918    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1919) -> Result<Json<RadiusAuthToken>, WebError> {
1920    person_id_radius_handler(state, id, kopid, client_auth_info).await
1921}
1922
1923#[utoipa::path(
1924    post,
1925    path = "/v1/account/{id}/_radius/_token",
1926    responses(
1927        (status=200, body=RadiusAuthToken, content_type="application/json"),
1928        ApiResponseWithout200,
1929    ),
1930    security(("token_jwt" = [])),
1931    tag = "v1/account",
1932    operation_id = "account_id_radius_token_post"
1933)]
1934pub async fn account_id_radius_token_post(
1935    State(state): State<ServerState>,
1936    Path(id): Path<String>,
1937    Extension(kopid): Extension<KOpId>,
1938    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1939) -> Result<Json<RadiusAuthToken>, WebError> {
1940    person_id_radius_handler(state, id, kopid, client_auth_info).await
1941}
1942
1943async fn person_id_radius_handler(
1944    state: ServerState,
1945    id: String,
1946    kopid: KOpId,
1947    client_auth_info: ClientAuthInfo,
1948) -> Result<Json<RadiusAuthToken>, WebError> {
1949    state
1950        .qe_r_ref
1951        .handle_internalradiustokenread(client_auth_info, id, kopid.eventid)
1952        .await
1953        .map(Json::from)
1954        .map_err(WebError::from)
1955}
1956
1957#[utoipa::path(
1958    post,
1959    path = "/v1/person/{id}/_unix",
1960    request_body=AccountUnixExtend,
1961    responses(
1962        DefaultApiResponse,
1963    ),
1964    security(("token_jwt" = [])),
1965    tag = "v1/person/unix",
1966)]
1967#[instrument(name = "account_post_id_unix", level = "INFO", skip(id, state, kopid))]
1968pub async fn person_id_unix_post(
1969    State(state): State<ServerState>,
1970    Path(id): Path<String>,
1971    Extension(kopid): Extension<KOpId>,
1972    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1973    Json(obj): Json<AccountUnixExtend>,
1974) -> Result<Json<()>, WebError> {
1975    state
1976        .qe_w_ref
1977        .handle_idmaccountunixextend(client_auth_info, id, obj, kopid.eventid)
1978        .await
1979        .map(Json::from)
1980        .map_err(WebError::from)
1981}
1982
1983#[utoipa::path(
1984    post,
1985    path = "/v1/service_account/{id}/_unix",
1986    request_body = AccountUnixExtend,
1987    responses(
1988        DefaultApiResponse,
1989    ),
1990    security(("token_jwt" = [])),
1991    tag = "v1/service_account",
1992)]
1993#[instrument(, level = "INFO", skip(id, state, kopid))]
1994pub async fn service_account_id_unix_post(
1995    State(state): State<ServerState>,
1996    Path(id): Path<String>,
1997    Extension(kopid): Extension<KOpId>,
1998    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
1999    Json(obj): Json<AccountUnixExtend>,
2000) -> Result<Json<()>, WebError> {
2001    state
2002        .qe_w_ref
2003        .handle_idmaccountunixextend(client_auth_info, id, obj, kopid.eventid)
2004        .await
2005        .map(Json::from)
2006        .map_err(WebError::from)
2007}
2008
2009#[utoipa::path(
2010    get,post,
2011    path = "/v1/account/{id}/_unix/_token",
2012    responses(
2013        (status=200, body=UnixUserToken, content_type="application/json"),
2014        ApiResponseWithout200,
2015    ),
2016    security(("token_jwt" = [])),
2017    tag = "v1/account",
2018    operation_id = "account_id_unix_token"
2019)]
2020#[instrument(level = "INFO", skip_all)]
2021pub async fn account_id_unix_token(
2022    State(state): State<ServerState>,
2023    Extension(kopid): Extension<KOpId>,
2024    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2025    Path(id): Path<String>,
2026) -> Result<Json<UnixUserToken>, WebError> {
2027    if id.is_empty() {
2029        return Err(OperationError::EmptyRequest.into());
2030    }
2031
2032    let res = state
2033        .qe_r_ref
2034        .handle_internalunixusertokenread(client_auth_info, id, kopid.eventid)
2035        .await
2036        .map(Json::from);
2037
2038    if let Err(OperationError::MissingClass(class)) = &res {
2040        if class == ENTRYCLASS_POSIX_ACCOUNT {
2041            return Err(OperationError::NoMatchingEntries.into());
2042        }
2043    };
2044    if let Err(OperationError::InvalidValueState) = &res {
2046        return Err(OperationError::NoMatchingEntries.into());
2047    };
2048    res.map_err(WebError::from)
2049}
2050
2051#[utoipa::path(
2052    post,
2053    path = "/v1/account/{id}/_unix/_auth",
2054    responses(
2055        (status=200, body=Option<UnixUserToken>, content_type="application/json"),
2056        ApiResponseWithout200,
2057    ),
2058    security(("token_jwt" = [])),
2059    tag = "v1/account",
2060    operation_id = "account_id_unix_auth_post"
2061)]
2062pub async fn account_id_unix_auth_post(
2063    State(state): State<ServerState>,
2064    Extension(kopid): Extension<KOpId>,
2065    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2066    Path(id): Path<String>,
2067    Json(obj): Json<SingleStringRequest>,
2068) -> Result<Json<Option<UnixUserToken>>, WebError> {
2069    state
2070        .qe_r_ref
2071        .handle_idmaccountunixauth(client_auth_info, id, obj.value, kopid.eventid)
2072        .await
2073        .map(Json::from)
2074        .map_err(WebError::from)
2075}
2076
2077#[utoipa::path(
2078    put,
2079    path = "/v1/person/{id}/_unix/_credential",
2080    request_body = SingleStringRequest,
2081    responses(
2082        DefaultApiResponse,
2083    ),
2084    security(("token_jwt" = [])),
2085    tag = "v1/person/unix",
2086    operation_id = "person_id_unix_credential_put"
2087)]
2088pub async fn person_id_unix_credential_put(
2089    State(state): State<ServerState>,
2090    Extension(kopid): Extension<KOpId>,
2091    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2092    Path(id): Path<String>,
2093    Json(obj): Json<SingleStringRequest>,
2094) -> Result<Json<()>, WebError> {
2095    state
2096        .qe_w_ref
2097        .handle_idmaccountunixsetcred(client_auth_info, id, obj.value, kopid.eventid)
2098        .await
2099        .map(Json::from)
2100        .map_err(WebError::from)
2101}
2102
2103#[utoipa::path(
2104    delete,
2105    path = "/v1/person/{id}/_unix/_credential",
2106    responses(
2107        DefaultApiResponse,
2108    ),
2109    security(("token_jwt" = [])),
2110    tag = "v1/person/unix",
2111    operation_id = "person_id_unix_credential_delete"
2112)]
2113pub async fn person_id_unix_credential_delete(
2114    State(state): State<ServerState>,
2115    Extension(kopid): Extension<KOpId>,
2116    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2117    Path(id): Path<String>,
2118) -> Result<Json<()>, WebError> {
2119    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::PosixAccount.into()));
2120    state
2121        .qe_w_ref
2122        .handle_purgeattribute(
2123            client_auth_info,
2124            id,
2125            "unix_password".to_string(),
2126            filter,
2127            kopid.eventid,
2128        )
2129        .await
2130        .map(Json::from)
2131        .map_err(WebError::from)
2132}
2133
2134#[utoipa::path(
2135    post,
2136    path = "/v1/person/{id}/_identify/_user",
2137    responses(
2138        (status=200, body=IdentifyUserResponse, content_type="application/json"),
2139        ApiResponseWithout200,
2140    ),
2141    security(("token_jwt" = [])),
2142    tag = "v1/person",
2143    operation_id = "person_identify_user_post"
2144)]
2145pub async fn person_identify_user_post(
2146    State(state): State<ServerState>,
2147    Extension(kopid): Extension<KOpId>,
2148    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2149    Path(id): Path<String>,
2150    Json(user_request): Json<IdentifyUserRequest>,
2151) -> Result<Json<IdentifyUserResponse>, WebError> {
2152    state
2153        .qe_r_ref
2154        .handle_user_identity_verification(client_auth_info, kopid.eventid, user_request, id)
2155        .await
2156        .map(Json::from)
2157        .map_err(WebError::from)
2158}
2159
2160#[utoipa::path(
2161    get,
2162    path = "/v1/group",
2163    responses(
2164        (status=200,body=Vec<ProtoEntry>, content_type="application/json"),
2165        ApiResponseWithout200,
2166    ),
2167    security(("token_jwt" = [])),
2168    tag = "v1/group",
2169    operation_id = "group_get",
2170)]
2171pub async fn group_get(
2173    State(state): State<ServerState>,
2174    Extension(kopid): Extension<KOpId>,
2175    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2176) -> Result<Json<Vec<ProtoEntry>>, WebError> {
2177    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
2178    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
2179}
2180
2181#[utoipa::path(
2182    get,
2183    path = "/v1/group/_search/{id}",
2184    responses(
2185        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
2186        ApiResponseWithout200,
2187    ),
2188    security(("token_jwt" = [])),
2189    tag = "v1/group",
2190    operation_id = "group_search_id",
2191)]
2192pub async fn group_search_id(
2193    State(state): State<ServerState>,
2194    Extension(kopid): Extension<KOpId>,
2195    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2196    Path(id): Path<String>,
2197) -> Result<Json<Vec<ProtoEntry>>, WebError> {
2198    let filter = filter_all!(f_and!([
2199        f_eq(Attribute::Class, EntryClass::Group.into()),
2200        f_sub(Attribute::Name, PartialValue::new_iname(&id))
2201    ]));
2202    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
2203}
2204
2205#[utoipa::path(
2206    post,
2207    path = "/v1/group",
2208    responses(
2209        DefaultApiResponse,
2210    ),
2211    security(("token_jwt" = [])),
2212    tag = "v1/group",
2213    operation_id = "group_post",
2214)]
2215pub async fn group_post(
2216    State(state): State<ServerState>,
2217    Extension(kopid): Extension<KOpId>,
2218    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2219    Json(obj): Json<ProtoEntry>,
2220) -> Result<Json<()>, WebError> {
2221    let classes = vec!["group".to_string(), "object".to_string()];
2222    json_rest_event_post(state, classes, obj, kopid, client_auth_info).await
2223}
2224
2225#[utoipa::path(
2226    get,
2227    path = "/v1/group/{id}",
2228    responses(
2229        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
2230        ApiResponseWithout200,
2231    ),
2232    security(("token_jwt" = [])),
2233    tag = "v1/group",
2234    operation_id = "group_id_get",
2235)]
2236pub async fn group_id_get(
2237    State(state): State<ServerState>,
2238    Extension(kopid): Extension<KOpId>,
2239    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2240    Path(id): Path<String>,
2241) -> Result<Json<Option<ProtoEntry>>, WebError> {
2242    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
2243    json_rest_event_get_id(state, id, filter, None, kopid, client_auth_info).await
2244}
2245
2246#[utoipa::path(
2247    patch,
2248    path = "/v1/group/{id}",
2249    responses(
2250        DefaultApiResponse,
2251    ),
2252    request_body=ProtoEntry,
2253    security(("token_jwt" = [])),
2254    tag = "v1/group",
2255    operation_id = "group_id_patch",
2256)]
2257pub async fn group_id_patch(
2258    State(state): State<ServerState>,
2259    Extension(kopid): Extension<KOpId>,
2260    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2261    Path(id): Path<String>,
2262    Json(obj): Json<ProtoEntry>,
2263) -> Result<Json<()>, WebError> {
2264    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
2266    let filter = Filter::join_parts_and(filter, filter_all!(f_id(id.as_str())));
2267    state
2268        .qe_w_ref
2269        .handle_internalpatch(client_auth_info, filter, obj, kopid.eventid)
2270        .await
2271        .map(Json::from)
2272        .map_err(WebError::from)
2273}
2274
2275#[utoipa::path(
2276    delete,
2277    path = "/v1/group/{id}",
2278    responses(
2279        DefaultApiResponse,
2280    ),
2281    security(("token_jwt" = [])),
2282    tag = "v1/group",
2283    operation_id = "group_id_delete",
2284)]
2285pub async fn group_id_delete(
2286    State(state): State<ServerState>,
2287    Extension(kopid): Extension<KOpId>,
2288    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2289    Path(id): Path<String>,
2290) -> Result<Json<()>, WebError> {
2291    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
2292    json_rest_event_delete_id(state, id, filter, kopid, client_auth_info).await
2293}
2294
2295#[utoipa::path(
2296    get,
2297    path = "/v1/group/{id}/_attr/{attr}",
2298    responses(
2299        (status=200, body=Vec<String>, content_type="application/json"),
2300        ApiResponseWithout200,
2301    ),
2302    security(("token_jwt" = [])),
2303    tag = "v1/group/attr",
2304    operation_id = "group_id_attr_get",
2305)]
2306pub async fn group_id_attr_get(
2307    State(state): State<ServerState>,
2308    Path((id, attr)): Path<(String, String)>,
2309    Extension(kopid): Extension<KOpId>,
2310    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2311) -> Result<Json<Option<Vec<String>>>, WebError> {
2312    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
2313    json_rest_event_get_id_attr(state, id, attr, filter, kopid, client_auth_info).await
2314}
2315
2316#[utoipa::path(
2317    post,
2318    path = "/v1/group/{id}/_attr/{attr}",
2319    request_body=Vec<String>,
2320    responses(
2321        DefaultApiResponse,
2322    ),
2323    security(("token_jwt" = [])),
2324    tag = "v1/group/attr",
2325    operation_id = "group_id_attr_post",
2326)]
2327pub async fn group_id_attr_post(
2328    Path((id, attr)): Path<(String, String)>,
2329    State(state): State<ServerState>,
2330    Extension(kopid): Extension<KOpId>,
2331    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2332    Json(values): Json<Vec<String>>,
2333) -> Result<Json<()>, WebError> {
2334    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
2335    json_rest_event_post_id_attr(state, id, attr, filter, values, kopid, client_auth_info).await
2336}
2337
2338#[utoipa::path(
2339    delete,
2340    path = "/v1/group/{id}/_attr/{attr}",
2341    request_body=Option<Vec<String>>,
2342    responses(
2343        DefaultApiResponse,
2344    ),
2345    security(("token_jwt" = [])),
2346    tag = "v1/group/attr",
2347    operation_id = "group_id_attr_delete",
2348)]
2349pub async fn group_id_attr_delete(
2350    Path((id, attr)): Path<(String, String)>,
2351    State(state): State<ServerState>,
2352    Extension(kopid): Extension<KOpId>,
2353    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2354    values: Option<Json<Vec<String>>>,
2355) -> Result<Json<()>, WebError> {
2356    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
2357    let values = values.map(|v| v.0);
2358    json_rest_event_delete_id_attr(state, id, attr, filter, values, kopid, client_auth_info).await
2359}
2360
2361#[utoipa::path(
2362    put,
2363    path = "/v1/group/{id}/_attr/{attr}",
2364    request_body=Vec<String>,
2365    responses(
2366        DefaultApiResponse,
2367    ),
2368    security(("token_jwt" = [])),
2369    tag = "v1/group/attr",
2370    operation_id = "group_id_attr_put",
2371)]
2372pub async fn group_id_attr_put(
2373    Path((id, attr)): Path<(String, String)>,
2374    State(state): State<ServerState>,
2375    Extension(kopid): Extension<KOpId>,
2376    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2377    Json(values): Json<Vec<String>>,
2378) -> Result<Json<()>, WebError> {
2379    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
2380    json_rest_event_put_attr(state, id, attr, filter, values, kopid, client_auth_info).await
2381}
2382
2383#[utoipa::path(
2384    post,
2385    path = "/v1/group/{id}/_unix",
2386    request_body = GroupUnixExtend,
2387    responses(
2388        DefaultApiResponse,
2389    ),
2390    security(("token_jwt" = [])),
2391    tag = "v1/group/unix",
2392    operation_id = "group_id_unix_post",
2393)]
2394pub async fn group_id_unix_post(
2395    State(state): State<ServerState>,
2396    Path(id): Path<String>,
2397    Extension(kopid): Extension<KOpId>,
2398    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2399    Json(obj): Json<GroupUnixExtend>,
2400) -> Result<Json<()>, WebError> {
2401    state
2402        .qe_w_ref
2403        .handle_idmgroupunixextend(client_auth_info, id, obj, kopid.eventid)
2404        .await
2405        .map(Json::from)
2406        .map_err(WebError::from)
2407}
2408
2409#[utoipa::path(
2410    get,
2411    path = "/v1/group/{id}/_unix/_token",
2412    responses(
2413        (status=200, body=UnixGroupToken, content_type="application/json"),
2414        ApiResponseWithout200,
2415    ),
2416    security(("token_jwt" = [])),
2417    tag = "v1/group/unix",
2418    operation_id = "group_id_unix_token_get",
2419)]
2420pub async fn group_id_unix_token_get(
2421    State(state): State<ServerState>,
2422    Extension(kopid): Extension<KOpId>,
2423    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2424    Path(id): Path<String>,
2425) -> Result<Json<UnixGroupToken>, WebError> {
2426    state
2427        .qe_r_ref
2428        .handle_internalunixgrouptokenread(client_auth_info, id, kopid.eventid)
2429        .await
2430        .map(Json::from)
2431        .map_err(WebError::from)
2432}
2433
2434#[utoipa::path(
2435    get,
2436    path = "/v1/domain",
2437    responses(
2438        (status=200, body=Vec<ProtoEntry>, content_type="application/json"),
2439        ApiResponseWithout200,
2440    ),
2441    security(("token_jwt" = [])),
2442    tag = "v1/domain",
2443    operation_id = "domain_get",
2444)]
2445pub async fn domain_get(
2446    State(state): State<ServerState>,
2447    Extension(kopid): Extension<KOpId>,
2448    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2449) -> Result<Json<Vec<ProtoEntry>>, WebError> {
2450    let filter = filter_all!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_DOMAIN_INFO)));
2451    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
2452}
2453
2454#[utoipa::path(
2455    get,
2456    path = "/v1/domain/_attr/{attr}",
2457    responses(
2458        (status=200, body=Option<Vec<String>>, content_type="application/json"),
2459        ApiResponseWithout200,
2460    ),
2461    security(("token_jwt" = [])),
2462    tag = "v1/domain",
2463    operation_id = "domain_attr_get",
2464)]
2465pub async fn domain_attr_get(
2466    State(state): State<ServerState>,
2467    Extension(kopid): Extension<KOpId>,
2468    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2469    Path(attr): Path<String>,
2470) -> Result<Json<Option<Vec<String>>>, WebError> {
2471    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::DomainInfo.into()));
2472    json_rest_event_get_attr(
2473        state,
2474        STR_UUID_DOMAIN_INFO,
2475        attr,
2476        filter,
2477        kopid,
2478        client_auth_info,
2479    )
2480    .await
2481}
2482
2483#[utoipa::path(
2484    put,
2485    path = "/v1/domain/_attr/{attr}",
2486    request_body=Vec<String>,
2487    responses(
2488        DefaultApiResponse,
2489    ),
2490    security(("token_jwt" = [])),
2491    tag = "v1/domain",
2492    operation_id = "domain_attr_put",
2493)]
2494pub async fn domain_attr_put(
2495    State(state): State<ServerState>,
2496    Extension(kopid): Extension<KOpId>,
2497    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2498    Path(attr): Path<String>,
2499    Json(values): Json<Vec<String>>,
2500) -> Result<Json<()>, WebError> {
2501    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::DomainInfo.into()));
2502
2503    json_rest_event_put_attr(
2504        state,
2505        STR_UUID_DOMAIN_INFO.to_string(),
2506        attr,
2507        filter,
2508        values,
2509        kopid,
2510        client_auth_info,
2511    )
2512    .await
2513}
2514
2515#[utoipa::path(
2516    delete,
2517    path = "/v1/domain/_attr/{attr}",
2518    request_body=Option<Vec<String>>,
2519    responses(
2520        DefaultApiResponse,
2521    ),
2522    security(("token_jwt" = [])),
2523    tag = "v1/domain",
2524    operation_id = "domain_attr_delete",
2525)]
2526pub async fn domain_attr_delete(
2527    State(state): State<ServerState>,
2528    Path(attr): Path<String>,
2529    Extension(kopid): Extension<KOpId>,
2530    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2531    Json(values): Json<Option<Vec<String>>>,
2532) -> Result<Json<()>, WebError> {
2533    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::DomainInfo.into()));
2534    json_rest_event_delete_attr(
2535        state,
2536        STR_UUID_DOMAIN_INFO.to_string(),
2537        attr,
2538        filter,
2539        values,
2540        kopid,
2541        client_auth_info,
2542    )
2543    .await
2544}
2545
2546#[utoipa::path(
2547    get,
2548    path = "/v1/system",
2549    responses(
2550        (status=200,body=Vec<ProtoEntry>, content_type="application/json"),
2551        ApiResponseWithout200,
2552    ),
2553    security(("token_jwt" = [])),
2554    tag = "v1/system",
2555    operation_id = "system_get",
2556)]
2557pub async fn system_get(
2558    State(state): State<ServerState>,
2559    Extension(kopid): Extension<KOpId>,
2560    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2561) -> Result<Json<Vec<ProtoEntry>>, WebError> {
2562    let filter = filter_all!(f_eq(
2563        Attribute::Uuid,
2564        PartialValue::Uuid(UUID_SYSTEM_CONFIG)
2565    ));
2566    json_rest_event_get(state, None, filter, kopid, client_auth_info).await
2567}
2568
2569#[utoipa::path(
2570    get,
2571    path = "/v1/system/_attr/{attr}",
2572    responses(
2573        (status=200, body=Option<Vec<String>>, content_type="application/json"),
2574        ApiResponseWithout200,
2575    ),
2576    security(("token_jwt" = [])),
2577    tag = "v1/system",
2578    operation_id = "system_attr_get",
2579)]
2580pub async fn system_attr_get(
2581    State(state): State<ServerState>,
2582    Path(attr): Path<String>,
2583    Extension(kopid): Extension<KOpId>,
2584    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2585) -> Result<Json<Option<Vec<String>>>, WebError> {
2586    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SystemConfig.into()));
2587    json_rest_event_get_attr(
2588        state,
2589        STR_UUID_SYSTEM_CONFIG,
2590        attr,
2591        filter,
2592        kopid,
2593        client_auth_info,
2594    )
2595    .await
2596}
2597
2598#[utoipa::path(
2599    post,
2600    path = "/v1/system/_attr/{attr}",
2601    request_body=Vec<String>,
2602    responses(
2603        DefaultApiResponse,
2604    ),
2605    security(("token_jwt" = [])),
2606    tag = "v1/system",
2607    operation_id = "system_attr_post",
2608)]
2609pub async fn system_attr_post(
2610    State(state): State<ServerState>,
2611    Path(attr): Path<String>,
2612    Extension(kopid): Extension<KOpId>,
2613    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2614    Json(values): Json<Vec<String>>,
2615) -> Result<Json<()>, WebError> {
2616    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SystemConfig.into()));
2617    json_rest_event_post_attr(
2618        state,
2619        STR_UUID_SYSTEM_CONFIG.to_string(),
2620        attr,
2621        filter,
2622        values,
2623        kopid,
2624        client_auth_info,
2625    )
2626    .await
2627}
2628
2629#[utoipa::path(
2630    delete,
2631    path = "/v1/system/_attr/{attr}",
2632    request_body=Option<Vec<String>>,
2633    responses(
2634        DefaultApiResponse,
2635    ),
2636    security(("token_jwt" = [])),
2637    tag = "v1/system",
2638    operation_id = "system_attr_delete",
2639)]
2640pub async fn system_attr_delete(
2641    State(state): State<ServerState>,
2642    Path(attr): Path<String>,
2643    Extension(kopid): Extension<KOpId>,
2644    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2645    Json(values): Json<Option<Vec<String>>>,
2646) -> Result<Json<()>, WebError> {
2647    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SystemConfig.into()));
2648    json_rest_event_delete_attr(
2649        state,
2650        STR_UUID_SYSTEM_CONFIG.to_string(),
2651        attr,
2652        filter,
2653        values,
2654        kopid,
2655        client_auth_info,
2656    )
2657    .await
2658}
2659
2660#[utoipa::path(
2661    put,
2662    path = "/v1/system/_attr/{attr}",
2663    request_body=Vec<String>,
2664    responses(
2665        DefaultApiResponse,
2666    ),
2667    security(("token_jwt" = [])),
2668    tag = "v1/system",
2669    operation_id = "system_attr_put",
2670)]
2671pub async fn system_attr_put(
2672    State(state): State<ServerState>,
2673    Path(attr): Path<String>,
2674    Extension(kopid): Extension<KOpId>,
2675    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2676    Json(values): Json<Vec<String>>,
2677) -> Result<Json<()>, WebError> {
2678    let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SystemConfig.into()));
2679    json_rest_event_put_attr(
2680        state,
2681        STR_UUID_SYSTEM_CONFIG.to_string(),
2682        attr,
2683        filter,
2684        values,
2685        kopid,
2686        client_auth_info,
2687    )
2688    .await
2689}
2690
2691#[utoipa::path(
2692    post,
2693    path = "/v1/recycle_bin",
2694    responses(
2695        (status=200,body=Vec<ProtoEntry>, content_type="application/json"),
2696        ApiResponseWithout200,
2697    ),
2698    security(("token_jwt" = [])),
2699    tag = "v1/recycle_bin",
2700    operation_id="recycle_bin_get",
2701)]
2702pub async fn recycle_bin_get(
2703    State(state): State<ServerState>,
2704    Extension(kopid): Extension<KOpId>,
2705    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2706) -> Result<Json<Vec<ProtoEntry>>, WebError> {
2707    let filter = filter_all!(f_pres(Attribute::Class));
2708    let attrs = None;
2709    state
2710        .qe_r_ref
2711        .handle_internalsearchrecycled(client_auth_info, filter, attrs, kopid.eventid)
2712        .await
2713        .map(Json::from)
2714        .map_err(WebError::from)
2715}
2716
2717#[utoipa::path(
2718    get,
2719    path = "/v1/recycle_bin/{id}",
2720    responses(
2721        (status=200, body=Option<ProtoEntry>, content_type="application/json"),
2722        ApiResponseWithout200,
2723    ),
2724    security(("token_jwt" = [])),
2725    tag = "v1/recycle_bin",
2726    operation_id = "recycle_bin_id_get",
2727)]
2728pub async fn recycle_bin_id_get(
2729    State(state): State<ServerState>,
2730    Path(id): Path<String>,
2731    Extension(kopid): Extension<KOpId>,
2732    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2733) -> Result<Json<Option<ProtoEntry>>, WebError> {
2734    let filter = filter_all!(f_id(id.as_str()));
2735    let attrs = None;
2736
2737    state
2738        .qe_r_ref
2739        .handle_internalsearchrecycled(client_auth_info, filter, attrs, kopid.eventid)
2740        .await
2741        .map(|mut r| r.pop())
2742        .map(Json::from)
2743        .map_err(WebError::from)
2744}
2745
2746#[utoipa::path(
2747    post,
2748    path = "/v1/recycle_bin/{id}/_revive",
2749    responses(
2750        DefaultApiResponse,
2751    ),
2752    security(("token_jwt" = [])),
2753    tag = "v1/recycle_bin",
2754    operation_id = "recycle_bin_revive_id_post",
2755)]
2756pub async fn recycle_bin_revive_id_post(
2757    State(state): State<ServerState>,
2758    Path(id): Path<String>,
2759    Extension(kopid): Extension<KOpId>,
2760    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2761) -> Result<Json<()>, WebError> {
2762    let filter = filter_all!(f_id(id.as_str()));
2763    state
2764        .qe_w_ref
2765        .handle_reviverecycled(client_auth_info, filter, kopid.eventid)
2766        .await
2767        .map(Json::from)
2768        .map_err(WebError::from)
2769}
2770
2771#[utoipa::path(
2772    get,
2773    path = "/v1/self/_applinks",
2774    responses(
2775        (status=200, body=Vec<AppLink>, content_type="application/json"),
2776        ApiResponseWithout200,
2777    ),
2778    security(("token_jwt" = [])),
2779    tag = "v1/self",
2780    operation_id = "self_applinks_get",
2781)]
2782pub async fn applinks_get(
2784    State(state): State<ServerState>,
2785    Extension(kopid): Extension<KOpId>,
2786    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2787) -> Result<Json<Vec<AppLink>>, WebError> {
2788    state
2789        .qe_r_ref
2790        .handle_list_applinks(client_auth_info, kopid.eventid)
2791        .await
2792        .map(Json::from)
2793        .map_err(WebError::from)
2794}
2795
2796#[utoipa::path(
2797    post,
2798    path = "/v1/reauth",
2799    responses(
2800        (status=200, content_type="application/json"), ApiResponseWithout200,
2802    ),
2803    request_body = AuthIssueSession,
2804    security(("token_jwt" = [])),
2805    tag = "v1/auth",
2806    operation_id = "reauth_post",
2807)] pub async fn reauth(
2809    State(state): State<ServerState>,
2810    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2811    jar: CookieJar,
2812    Extension(kopid): Extension<KOpId>,
2813    Json(obj): Json<AuthIssueSession>,
2814) -> Result<Response, WebError> {
2815    let inter = state
2817        .qe_r_ref
2818        .handle_reauth(client_auth_info, obj, kopid.eventid)
2819        .await;
2820    debug!("ReAuth result: {:?}", inter);
2821    auth_session_state_management(&state, jar, inter)
2822}
2823
2824#[utoipa::path(
2825    post,
2826    path = "/v1/auth",
2827    responses(
2828        (status=200, content_type="application/json"), ApiResponseWithout200,
2830    ),
2831    request_body = AuthRequest,
2832    security(("token_jwt" = [])),
2833    tag = "v1/auth",
2834    operation_id = "auth_post",
2835)]
2836pub async fn auth(
2837    State(state): State<ServerState>,
2838    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
2839    jar: CookieJar,
2840    headers: HeaderMap,
2841    Extension(kopid): Extension<KOpId>,
2842    Json(auth_req): Json<AuthRequest>,
2843) -> Result<Response, WebError> {
2844    let maybe_sessionid = state.get_current_auth_session_id(&headers, &jar);
2849    debug!("Session ID: {:?}", maybe_sessionid);
2850
2851    let auth_step = AuthStep::from(auth_req.step);
2853
2854    let inter = state .qe_r_ref
2859        .handle_auth(maybe_sessionid, auth_step, kopid.eventid, client_auth_info)
2860        .await;
2861    debug!("Auth result: {:?}", inter);
2862    auth_session_state_management(&state, jar, inter)
2863}
2864
2865#[instrument(level = "trace", skip_all)]
2867fn auth_session_state_management(
2868    state: &ServerState,
2869    mut jar: CookieJar,
2870    inter: Result<AuthResult, OperationError>,
2871) -> Result<Response, WebError> {
2872    let mut auth_session_id_tok = None;
2873
2874    let res: Result<AuthResponse, _> = match inter {
2875        Ok(AuthResult {
2876            state: auth_state,
2877            sessionid,
2878        }) => {
2879            match auth_state {
2881                AuthState::Choose(allowed) => {
2882                    debug!("🧩 -> AuthState::Choose");
2883                    let kref = &state.jws_signer;
2884                    let jws = Jws::into_json(&sessionid).map_err(|e| {
2885                        error!(?e);
2886                        OperationError::InvalidSessionState
2887                    })?;
2888
2889                    kref.sign(&jws)
2891                        .map(|jwss| {
2892                            auth_session_id_tok = Some(jwss.to_string());
2893                        })
2894                        .map_err(|e| {
2895                            error!(?e);
2896                            OperationError::InvalidSessionState
2897                        })
2898                        .map(|_| ProtoAuthState::Choose(allowed))
2899                }
2900                AuthState::Continue(allowed) => {
2901                    debug!("🧩 -> AuthState::Continue");
2902                    let kref = &state.jws_signer;
2903                    let jws = Jws::into_json(&sessionid).map_err(|e| {
2905                        error!(?e);
2906                        OperationError::InvalidSessionState
2907                    })?;
2908                    kref.sign(&jws)
2909                        .map(|jwss| {
2910                            auth_session_id_tok = Some(jwss.to_string());
2911                        })
2912                        .map_err(|e| {
2913                            error!(?e);
2914                            OperationError::InvalidSessionState
2915                        })
2916                        .map(|_| ProtoAuthState::Continue(allowed))
2917                }
2918                AuthState::Success(token, issue) => {
2919                    debug!("🧩 -> AuthState::Success");
2920
2921                    match issue {
2922                        AuthIssueSession::Token => Ok(ProtoAuthState::Success(token.to_string())),
2923                        AuthIssueSession::Cookie => {
2924                            let token_str = token.to_string();
2926                            let mut bearer_cookie =
2927                                Cookie::new(COOKIE_BEARER_TOKEN, token_str.clone());
2928                            bearer_cookie.set_secure(state.secure_cookies);
2929                            bearer_cookie.set_same_site(SameSite::Lax);
2930                            bearer_cookie.set_http_only(true);
2931                            bearer_cookie.set_domain(state.domain.clone());
2935                            bearer_cookie.set_path("/");
2936                            jar = jar
2937                                .add(bearer_cookie)
2938                                .remove(Cookie::from(COOKIE_AUTH_SESSION_ID));
2939                            Ok(ProtoAuthState::Success(token_str))
2940                        }
2941                    }
2942                }
2943                AuthState::External(_) => {
2944                    warn!("🧩 -> AuthState::Denied - we tried to use an external handler within an API");
2945                    Ok(ProtoAuthState::Denied("unable to use external authentication handler from this API.".into()))
2946                }
2947                AuthState::Denied(reason) => {
2948                    debug!("🧩 -> AuthState::Denied");
2949                    Ok(ProtoAuthState::Denied(reason))
2950                }
2951            }
2952            .map(|state| AuthResponse { sessionid, state })
2953        }
2954        Err(e) => Err(e),
2955    };
2956
2957    res.map(|response| {
2959        jar = if let Some(token) = auth_session_id_tok.clone() {
2960            let mut token_cookie = Cookie::new(COOKIE_AUTH_SESSION_ID, token);
2961            token_cookie.set_secure(state.secure_cookies);
2962            token_cookie.set_same_site(SameSite::Strict);
2963            token_cookie.set_http_only(true);
2964            jar.add(token_cookie)
2968        } else {
2969            jar
2970        };
2971
2972        trace!(?jar);
2973
2974        let mut res = (jar, Json::from(response)).into_response();
2975
2976        match auth_session_id_tok {
2977            Some(tok) => {
2978                match HeaderValue::from_str(&tok) {
2979                    Ok(val) => {
2980                        res.headers_mut().insert(KSESSIONID, val);
2981                    }
2982                    Err(err) => {
2983                        admin_error!(?err, "Failed to add sessionid {} to header", tok);
2984                    }
2985                }
2986                res
2987            }
2988            None => res,
2989        }
2990    })
2991    .map_err(WebError::from)
2992}
2993
2994#[utoipa::path(
2995    get,
2996    path = "/v1/auth/valid",
2997    responses(
2998        DefaultApiResponse,
2999    ),
3000    security(("token_jwt" = [])),
3001    tag = "v1/auth",
3002    operation_id = "auth_valid",
3003)]
3004pub async fn auth_valid(
3005    State(state): State<ServerState>,
3006    Extension(kopid): Extension<KOpId>,
3007    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
3008) -> Result<Json<()>, WebError> {
3009    state
3010        .qe_r_ref
3011        .handle_auth_valid(client_auth_info, kopid.eventid)
3012        .await
3013        .map(Json::from)
3014        .map_err(WebError::from)
3015}
3016
3017#[utoipa::path(
3018    get,
3019    path = "/v1/debug/ipinfo",
3020    responses(
3021        (status = 200, description = "Ok", body=String, content_type="application/json"),
3022    ),
3023    security(("token_jwt" = [])),
3024    tag = "v1/debug",
3025    operation_id = "debug_ipinfo",
3026)]
3027pub async fn debug_ipinfo(
3028    State(_state): State<ServerState>,
3029    Extension(trusted_client_ip): Extension<ClientConnInfo>,
3030) -> Result<Json<IpAddr>, ()> {
3031    Ok(Json::from(trusted_client_ip.client_ip_addr))
3032}
3033
3034#[derive(utoipa::ToSchema)]
3035#[schema [value_type=HashMap<String, String>]]
3036#[allow(dead_code)]
3038struct SchemaJwk(Jwk);
3039
3040#[utoipa::path(
3041    get,
3042    path = "/v1/jwk/{key_id}",
3043    responses(
3044        (status=200, body=SchemaJwk, content_type="application/json"),
3045        ApiResponseWithout200,
3046    ),
3047    security(("token_jwt" = [])),
3048    tag = "v1/jwk",
3049    operation_id = "public_jwk_key_id_get"
3050)]
3051pub async fn public_jwk_key_id_get(
3052    State(state): State<ServerState>,
3053    Path(key_id): Path<String>,
3054    Extension(kopid): Extension<KOpId>,
3055) -> Result<Json<Jwk>, WebError> {
3056    if key_id.len() > 64 {
3057        return Err(WebError::from(OperationError::NoMatchingEntries));
3059    }
3060    state
3061        .qe_r_ref
3062        .handle_public_jwk_get(key_id, kopid.eventid)
3063        .await
3064        .map(Json::from)
3065        .map_err(WebError::from)
3066}
3067
3068fn cacheable_routes(state: ServerState) -> Router<ServerState> {
3069    Router::new()
3070        .route("/v1/jwk/{key_id}", get(public_jwk_key_id_get))
3071        .route(
3072            "/v1/person/{id}/_radius/_token",
3073            get(person_id_radius_token_get),
3074        )
3075        .route("/v1/account/{id}/_unix/_token", get(account_id_unix_token))
3076        .route(
3077            "/v1/account/{id}/_radius/_token",
3078            get(account_id_radius_token_get),
3079        )
3080        .layer(from_fn(cache_me_short))
3081        .with_state(state)
3082}
3083
3084#[instrument(skip(state), name = "https_v1_route_setup")]
3085pub(crate) fn route_setup(state: ServerState) -> Router<ServerState> {
3086    Router::new()
3087        .route("/v1/oauth2", get(super::v1_oauth2::oauth2_get))
3088        .route(
3089            "/v1/oauth2/_basic",
3090            post(super::v1_oauth2::oauth2_basic_post),
3091        )
3092        .route(
3093            "/v1/oauth2/_public",
3094            post(super::v1_oauth2::oauth2_public_post),
3095        )
3096        .route(
3097            "/v1/oauth2/{rs_name}",
3098            get(super::v1_oauth2::oauth2_id_get)
3099                .patch(super::v1_oauth2::oauth2_id_patch)
3100                .delete(super::v1_oauth2::oauth2_id_delete),
3101        )
3102        .route(
3103            "/v1/oauth2/{rs_name}/_attr/{attr}",
3104            post(super::v1_oauth2::oauth2_id_attr_post)
3105                .delete(super::v1_oauth2::oauth2_id_attr_delete),
3106        )
3107        .route(
3108            "/v1/oauth2/{rs_name}/_image",
3109            post(super::v1_oauth2::oauth2_id_image_post)
3110                .delete(super::v1_oauth2::oauth2_id_image_delete),
3111        )
3112        .route(
3113            "/v1/oauth2/{rs_name}/_basic_secret",
3114            get(super::v1_oauth2::oauth2_id_get_basic_secret),
3115        )
3116        .route(
3117            "/v1/oauth2/{rs_name}/_scopemap/{group}",
3118            post(super::v1_oauth2::oauth2_id_scopemap_post)
3119                .delete(super::v1_oauth2::oauth2_id_scopemap_delete),
3120        )
3121        .route(
3122            "/v1/oauth2/{rs_name}/_sup_scopemap/{group}",
3123            post(super::v1_oauth2::oauth2_id_sup_scopemap_post)
3124                .delete(super::v1_oauth2::oauth2_id_sup_scopemap_delete),
3125        )
3126        .route(
3127            "/v1/oauth2/{rs_name}/_claimmap/{claim_name}/{group}",
3128            post(super::v1_oauth2::oauth2_id_claimmap_post)
3129                .delete(super::v1_oauth2::oauth2_id_claimmap_delete),
3130        )
3131        .route(
3132            "/v1/oauth2/{rs_name}/_claimmap/{claim_name}",
3133            post(super::v1_oauth2::oauth2_id_claimmap_join_post),
3134        )
3135        .route("/v1/raw/create", post(raw_create))
3136        .route("/v1/raw/modify", post(raw_modify))
3137        .route("/v1/raw/delete", post(raw_delete))
3138        .route("/v1/raw/search", post(raw_search))
3139        .route("/v1/schema", get(schema_get))
3140        .route(
3141            "/v1/schema/attributetype",
3142            get(schema_attributetype_get), )
3144        .route(
3145            "/v1/schema/attributetype/{id}",
3146            get(schema_attributetype_get_id),
3147        )
3148        .route(
3150            "/v1/schema/classtype",
3151            get(schema_classtype_get), )
3153        .route(
3154            "/v1/schema/classtype/{id}",
3155            get(schema_classtype_get_id), )
3158        .route("/v1/self", get(whoami))
3159        .route("/v1/self/_uat", get(whoami_uat))
3160        .route("/v1/self/_applinks", get(applinks_get))
3177        .route("/v1/person", get(person_get).post(person_post))
3179        .route("/v1/person/_search/{id}", get(person_search_id))
3180        .route(
3181            "/v1/person/{id}",
3182            get(person_id_get)
3183                .patch(person_id_patch)
3184                .delete(person_id_delete),
3185        )
3186        .route(
3187            "/v1/person/{id}/_attr/{attr}",
3188            get(person_id_get_attr)
3189                .put(person_id_put_attr)
3190                .post(person_id_post_attr)
3191                .delete(person_id_delete_attr),
3192        )
3193        .route(
3194            "/v1/person/{id}/_certificate",
3195            get(person_get_id_certificate).post(person_post_id_certificate),
3196        )
3197        .route(
3198            "/v1/person/{id}/_credential/_status",
3199            get(person_get_id_credential_status),
3200        )
3201        .route(
3202            "/v1/person/{id}/_credential/_update",
3203            get(person_id_credential_update_get),
3204        )
3205        .route(
3206            "/v1/person/{id}/_credential/_update_intent/{ttl}",
3207            get(person_id_credential_update_intent_ttl_get),
3208        )
3209        .route(
3210            "/v1/person/{id}/_credential/_update_intent",
3211            get(person_id_credential_update_intent_get),
3212        )
3213        .route(
3214            "/v1/person/{id}/_ssh_pubkeys",
3215            get(person_id_ssh_pubkeys_get).post(person_id_ssh_pubkeys_post),
3216        )
3217        .route(
3218            "/v1/person/{id}/_ssh_pubkeys/{tag}",
3219            get(person_id_ssh_pubkeys_tag_get).delete(person_id_ssh_pubkeys_tag_delete),
3220        )
3221        .route(
3222            "/v1/person/{id}/_radius",
3223            get(person_id_radius_get)
3224                .post(person_id_radius_post)
3225                .delete(person_id_radius_delete),
3226        )
3227        .route("/v1/person/{id}/_unix", post(person_id_unix_post))
3228        .route(
3229            "/v1/person/{id}/_unix/_credential",
3230            put(person_id_unix_credential_put).delete(person_id_unix_credential_delete),
3231        )
3232        .route(
3233            "/v1/person/{id}/_identify_user",
3234            post(person_identify_user_post),
3235        )
3236        .route(
3238            "/v1/service_account",
3239            get(service_account_get).post(service_account_post),
3240        )
3241        .route(
3242            "/v1/service_account/",
3243            get(service_account_get).post(service_account_post),
3244        )
3245        .route(
3246            "/v1/service_account/{id}",
3247            get(service_account_id_get)
3248                .delete(service_account_id_delete)
3249                .patch(service_account_id_patch),
3250        )
3251        .route(
3252            "/v1/service_account/{id}/_attr/{attr}",
3253            get(service_account_id_get_attr)
3254                .put(service_account_id_put_attr)
3255                .post(service_account_id_post_attr)
3256                .delete(service_account_id_delete_attr),
3257        )
3258        .route(
3260            "/v1/service_account/{id}/_into_person",
3261            #[allow(deprecated)]
3262            post(service_account_into_person),
3263        )
3264        .route(
3265            "/v1/service_account/{id}/_api_token",
3266            post(service_account_api_token_post).get(service_account_api_token_get),
3267        )
3268        .route(
3269            "/v1/service_account/{id}/_api_token/{token_id}",
3270            delete(service_account_api_token_delete),
3271        )
3272        .route(
3277            "/v1/service_account/{id}/_credential/_generate",
3278            get(service_account_credential_generate),
3279        )
3280        .route(
3281            "/v1/service_account/{id}/_credential/_status",
3282            get(service_account_id_credential_status_get),
3283        )
3284        .route(
3289            "/v1/service_account/{id}/_ssh_pubkeys",
3290            get(service_account_id_ssh_pubkeys_get).post(service_account_id_ssh_pubkeys_post),
3291        )
3292        .route(
3293            "/v1/service_account/{id}/_ssh_pubkeys/{tag}",
3294            get(service_account_id_ssh_pubkeys_tag_get)
3295                .delete(service_account_id_ssh_pubkeys_tag_delete),
3296        )
3297        .route(
3298            "/v1/service_account/{id}/_unix",
3299            post(service_account_id_unix_post),
3300        )
3301        .route(
3302            "/v1/account/{id}/_unix/_auth",
3303            post(account_id_unix_auth_post),
3304        )
3305        .route("/v1/account/{id}/_unix/_token", post(account_id_unix_token))
3306        .route(
3307            "/v1/account/{id}/_radius/_token",
3308            post(account_id_radius_token_post),
3309        )
3310        .route(
3311            "/v1/account/{id}/_ssh_pubkeys",
3312            #[allow(deprecated)]
3313            get(account_id_ssh_pubkeys_get),
3314        )
3315        .route(
3316            "/v1/account/{id}/_ssh_pubkeys/{tag}",
3317            get(account_id_ssh_pubkeys_tag_get),
3318        )
3319        .route(
3320            "/v1/account/{id}/_user_auth_token",
3321            get(account_id_user_auth_token_get),
3322        )
3323        .route(
3324            "/v1/account/{id}/_user_auth_token/{token_id}",
3325            delete(account_user_auth_token_delete),
3326        )
3327        .route(
3328            "/v1/credential/_exchange_intent",
3329            post(credential_update_exchange_intent),
3330        )
3331        .route("/v1/credential/_status", post(credential_update_status))
3332        .route("/v1/credential/_update", post(credential_update_update))
3333        .route("/v1/credential/_commit", post(credential_update_commit))
3334        .route("/v1/credential/_cancel", post(credential_update_cancel))
3335        .route("/v1/domain", get(domain_get))
3337        .route(
3338            "/v1/domain/_image",
3339            post(super::v1_domain::image_post).delete(super::v1_domain::image_delete),
3340        )
3341        .route(
3342            "/v1/domain/_attr/{attr}",
3343            get(domain_attr_get)
3344                .put(domain_attr_put)
3345                .delete(domain_attr_delete),
3346        )
3347        .route("/v1/group/{id}/_unix/_token", get(group_id_unix_token_get))
3348        .route("/v1/group/{id}/_unix", post(group_id_unix_post))
3349        .route("/v1/group", get(group_get).post(group_post))
3350        .route("/v1/group/_search/{id}", get(group_search_id))
3351        .route(
3352            "/v1/group/{id}",
3353            get(group_id_get)
3354                .patch(group_id_patch)
3355                .delete(group_id_delete),
3356        )
3357        .route(
3358            "/v1/group/{id}/_attr/{attr}",
3359            delete(group_id_attr_delete)
3360                .get(group_id_attr_get)
3361                .put(group_id_attr_put)
3362                .post(group_id_attr_post),
3363        )
3364        .with_state(state.clone())
3365        .route("/v1/system", get(system_get))
3366        .route(
3367            "/v1/system/_attr/{attr}",
3368            get(system_attr_get)
3369                .post(system_attr_post)
3370                .put(system_attr_put)
3371                .delete(system_attr_delete),
3372        )
3373        .route("/v1/recycle_bin", get(recycle_bin_get))
3374        .route("/v1/recycle_bin/{id}", get(recycle_bin_id_get))
3375        .route(
3376            "/v1/recycle_bin/{id}/_revive",
3377            post(recycle_bin_revive_id_post),
3378        )
3379        .route("/v1/auth", post(auth))
3386        .route(V1_AUTH_VALID, get(auth_valid))
3387        .route("/v1/logout", get(logout))
3388        .route("/v1/reauth", post(reauth))
3389        .with_state(state.clone())
3390        .layer(from_fn(dont_cache_me))
3391        .merge(cacheable_routes(state))
3392        .route("/v1/debug/ipinfo", get(debug_ipinfo))
3393}