mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Add stricter headers (#546)
This commit is contained in:
parent
aca6b23d54
commit
002e3d696b
|
@ -7,6 +7,30 @@ use oauth2_ext::PkceCodeChallenge;
|
|||
use std::collections::HashMap;
|
||||
use url::Url;
|
||||
|
||||
macro_rules! assert_no_cache {
|
||||
($response:expr) => {{
|
||||
// Check we have correct nocache headers.
|
||||
let cache_header: &str = $response
|
||||
.headers()
|
||||
.get("cache-control")
|
||||
.expect("missing cache-control header")
|
||||
.to_str()
|
||||
.expect("invalid cache-control header");
|
||||
|
||||
assert!(cache_header.contains("no-store"));
|
||||
assert!(cache_header.contains("max-age=0"));
|
||||
|
||||
let pragma_header: &str = $response
|
||||
.headers()
|
||||
.get("pragma")
|
||||
.expect("missing cache-control header")
|
||||
.to_str()
|
||||
.expect("invalid cache-control header");
|
||||
|
||||
assert!(pragma_header.contains("no-cache"));
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_oauth2_basic_flow() {
|
||||
run_test(|rsclient: KanidmClient| {
|
||||
|
@ -73,6 +97,7 @@ fn test_oauth2_basic_flow() {
|
|||
.expect("Failed to send request.");
|
||||
|
||||
assert!(response.status() == reqwest::StatusCode::OK);
|
||||
assert_no_cache!(response);
|
||||
|
||||
let consent_req: ConsentRequest = response
|
||||
.json()
|
||||
|
@ -92,6 +117,7 @@ fn test_oauth2_basic_flow() {
|
|||
|
||||
// This should yield a 302 redirect with some query params.
|
||||
assert!(response.status() == reqwest::StatusCode::FOUND);
|
||||
assert_no_cache!(response);
|
||||
|
||||
// And we should have a URL in the location header.
|
||||
let redir_str = response
|
||||
|
@ -134,6 +160,7 @@ fn test_oauth2_basic_flow() {
|
|||
.expect("Failed to send code exchange request.");
|
||||
|
||||
assert!(response.status() == reqwest::StatusCode::OK);
|
||||
assert_no_cache!(response);
|
||||
|
||||
// The body is a json AccessTokenResponse
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,5 @@
|
|||
use super::{
|
||||
json_rest_event_get, json_rest_event_post, to_tide_response, AppState, RequestExtensions,
|
||||
};
|
||||
use super::v1::{json_rest_event_get, json_rest_event_post};
|
||||
use super::{to_tide_response, AppState, RequestExtensions};
|
||||
use crate::idm::oauth2::{
|
||||
AccessTokenRequest, AuthorisationRequest, AuthorisePermitSuccess, ErrorResponse, Oauth2Error,
|
||||
};
|
||||
|
@ -214,8 +213,6 @@ async fn oauth2_authorise(
|
|||
}
|
||||
}
|
||||
.map(|mut res| {
|
||||
res.insert_header("Cache-Control", "no-store");
|
||||
res.insert_header("Pragma", "no-cache");
|
||||
res.insert_header("X-KANIDM-OPID", hvalue);
|
||||
res
|
||||
})
|
||||
|
@ -290,8 +287,6 @@ async fn oauth2_authorise_permit(
|
|||
tide::Response::new(500)
|
||||
}
|
||||
};
|
||||
res.insert_header("Cache-Control", "no-store");
|
||||
res.insert_header("Pragma", "no-cache");
|
||||
res.insert_header("X-KANIDM-OPID", hvalue);
|
||||
Ok(res)
|
||||
}
|
||||
|
@ -359,13 +354,19 @@ pub async fn oauth2_token_post(mut req: tide::Request<AppState>) -> tide::Result
|
|||
}
|
||||
}
|
||||
.map(|mut res| {
|
||||
res.insert_header("Cache-Control", "no-store");
|
||||
res.insert_header("Pragma", "no-cache");
|
||||
res.insert_header("X-KANIDM-OPID", hvalue);
|
||||
res
|
||||
})
|
||||
}
|
||||
|
||||
// For future openid integration
|
||||
pub async fn get_openid_configuration(_req: tide::Request<AppState>) -> tide::Result {
|
||||
let mut res = tide::Response::new(200);
|
||||
res.set_content_type("text/html;charset=utf-8");
|
||||
res.set_body("");
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/*
|
||||
pub async fn oauth2_token_introspect_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
}
|
||||
|
|
896
kanidmd/src/lib/core/https/v1.rs
Normal file
896
kanidmd/src/lib/core/https/v1.rs
Normal file
|
@ -0,0 +1,896 @@
|
|||
use crate::event::AuthResult;
|
||||
use crate::filter::{Filter, FilterInvalid};
|
||||
use crate::idm::AuthState;
|
||||
use crate::prelude::*;
|
||||
use crate::status::StatusRequestEvent;
|
||||
|
||||
use kanidm_proto::v1::Entry as ProtoEntry;
|
||||
use kanidm_proto::v1::{
|
||||
AccountUnixExtend, AuthRequest, AuthResponse, AuthState as ProtoAuthState, CreateRequest,
|
||||
DeleteRequest, GroupUnixExtend, ModifyRequest, OperationError, SearchRequest,
|
||||
SetCredentialRequest, SingleStringRequest,
|
||||
};
|
||||
|
||||
use super::{to_tide_response, AppState, RequestExtensions};
|
||||
use async_std::task;
|
||||
|
||||
pub async fn create(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
// parse the req to a CreateRequest
|
||||
let msg: CreateRequest = req.body_json().await?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req.state().qe_w_ref.handle_create(uat, msg, eventid).await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn modify(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let msg: ModifyRequest = req.body_json().await?;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req.state().qe_w_ref.handle_modify(uat, msg, eventid).await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn delete(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let msg: DeleteRequest = req.body_json().await?;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req.state().qe_w_ref.handle_delete(uat, msg, eventid).await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn search(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let msg: SearchRequest = req.body_json().await?;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req.state().qe_r_ref.handle_search(uat, msg, eventid).await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn whoami(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
// New event, feed current auth data from the token to it.
|
||||
let res = req.state().qe_r_ref.handle_whoami(uat, eventid).await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
// =============== REST generics ========================
|
||||
|
||||
pub async fn json_rest_event_get(
|
||||
req: tide::Request<AppState>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
attrs: Option<Vec<String>>,
|
||||
) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsearch(uat, filter, attrs, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn json_rest_event_get_id(
|
||||
req: tide::Request<AppState>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
attrs: Option<Vec<String>>,
|
||||
) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let id = req.get_url_param("id")?;
|
||||
|
||||
let filter = Filter::join_parts_and(filter, filter_all!(f_id(id.as_str())));
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsearch(uat, filter, attrs, eventid)
|
||||
.await
|
||||
.map(|mut r| r.pop());
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn json_rest_event_delete_id(
|
||||
req: tide::Request<AppState>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let id = req.get_url_param("id")?;
|
||||
|
||||
let filter = Filter::join_parts_and(filter, filter_all!(f_id(id.as_str())));
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_internaldelete(uat, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn json_rest_event_get_id_attr(
|
||||
req: tide::Request<AppState>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> tide::Result {
|
||||
let id = req.get_url_param("id")?;
|
||||
let attr = req.get_url_param("attr")?;
|
||||
let uat = req.get_current_uat();
|
||||
|
||||
let filter = Filter::join_parts_and(filter, filter_all!(f_id(id.as_str())));
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let attrs = Some(vec![attr.clone()]);
|
||||
|
||||
let res: Result<Option<_>, _> = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsearch(uat, filter, attrs, eventid)
|
||||
.await
|
||||
.map(|mut event_result| event_result.pop().and_then(|mut e| e.attrs.remove(&attr)));
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn json_rest_event_post(
|
||||
mut req: tide::Request<AppState>,
|
||||
classes: Vec<String>,
|
||||
) -> tide::Result {
|
||||
debug_assert!(!classes.is_empty());
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
// Read the json from the wire.
|
||||
let uat = req.get_current_uat();
|
||||
let mut obj: ProtoEntry = req.body_json().await?;
|
||||
obj.attrs.insert("class".to_string(), classes);
|
||||
let msg = CreateRequest { entries: vec![obj] };
|
||||
|
||||
let res = req.state().qe_w_ref.handle_create(uat, msg, eventid).await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn json_rest_event_post_id_attr(
|
||||
mut req: tide::Request<AppState>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let attr = req.get_url_param("attr")?;
|
||||
let values: Vec<String> = req.body_json().await?;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_appendattribute(uat, uuid_or_name, attr, values, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn json_rest_event_put_id_attr(
|
||||
mut req: tide::Request<AppState>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let attr = req.get_url_param("attr")?;
|
||||
let values: Vec<String> = req.body_json().await?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_setattribute(uat, uuid_or_name, attr, values, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn json_rest_event_delete_id_attr(
|
||||
mut req: tide::Request<AppState>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
// Seperate for account_delete_id_radius
|
||||
attr: String,
|
||||
) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
// TODO #211: Attempt to get an option Vec<String> here?
|
||||
// It's probably better to focus on SCIM instead, it seems richer than this.
|
||||
let body = req.take_body();
|
||||
let values: Vec<String> = if body.is_empty().unwrap_or(true) {
|
||||
vec![]
|
||||
} else {
|
||||
// Must now be a valid list.
|
||||
body.into_json().await?
|
||||
};
|
||||
|
||||
if values.is_empty() {
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_purgeattribute(uat, uuid_or_name, attr, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
} else {
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_removeattributevalues(uat, uuid_or_name, attr, values, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn json_rest_event_credential_put(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let sac: SetCredentialRequest = req.body_json().await?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_credentialset(uat, uuid_or_name, sac, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
// Okay, so a put normally needs
|
||||
// * filter of what we are working on (id + class)
|
||||
// * a Map<String, Vec<String>> that we turn into a modlist.
|
||||
//
|
||||
// OR
|
||||
// * filter of what we are working on (id + class)
|
||||
// * a Vec<String> that we are changing
|
||||
// * the attr name (as a param to this in path)
|
||||
//
|
||||
// json_rest_event_put_id(path, req, state
|
||||
|
||||
pub async fn schema_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
// NOTE: This is filter_all, because from_internal_message will still do the alterations
|
||||
// needed to make it safe. This is needed because there may be aci's that block access
|
||||
// to the recycle/ts types in the filter, and we need the aci to only eval on this
|
||||
// part of the filter!
|
||||
let filter = filter_all!(f_or!([
|
||||
f_eq("class", PartialValue::new_class("attributetype")),
|
||||
f_eq("class", PartialValue::new_class("classtype"))
|
||||
]));
|
||||
json_rest_event_get(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn schema_attributetype_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("attributetype")));
|
||||
json_rest_event_get(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn schema_attributetype_get_id(req: tide::Request<AppState>) -> tide::Result {
|
||||
// These can't use get_id because they attribute name and class name aren't ... well name.
|
||||
let uat = req.get_current_uat();
|
||||
let id = req.get_url_param("id")?;
|
||||
|
||||
let filter = filter_all!(f_and!([
|
||||
f_eq("class", PartialValue::new_class("attributetype")),
|
||||
f_eq("attributename", PartialValue::new_iutf8(id.as_str()))
|
||||
]));
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsearch(uat, filter, None, eventid)
|
||||
.await
|
||||
.map(|mut r| r.pop());
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn schema_classtype_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("classtype")));
|
||||
json_rest_event_get(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn schema_classtype_get_id(req: tide::Request<AppState>) -> tide::Result {
|
||||
// These can't use get_id because they attribute name and class name aren't ... well name.
|
||||
let uat = req.get_current_uat();
|
||||
let id = req.get_url_param("id")?;
|
||||
|
||||
let filter = filter_all!(f_and!([
|
||||
f_eq("class", PartialValue::new_class("classtype")),
|
||||
f_eq("classname", PartialValue::new_iutf8(id.as_str()))
|
||||
]));
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsearch(uat, filter, None, eventid)
|
||||
.await
|
||||
.map(|mut r| r.pop());
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
// == person ==
|
||||
|
||||
pub async fn person_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("person")));
|
||||
json_rest_event_get(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn person_post(req: tide::Request<AppState>) -> tide::Result {
|
||||
let classes = vec!["account".to_string(), "object".to_string()];
|
||||
json_rest_event_post(req, classes).await
|
||||
}
|
||||
|
||||
pub async fn person_id_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("person")));
|
||||
json_rest_event_get_id(req, filter, None).await
|
||||
}
|
||||
|
||||
// == account ==
|
||||
|
||||
pub async fn account_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
json_rest_event_get(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn account_post(req: tide::Request<AppState>) -> tide::Result {
|
||||
let classes = vec!["account".to_string(), "object".to_string()];
|
||||
json_rest_event_post(req, classes).await
|
||||
}
|
||||
|
||||
pub async fn account_id_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
json_rest_event_get_id(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn account_id_get_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
json_rest_event_get_id_attr(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn account_id_post_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
json_rest_event_post_id_attr(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn account_id_delete_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
let attr = req.get_url_param("attr")?;
|
||||
json_rest_event_delete_id_attr(req, filter, attr).await
|
||||
}
|
||||
|
||||
pub async fn account_id_put_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
json_rest_event_put_id_attr(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn account_id_delete(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
json_rest_event_delete_id(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn account_put_id_credential_primary(req: tide::Request<AppState>) -> tide::Result {
|
||||
json_rest_event_credential_put(req).await
|
||||
}
|
||||
|
||||
pub async fn account_get_id_credential_status(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_idmcredentialstatus(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_get_backup_code(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_idmbackupcodeview(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
// Return a vec of str
|
||||
pub async fn account_get_id_ssh_pubkeys(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsshkeyread(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_post_id_ssh_pubkey(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let (tag, key): (String, String) = req.body_json().await?;
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
// Add a msg here
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_sshkeycreate(uat, uuid_or_name, tag, key, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_get_id_ssh_pubkey_tag(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let tag = req.get_url_param("tag")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsshkeytagread(uat, uuid_or_name, tag, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_delete_id_ssh_pubkey_tag(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let tag = req.get_url_param("tag")?;
|
||||
let attr = "ssh_publickey".to_string();
|
||||
let values = vec![tag];
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_removeattributevalues(uat, uuid_or_name, attr, values, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
// Get and return a single str
|
||||
pub async fn account_get_id_radius(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalradiusread(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_post_id_radius_regenerate(req: tide::Request<AppState>) -> tide::Result {
|
||||
// Need to to send the regen msg
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_regenerateradius(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_delete_id_radius(req: tide::Request<AppState>) -> tide::Result {
|
||||
let attr = "radius_secret".to_string();
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("account")));
|
||||
json_rest_event_delete_id_attr(req, filter, attr).await
|
||||
}
|
||||
|
||||
pub async fn account_get_id_radius_token(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalradiustokenread(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_post_id_person_extend(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_idmaccountpersonextend(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_post_id_unix(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let obj: AccountUnixExtend = req.body_json().await?;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_idmaccountunixextend(uat, uuid_or_name, obj, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_get_id_unix_token(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalunixusertokenread(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_post_id_unix_auth(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let obj: SingleStringRequest = req.body_json().await?;
|
||||
let cred = obj.value;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_idmaccountunixauth(uat, uuid_or_name, cred, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_put_id_unix_credential(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let obj: SingleStringRequest = req.body_json().await?;
|
||||
let cred = obj.value;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_idmaccountunixsetcred(uat, uuid_or_name, cred, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn account_delete_id_unix_credential(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let attr = "unix_password".to_string();
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("posixaccount")));
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_purgeattribute(uat, uuid_or_name, attr, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn group_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("group")));
|
||||
json_rest_event_get(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn group_post(req: tide::Request<AppState>) -> tide::Result {
|
||||
let classes = vec!["group".to_string(), "object".to_string()];
|
||||
json_rest_event_post(req, classes).await
|
||||
}
|
||||
|
||||
pub async fn group_id_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("group")));
|
||||
json_rest_event_get_id(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn group_id_get_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("group")));
|
||||
json_rest_event_get_id_attr(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn group_id_post_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("group")));
|
||||
json_rest_event_post_id_attr(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn group_id_delete_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("group")));
|
||||
let attr = req.get_url_param("attr")?;
|
||||
json_rest_event_delete_id_attr(req, filter, attr).await
|
||||
}
|
||||
|
||||
pub async fn group_id_put_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("group")));
|
||||
json_rest_event_put_id_attr(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn group_id_delete(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("group")));
|
||||
json_rest_event_delete_id(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn group_post_id_unix(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
let obj: GroupUnixExtend = req.body_json().await?;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_idmgroupunixextend(uat, uuid_or_name, obj, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn group_get_id_unix_token(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let uuid_or_name = req.get_url_param("id")?;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalunixgrouptokenread(uat, uuid_or_name, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn domain_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("domain_info")));
|
||||
json_rest_event_get(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn domain_id_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("domain_info")));
|
||||
json_rest_event_get_id(req, filter, None).await
|
||||
}
|
||||
|
||||
pub async fn domain_id_get_attr(
|
||||
req: tide::Request<AppState>,
|
||||
// (path, session, state): (Path<(String, String)>, Session, Data<AppState>),
|
||||
) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("domain_info")));
|
||||
json_rest_event_get_id_attr(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn domain_id_put_attr(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_eq("class", PartialValue::new_class("domain_info")));
|
||||
json_rest_event_put_id_attr(req, filter).await
|
||||
}
|
||||
|
||||
pub async fn recycle_bin_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let filter = filter_all!(f_pres("class"));
|
||||
let uat = req.get_current_uat();
|
||||
let attrs = None;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsearchrecycled(uat, filter, attrs, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn recycle_bin_id_get(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let id = req.get_url_param("id")?;
|
||||
let filter = filter_all!(f_id(id.as_str()));
|
||||
let attrs = None;
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let res = req
|
||||
.state()
|
||||
.qe_r_ref
|
||||
.handle_internalsearchrecycled(uat, filter, attrs, eventid)
|
||||
.await
|
||||
.map(|mut r| r.pop());
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn recycle_bin_revive_id_post(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let id = req.get_url_param("id")?;
|
||||
let filter = filter_all!(f_id(id.as_str()));
|
||||
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_reviverecycled(uat, filter, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn do_nothing(_req: tide::Request<AppState>) -> tide::Result {
|
||||
let mut res = tide::Response::new(200);
|
||||
res.set_body("did nothing");
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub async fn auth(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
// First, deal with some state management.
|
||||
// Do anything here first that's needed like getting the session details
|
||||
// out of the req cookie.
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
|
||||
let maybe_sessionid = req.get_current_auth_session_id();
|
||||
debug!("🍿 {:?}", maybe_sessionid);
|
||||
|
||||
let obj: AuthRequest = req.body_json().await.map_err(|e| {
|
||||
debug!("wat? {:?}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
let mut auth_session_id_tok = None;
|
||||
|
||||
// We probably need to know if we allocate the cookie, that this is a
|
||||
// new session, and in that case, anything *except* authrequest init is
|
||||
// invalid.
|
||||
let res: Result<AuthResponse, _> = match req
|
||||
.state()
|
||||
// This may change in the future ...
|
||||
.qe_r_ref
|
||||
.handle_auth(maybe_sessionid, obj, eventid)
|
||||
.await
|
||||
{
|
||||
// .and_then(|ar| {
|
||||
Ok(ar) => {
|
||||
let AuthResult {
|
||||
state,
|
||||
sessionid,
|
||||
delay,
|
||||
} = ar;
|
||||
// If there is a delay, honour it now.
|
||||
if let Some(delay_timer) = delay {
|
||||
task::sleep(delay_timer).await;
|
||||
}
|
||||
// Do some response/state management.
|
||||
match state {
|
||||
AuthState::Choose(allowed) => {
|
||||
debug!("🧩 -> AuthState::Choose");
|
||||
let msession = req.session_mut();
|
||||
|
||||
// Ensure the auth-session-id is set
|
||||
msession.remove("auth-session-id");
|
||||
msession
|
||||
.insert("auth-session-id", sessionid)
|
||||
.map_err(|_| OperationError::InvalidSessionState)
|
||||
.and_then(|_| {
|
||||
let kref = &req.state().bundy_handle;
|
||||
// Get the header token ready.
|
||||
kref.sign(&sessionid)
|
||||
.map(|t| {
|
||||
auth_session_id_tok = Some(t);
|
||||
})
|
||||
.map_err(|_| OperationError::InvalidSessionState)
|
||||
})
|
||||
.map(|_| ProtoAuthState::Choose(allowed))
|
||||
}
|
||||
AuthState::Continue(allowed) => {
|
||||
debug!("🧩 -> AuthState::Continue");
|
||||
let msession = req.session_mut();
|
||||
// Ensure the auth-session-id is set
|
||||
msession.remove("auth-session-id");
|
||||
msession
|
||||
.insert("auth-session-id", sessionid)
|
||||
.map_err(|_| OperationError::InvalidSessionState)
|
||||
.and_then(|_| {
|
||||
let kref = &req.state().bundy_handle;
|
||||
// Get the header token ready.
|
||||
kref.sign(&sessionid)
|
||||
.map(|t| {
|
||||
auth_session_id_tok = Some(t);
|
||||
})
|
||||
.map_err(|_| OperationError::InvalidSessionState)
|
||||
})
|
||||
.map(|_| ProtoAuthState::Continue(allowed))
|
||||
}
|
||||
AuthState::Success(token) => {
|
||||
debug!("🧩 -> AuthState::Success");
|
||||
// Remove the auth-session-id
|
||||
let msession = req.session_mut();
|
||||
msession.remove("auth-session-id");
|
||||
// Create a session cookie?
|
||||
msession.remove("bearer");
|
||||
msession
|
||||
.insert("bearer", token.clone())
|
||||
.map_err(|_| OperationError::InvalidSessionState)
|
||||
.map(|_| ProtoAuthState::Success(token))
|
||||
}
|
||||
AuthState::Denied(reason) => {
|
||||
debug!("🧩 -> AuthState::Denied");
|
||||
let msession = req.session_mut();
|
||||
// Remove the auth-session-id
|
||||
msession.remove("auth-session-id");
|
||||
Ok(ProtoAuthState::Denied(reason))
|
||||
}
|
||||
}
|
||||
.map(|state| AuthResponse { sessionid, state })
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
|
||||
to_tide_response(res, hvalue).map(|mut res| {
|
||||
// if the sessionid was injected into our cookie, set it in the
|
||||
// header too.
|
||||
if let Some(tok) = auth_session_id_tok {
|
||||
res.insert_header("X-KANIDM-AUTH-SESSION-ID", tok);
|
||||
}
|
||||
res
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn auth_valid(req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req.state().qe_r_ref.handle_auth_valid(uat, eventid).await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
pub async fn idm_account_set_password(mut req: tide::Request<AppState>) -> tide::Result {
|
||||
let uat = req.get_current_uat();
|
||||
let obj: SingleStringRequest = req.body_json().await?;
|
||||
let cleartext = obj.value;
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let res = req
|
||||
.state()
|
||||
.qe_w_ref
|
||||
.handle_idmaccountsetpassword(uat, cleartext, eventid)
|
||||
.await;
|
||||
to_tide_response(res, hvalue)
|
||||
}
|
||||
|
||||
// == Status
|
||||
|
||||
pub async fn status(req: tide::Request<AppState>) -> tide::Result {
|
||||
// We ignore the body in this req
|
||||
let (eventid, hvalue) = req.new_eventid();
|
||||
let r = req
|
||||
.state()
|
||||
.status_ref
|
||||
.handle_request(StatusRequestEvent { eventid })
|
||||
.await;
|
||||
let mut res = tide::Response::new(tide::StatusCode::Ok);
|
||||
res.insert_header("X-KANIDM-OPID", hvalue);
|
||||
res.set_body(tide::Body::from_json(&r)?);
|
||||
Ok(res)
|
||||
}
|
Loading…
Reference in a new issue