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