kanidmd_core/https/views/
radius.rs

1use crate::https::extractors::{DomainInfo, VerifiedClientInformation};
2use crate::https::middleware::KOpId;
3use crate::https::views::errors::HtmxError;
4use crate::https::ServerState;
5use askama::Template;
6use askama_axum::IntoResponse;
7use axum::extract::State;
8use axum::response::Response;
9use axum::Extension;
10use axum_extra::extract::CookieJar;
11use kanidm_proto::internal::UserAuthToken;
12
13use super::constants::{ProfileMenuItems, /*UiMessage,*/ Urls};
14use super::navbar::NavbarCtx;
15use crate::https::views::login::{LoginDisplayCtx, Reauth, ReauthPurpose};
16
17#[derive(Template)]
18#[template(path = "user_settings.html")]
19pub(crate) struct ProfileView {
20    navbar_ctx: NavbarCtx,
21    profile_partial: RadiusPartialView,
22}
23
24#[derive(Template, Clone)]
25#[template(path = "radius.html")]
26pub(crate) struct RadiusPartialView {
27    menu_active_item: ProfileMenuItems,
28    radius_password: Option<String>,
29}
30
31pub(crate) async fn view_radius_get(
32    State(state): State<ServerState>,
33    Extension(kopid): Extension<KOpId>,
34    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
35    DomainInfo(domain_info): DomainInfo,
36    jar: CookieJar,
37) -> axum::response::Result<Response> {
38    let uat: &UserAuthToken = client_auth_info
39        .pre_validated_uat()
40        .map_err(|op_err| HtmxError::new(&kopid, op_err, domain_info.clone()))?;
41
42    let time = time::OffsetDateTime::now_utc() + time::Duration::new(60, 0);
43    let can_rw = uat.purpose_readwrite_active(time);
44
45    // The user lacks an elevated session, request a re-auth
46    if !can_rw {
47        let display_ctx = LoginDisplayCtx {
48            domain_info,
49            oauth2: None,
50            reauth: Some(Reauth {
51                username: uat.spn.clone(),
52                purpose: ReauthPurpose::ProfileSettings,
53            }),
54            error: None,
55        };
56
57        return Ok(super::login::view_reauth_get(
58            state,
59            client_auth_info,
60            kopid,
61            jar,
62            Urls::Radius.as_ref(),
63            display_ctx,
64        )
65        .await);
66    }
67
68    let radius_password = state
69        .qe_r_ref
70        .handle_internalradiusread(client_auth_info.clone(), uat.spn.clone(), kopid.eventid)
71        .await
72        .map_err(|op_err| HtmxError::new(&kopid, op_err, domain_info.clone()))?;
73
74    Ok(ProfileView {
75        navbar_ctx: NavbarCtx { domain_info },
76        profile_partial: RadiusPartialView {
77            menu_active_item: ProfileMenuItems::Radius,
78            radius_password,
79        },
80    }
81    .into_response())
82}
83
84pub(crate) async fn view_radius_post(
85    State(state): State<ServerState>,
86    Extension(kopid): Extension<KOpId>,
87    VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
88    DomainInfo(domain_info): DomainInfo,
89) -> axum::response::Result<Response> {
90    let uat_client_auth_info = client_auth_info.clone();
91    let uat: &UserAuthToken = uat_client_auth_info
92        .pre_validated_uat()
93        .map_err(|op_err| HtmxError::new(&kopid, op_err, domain_info.clone()))?;
94
95    let radius_password = state
96        .qe_w_ref
97        .handle_regenerateradius(client_auth_info, uat.uuid.to_string(), kopid.eventid)
98        .await
99        .map_err(|op_err| HtmxError::new(&kopid, op_err, domain_info.clone()))?;
100
101    Ok(RadiusPartialView {
102        menu_active_item: ProfileMenuItems::Radius,
103        radius_password: Some(radius_password),
104    }
105    .into_response())
106}