mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 04:27:02 +01:00
parent
307a66ea29
commit
cc79b2a205
|
@ -5,6 +5,7 @@ db_fs_type = "zfs"
|
|||
db_path = "/tmp/kanidm/kanidm.db"
|
||||
tls_chain = "/tmp/kanidm/chain.pem"
|
||||
tls_key = "/tmp/kanidm/key.pem"
|
||||
tls_client_ca = "/tmp/kanidm/client_ca"
|
||||
|
||||
# The log level of the server. May be one of info, debug, trace
|
||||
#
|
||||
|
|
|
@ -36,6 +36,7 @@ use kanidmd_lib::{
|
|||
},
|
||||
idm::server::{IdmServer, IdmServerTransaction},
|
||||
idm::serviceaccount::ListApiTokenEvent,
|
||||
idm::ClientAuthInfo,
|
||||
};
|
||||
|
||||
// ===========================================================
|
||||
|
@ -70,12 +71,12 @@ impl QueryServerReadV1 {
|
|||
#[instrument(
|
||||
level = "info",
|
||||
name = "search",
|
||||
skip(self, uat, req, eventid)
|
||||
skip_all,
|
||||
fields(uuid = ?eventid)
|
||||
)]
|
||||
pub async fn handle_search(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
req: SearchRequest,
|
||||
eventid: Uuid,
|
||||
) -> Result<SearchResponse, OperationError> {
|
||||
|
@ -83,7 +84,7 @@ impl QueryServerReadV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(?e, "Invalid identity");
|
||||
e
|
||||
|
@ -114,7 +115,7 @@ impl QueryServerReadV1 {
|
|||
sessionid: Option<Uuid>,
|
||||
req: AuthRequest,
|
||||
eventid: Uuid,
|
||||
ip_addr: IpAddr,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
) -> Result<AuthResult, OperationError> {
|
||||
// This is probably the first function that really implements logic
|
||||
// "on top" of the db server concept. In this case we check if
|
||||
|
@ -137,12 +138,10 @@ impl QueryServerReadV1 {
|
|||
// the session are enforced.
|
||||
idm_auth.expire_auth_sessions(ct).await;
|
||||
|
||||
let source = Source::Https(ip_addr);
|
||||
|
||||
// Generally things like auth denied are in Ok() msgs
|
||||
// so true errors should always trigger a rollback.
|
||||
let res = idm_auth
|
||||
.auth(&ae, ct, source)
|
||||
.auth(&ae, ct, client_auth_info)
|
||||
.await
|
||||
.and_then(|r| idm_auth.commit().map(|_| r));
|
||||
|
||||
|
@ -159,17 +158,16 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_reauth(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
issue: AuthIssueSession,
|
||||
eventid: Uuid,
|
||||
ip_addr: IpAddr,
|
||||
) -> Result<AuthResult, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idm_auth = self.idms.auth().await;
|
||||
security_info!("Begin reauth event");
|
||||
|
||||
let ident = idm_auth
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info.clone(), ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(?e, "Invalid identity");
|
||||
e
|
||||
|
@ -180,12 +178,10 @@ impl QueryServerReadV1 {
|
|||
// the session are enforced.
|
||||
idm_auth.expire_auth_sessions(ct).await;
|
||||
|
||||
let source = Source::Https(ip_addr);
|
||||
|
||||
// Generally things like auth denied are in Ok() msgs
|
||||
// so true errors should always trigger a rollback.
|
||||
let res = idm_auth
|
||||
.reauth_init(ident, issue, ct, source)
|
||||
.reauth_init(ident, issue, ct, client_auth_info)
|
||||
.await
|
||||
.and_then(|r| idm_auth.commit().map(|_| r));
|
||||
|
||||
|
@ -325,12 +321,12 @@ impl QueryServerReadV1 {
|
|||
#[instrument(
|
||||
level = "info",
|
||||
name = "whoami",
|
||||
skip(self, uat, eventid)
|
||||
skip_all,
|
||||
fields(uuid = ?eventid)
|
||||
)]
|
||||
pub async fn handle_whoami(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
eventid: Uuid,
|
||||
) -> Result<WhoamiResponse, OperationError> {
|
||||
// Begin a read
|
||||
|
@ -344,7 +340,7 @@ impl QueryServerReadV1 {
|
|||
// then move this to core.rs, and don't allow Option<UAT> to get
|
||||
// this far.
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(?e, "Invalid identity");
|
||||
e
|
||||
|
@ -371,12 +367,12 @@ impl QueryServerReadV1 {
|
|||
#[instrument(
|
||||
level = "info",
|
||||
name = "whoami_uat",
|
||||
skip(self, uat, eventid)
|
||||
skip_all,
|
||||
fields(uuid = ?eventid)
|
||||
)]
|
||||
pub async fn handle_whoami_uat(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
eventid: Uuid,
|
||||
) -> Result<UserAuthToken, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
|
@ -389,7 +385,7 @@ impl QueryServerReadV1 {
|
|||
// then move this to core.rs, and don't allow Option<UAT> to get
|
||||
// this far.
|
||||
idms_prox_read
|
||||
.validate_and_parse_token_to_uat(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_uat(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(?e, "Invalid identity");
|
||||
e
|
||||
|
@ -400,18 +396,18 @@ impl QueryServerReadV1 {
|
|||
/// pull an image so we can present it to the user
|
||||
pub async fn handle_oauth2_rs_image_get_image(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
rs: Filter<FilterInvalid>,
|
||||
) -> Result<ImageValue, OperationError> {
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ct = duration_from_epoch_now();
|
||||
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_get_image {:?}", uat);
|
||||
e
|
||||
})?;
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_get_image");
|
||||
e
|
||||
})?;
|
||||
let attrs = vec![Attribute::Image.to_string()];
|
||||
|
||||
let search = SearchEvent::from_internal_message(
|
||||
|
@ -442,7 +438,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_internalsearch(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
filter: Filter<FilterInvalid>,
|
||||
attrs: Option<Vec<String>>,
|
||||
eventid: Uuid,
|
||||
|
@ -450,7 +446,7 @@ impl QueryServerReadV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -485,7 +481,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_internalsearchrecycled(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
filter: Filter<FilterInvalid>,
|
||||
attrs: Option<Vec<String>>,
|
||||
eventid: Uuid,
|
||||
|
@ -494,7 +490,7 @@ impl QueryServerReadV1 {
|
|||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -529,14 +525,14 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_internalradiusread(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<Option<String>, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -589,7 +585,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_internalradiustokenread(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<RadiusAuthToken, OperationError> {
|
||||
|
@ -597,7 +593,7 @@ impl QueryServerReadV1 {
|
|||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -636,7 +632,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_internalunixusertokenread(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<UnixUserToken, OperationError> {
|
||||
|
@ -644,7 +640,7 @@ impl QueryServerReadV1 {
|
|||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -689,14 +685,14 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_internalunixgrouptokenread(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<UnixGroupToken, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -735,14 +731,14 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_internalsshkeyread(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<Vec<String>, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -797,7 +793,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_internalsshkeytagread(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
tag: String,
|
||||
eventid: Uuid,
|
||||
|
@ -805,7 +801,7 @@ impl QueryServerReadV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -862,14 +858,14 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_service_account_api_token_get(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<Vec<ApiToken>, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -894,14 +890,14 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_account_user_auth_token_get(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<Vec<UatStatus>, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -926,7 +922,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_user_identity_verification(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
eventid: Uuid,
|
||||
user_request: IdentifyUserRequest,
|
||||
other_id: String,
|
||||
|
@ -935,7 +931,7 @@ impl QueryServerReadV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -967,7 +963,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_idmaccountunixauth(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
cred: String,
|
||||
eventid: Uuid,
|
||||
|
@ -976,7 +972,7 @@ impl QueryServerReadV1 {
|
|||
let mut idm_auth = self.idms.auth().await;
|
||||
// resolve the id
|
||||
let ident = idm_auth
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -1017,7 +1013,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_idmcredentialstatus(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<CredentialStatus, OperationError> {
|
||||
|
@ -1025,7 +1021,7 @@ impl QueryServerReadV1 {
|
|||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -1063,7 +1059,7 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_idmbackupcodeview(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<BackupCodesView, OperationError> {
|
||||
|
@ -1071,7 +1067,7 @@ impl QueryServerReadV1 {
|
|||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -1296,14 +1292,14 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_oauth2_basic_secret_read(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
filter: Filter<FilterInvalid>,
|
||||
eventid: Uuid,
|
||||
) -> Result<Option<String>, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -1349,26 +1345,21 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_oauth2_authorise(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
auth_req: AuthorisationRequest,
|
||||
eventid: Uuid,
|
||||
) -> Result<AuthoriseResponse, Oauth2Error> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let (ident, uat) = idms_prox_read
|
||||
.validate_and_parse_uat(uat.as_deref(), ct)
|
||||
.and_then(|uat| {
|
||||
idms_prox_read
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.map(|ident| (ident, uat))
|
||||
})
|
||||
let ident = idms_prox_read
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
Oauth2Error::AuthenticationRequired
|
||||
})?;
|
||||
|
||||
// Now we can send to the idm server for authorisation checking.
|
||||
idms_prox_read.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
idms_prox_read.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
|
@ -1378,25 +1369,20 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_oauth2_authorise_reject(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
consent_req: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<Url, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let (ident, uat) = idms_prox_read
|
||||
.validate_and_parse_uat(uat.as_deref(), ct)
|
||||
.and_then(|uat| {
|
||||
idms_prox_read
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.map(|ident| (ident, uat))
|
||||
})
|
||||
let ident = idms_prox_read
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
})?;
|
||||
|
||||
idms_prox_read.check_oauth2_authorise_reject(&ident, &uat, &consent_req, ct)
|
||||
idms_prox_read.check_oauth2_authorise_reject(&ident, &consent_req, ct)
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
|
@ -1467,13 +1453,13 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_list_applinks(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
eventid: Uuid,
|
||||
) -> Result<Vec<AppLink>, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -1500,19 +1486,17 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_auth_valid(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
|
||||
// parse_token_to_ident
|
||||
idms_prox_read
|
||||
.validate_and_parse_uat(uat.as_deref(), ct)
|
||||
.and_then(|uat| idms_prox_read.process_uat_to_identity(&uat, ct))
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map(|_| ())
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid token: {:?}", e);
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
})
|
||||
}
|
||||
|
@ -1527,11 +1511,12 @@ impl QueryServerReadV1 {
|
|||
eventid: Uuid,
|
||||
protomsg: LdapMsg,
|
||||
uat: Option<LdapBoundToken>,
|
||||
ip_addr: IpAddr,
|
||||
) -> Option<LdapResponseState> {
|
||||
let res = match ServerOps::try_from(protomsg) {
|
||||
Ok(server_op) => self
|
||||
.ldap
|
||||
.do_op(&self.idms, server_op, uat, eventid)
|
||||
.do_op(&self.idms, server_op, uat, ip_addr, eventid)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
admin_error!("do_op failed -> {:?}", e);
|
||||
|
|
|
@ -16,7 +16,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_sync_account_token_generate(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
label: String,
|
||||
eventid: Uuid,
|
||||
|
@ -24,7 +24,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -56,14 +56,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_sync_account_token_destroy(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -89,14 +89,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_sync_account_finalise(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -124,14 +124,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_sync_account_terminate(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -159,7 +159,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_scim_sync_apply(
|
||||
&self,
|
||||
bearer: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
changes: ScimSyncRequest,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
|
@ -167,7 +167,7 @@ impl QueryServerWriteV1 {
|
|||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
let ident =
|
||||
idms_prox_write.validate_and_parse_sync_token_to_ident(bearer.as_deref(), ct)?;
|
||||
idms_prox_write.validate_sync_client_auth_info_to_ident(client_auth_info, ct)?;
|
||||
|
||||
let sse = ScimSyncUpdateEvent { ident };
|
||||
|
||||
|
@ -185,13 +185,13 @@ impl QueryServerReadV1 {
|
|||
)]
|
||||
pub async fn handle_scim_sync_status(
|
||||
&self,
|
||||
bearer: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
eventid: Uuid,
|
||||
) -> Result<ScimSyncState, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_read = self.idms.proxy_read().await;
|
||||
|
||||
let ident = idms_prox_read.validate_and_parse_sync_token_to_ident(bearer.as_deref(), ct)?;
|
||||
let ident = idms_prox_read.validate_sync_client_auth_info_to_ident(client_auth_info, ct)?;
|
||||
|
||||
idms_prox_read.scim_sync_get_state(&ident)
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ impl QueryServerWriteV1 {
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
async fn modify_from_parts(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: &str,
|
||||
proto_ml: &ProtoModifyList,
|
||||
filter: Filter<FilterInvalid>,
|
||||
|
@ -64,7 +64,7 @@ impl QueryServerWriteV1 {
|
|||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -103,7 +103,7 @@ impl QueryServerWriteV1 {
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
async fn modify_from_internal_parts(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: &str,
|
||||
ml: &ModifyList<ModifyInvalid>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
|
@ -112,7 +112,7 @@ impl QueryServerWriteV1 {
|
|||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -158,7 +158,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_create(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
req: CreateRequest,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
|
@ -166,7 +166,7 @@ impl QueryServerWriteV1 {
|
|||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -195,14 +195,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_modify(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
req: ModifyRequest,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -231,14 +231,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_delete(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
req: DeleteRequest,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -266,7 +266,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_internalpatch(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
filter: Filter<FilterInvalid>,
|
||||
update: ProtoEntry,
|
||||
eventid: Uuid,
|
||||
|
@ -275,7 +275,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -310,14 +310,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_internaldelete(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
filter: Filter<FilterInvalid>,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -345,14 +345,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_reviverecycled(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
filter: Filter<FilterInvalid>,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -380,14 +380,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_service_account_credential_generate(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<String, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -425,7 +425,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_service_account_api_token_generate(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
label: String,
|
||||
expiry: Option<OffsetDateTime>,
|
||||
|
@ -435,7 +435,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -469,7 +469,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_service_account_api_token_destroy(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
token_id: Uuid,
|
||||
eventid: Uuid,
|
||||
|
@ -477,7 +477,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -509,7 +509,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_account_user_auth_token_destroy(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
token_id: Uuid,
|
||||
eventid: Uuid,
|
||||
|
@ -517,7 +517,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -549,23 +549,22 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_logout(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
// We specifically need a uat here to assess the auth type!
|
||||
let (ident, uat) = idms_prox_write
|
||||
.validate_and_parse_uat(uat.as_deref(), ct)
|
||||
.and_then(|uat| {
|
||||
idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.map(|ident| (ident, uat))
|
||||
let ident = idms_prox_write
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
})?;
|
||||
|
||||
if uat.uuid == UUID_ANONYMOUS {
|
||||
info!("Ignoring request to logout anonymous session - these sessions are not recorded");
|
||||
if !ident.can_logout() {
|
||||
info!("Ignoring request to logout session - these sessions are not recorded");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -594,14 +593,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_idmcredentialupdate(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<(CUSessionToken, CUStatus), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -642,7 +641,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_idmcredentialupdateintent(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
ttl: Option<Duration>,
|
||||
eventid: Uuid,
|
||||
|
@ -650,7 +649,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -781,14 +780,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_service_account_into_person(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<(), OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -813,14 +812,14 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_regenerateradius(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<String, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -859,7 +858,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_purgeattribute(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
attr: String,
|
||||
filter: Filter<FilterInvalid>,
|
||||
|
@ -868,7 +867,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -911,7 +910,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_removeattributevalues(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
attr: String,
|
||||
values: Vec<String>,
|
||||
|
@ -921,7 +920,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -966,12 +965,12 @@ impl QueryServerWriteV1 {
|
|||
#[instrument(
|
||||
level = "info",
|
||||
name = "append_attribute",
|
||||
skip(self, uat, uuid_or_name, attr, values, filter, eventid)
|
||||
skip_all,
|
||||
fields(uuid = ?eventid)
|
||||
)]
|
||||
pub async fn handle_appendattribute(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
attr: String,
|
||||
values: Vec<String>,
|
||||
|
@ -986,19 +985,19 @@ impl QueryServerWriteV1 {
|
|||
.map(|v| ProtoModify::Present(attr.clone(), v))
|
||||
.collect(),
|
||||
);
|
||||
self.modify_from_parts(uat, &uuid_or_name, &proto_ml, filter)
|
||||
self.modify_from_parts(client_auth_info, &uuid_or_name, &proto_ml, filter)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
level = "info",
|
||||
name = "set_attribute",
|
||||
skip(self, uat, uuid_or_name, attr, values, filter, eventid)
|
||||
skip_all,
|
||||
fields(uuid = ?eventid)
|
||||
)]
|
||||
pub async fn handle_setattribute(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
attr: String,
|
||||
values: Vec<String>,
|
||||
|
@ -1016,7 +1015,7 @@ impl QueryServerWriteV1 {
|
|||
)
|
||||
.collect(),
|
||||
);
|
||||
self.modify_from_parts(uat, &uuid_or_name, &proto_ml, filter)
|
||||
self.modify_from_parts(client_auth_info, &uuid_or_name, &proto_ml, filter)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -1028,7 +1027,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_sshkeycreate(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
tag: &str,
|
||||
key: &str,
|
||||
|
@ -1041,7 +1040,7 @@ impl QueryServerWriteV1 {
|
|||
// than relying on the proto ones.
|
||||
let ml = ModifyList::new_append(Attribute::SshPublicKey, v_sk);
|
||||
|
||||
self.modify_from_internal_parts(uat, &uuid_or_name, &ml, filter)
|
||||
self.modify_from_internal_parts(client_auth_info, &uuid_or_name, &ml, filter)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -1053,7 +1052,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_idmaccountunixextend(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
ux: AccountUnixExtend,
|
||||
eventid: Uuid,
|
||||
|
@ -1088,19 +1087,19 @@ impl QueryServerWriteV1 {
|
|||
|
||||
let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
|
||||
|
||||
self.modify_from_internal_parts(uat, &uuid_or_name, &ml, filter)
|
||||
self.modify_from_internal_parts(client_auth_info, &uuid_or_name, &ml, filter)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(
|
||||
level = "info",
|
||||
name = "idm_group_unix_extend",
|
||||
skip(self, uat, uuid_or_name, gx, eventid)
|
||||
skip_all,
|
||||
fields(uuid = ?eventid)
|
||||
)]
|
||||
pub async fn handle_idmgroupunixextend(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
gx: GroupUnixExtend,
|
||||
eventid: Uuid,
|
||||
|
@ -1131,7 +1130,7 @@ impl QueryServerWriteV1 {
|
|||
|
||||
let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
|
||||
|
||||
self.modify_from_internal_parts(uat, &uuid_or_name, &ml, filter)
|
||||
self.modify_from_internal_parts(client_auth_info, &uuid_or_name, &ml, filter)
|
||||
.await
|
||||
}
|
||||
|
||||
|
@ -1142,7 +1141,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_idmaccountunixsetcred(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
uuid_or_name: String,
|
||||
cred: String,
|
||||
eventid: Uuid,
|
||||
|
@ -1150,7 +1149,7 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -1185,18 +1184,18 @@ impl QueryServerWriteV1 {
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn handle_oauth2_rs_image_delete(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
rs: Filter<FilterInvalid>,
|
||||
) -> Result<(), OperationError> {
|
||||
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
|
||||
let ct = duration_from_epoch_now();
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_delete {:?}", uat);
|
||||
e
|
||||
})?;
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_delete");
|
||||
e
|
||||
})?;
|
||||
let ml = ModifyList::new_purge(Attribute::Image);
|
||||
let mdf = match ModifyEvent::from_internal_parts(ident, &ml, &rs, &idms_prox_write.qs_write)
|
||||
{
|
||||
|
@ -1215,7 +1214,7 @@ impl QueryServerWriteV1 {
|
|||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn handle_oauth2_rs_image_update(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
rs: Filter<FilterInvalid>,
|
||||
image: ImageValue,
|
||||
) -> Result<(), OperationError> {
|
||||
|
@ -1223,9 +1222,9 @@ impl QueryServerWriteV1 {
|
|||
let ct = duration_from_epoch_now();
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_update {:?}", uat);
|
||||
admin_error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_update");
|
||||
e
|
||||
})?;
|
||||
|
||||
|
@ -1255,7 +1254,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_oauth2_scopemap_update(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
group: String,
|
||||
scopes: Vec<String>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
|
@ -1267,7 +1266,7 @@ impl QueryServerWriteV1 {
|
|||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -1316,7 +1315,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_oauth2_scopemap_delete(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
group: String,
|
||||
filter: Filter<FilterInvalid>,
|
||||
eventid: Uuid,
|
||||
|
@ -1325,7 +1324,7 @@ impl QueryServerWriteV1 {
|
|||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -1370,7 +1369,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_oauth2_sup_scopemap_update(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
group: String,
|
||||
scopes: Vec<String>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
|
@ -1382,7 +1381,7 @@ impl QueryServerWriteV1 {
|
|||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -1431,7 +1430,7 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_oauth2_sup_scopemap_delete(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
group: String,
|
||||
filter: Filter<FilterInvalid>,
|
||||
eventid: Uuid,
|
||||
|
@ -1440,7 +1439,7 @@ impl QueryServerWriteV1 {
|
|||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
|
@ -1487,26 +1486,22 @@ impl QueryServerWriteV1 {
|
|||
)]
|
||||
pub async fn handle_oauth2_authorise_permit(
|
||||
&self,
|
||||
uat: Option<String>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
consent_req: String,
|
||||
eventid: Uuid,
|
||||
) -> Result<AuthorisePermitSuccess, OperationError> {
|
||||
let ct = duration_from_epoch_now();
|
||||
let mut idms_prox_write = self.idms.proxy_write(ct).await;
|
||||
let (ident, uat) = idms_prox_write
|
||||
.validate_and_parse_uat(uat.as_deref(), ct)
|
||||
.and_then(|uat| {
|
||||
idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.map(|ident| (ident, uat))
|
||||
})
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
admin_error!(err = ?e, "Invalid identity");
|
||||
e
|
||||
})?;
|
||||
|
||||
idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_req, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_req, ct)
|
||||
.and_then(|r| idms_prox_write.commit().map(|()| r))
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ fn default_online_backup_versions() -> usize {
|
|||
pub struct TlsConfiguration {
|
||||
pub chain: String,
|
||||
pub key: String,
|
||||
pub client_ca: Option<String>,
|
||||
}
|
||||
|
||||
/// This is the Server Configuration as read from `server.toml`.
|
||||
|
@ -100,6 +101,9 @@ pub struct ServerConfig {
|
|||
/// The file path to the TLS Private Key
|
||||
pub tls_key: Option<String>,
|
||||
|
||||
/// The directory path of the client ca and crl dir.
|
||||
pub tls_client_ca: Option<String>,
|
||||
|
||||
/// The listener address for the HTTPS server.
|
||||
///
|
||||
/// eg. `[::]:8443` or `127.0.0.1:8443`. Defaults to [kanidm_proto::constants::DEFAULT_SERVER_ADDRESS]
|
||||
|
@ -213,6 +217,9 @@ impl ServerConfig {
|
|||
"TLS_KEY" => {
|
||||
self.tls_key = Some(value.to_string());
|
||||
}
|
||||
"TLS_CLIENT_CA" => {
|
||||
self.tls_client_ca = Some(value.to_string());
|
||||
}
|
||||
"BINDADDRESS" => {
|
||||
self.bindaddress = Some(value.to_string());
|
||||
}
|
||||
|
@ -571,7 +578,7 @@ impl Configuration {
|
|||
pub fn update_config_for_server_mode(&mut self, sconfig: &ServerConfig) {
|
||||
#[cfg(any(test, debug_assertions))]
|
||||
debug!("update_config_for_server_mode {:?}", sconfig);
|
||||
self.update_tls(&sconfig.tls_chain, &sconfig.tls_key);
|
||||
self.update_tls(&sconfig.tls_chain, &sconfig.tls_key, &sconfig.tls_client_ca);
|
||||
self.update_bind(&sconfig.bindaddress);
|
||||
self.update_ldapbind(&sconfig.ldapbindaddress);
|
||||
self.update_online_backup(&sconfig.online_backup);
|
||||
|
@ -632,13 +639,23 @@ impl Configuration {
|
|||
self.repl_config = repl_config;
|
||||
}
|
||||
|
||||
pub fn update_tls(&mut self, chain: &Option<String>, key: &Option<String>) {
|
||||
pub fn update_tls(
|
||||
&mut self,
|
||||
chain: &Option<String>,
|
||||
key: &Option<String>,
|
||||
client_ca: &Option<String>,
|
||||
) {
|
||||
match (chain, key) {
|
||||
(None, None) => {}
|
||||
(Some(chainp), Some(keyp)) => {
|
||||
let chain = chainp.to_string();
|
||||
let key = keyp.to_string();
|
||||
self.tls_config = Some(TlsConfiguration { chain, key })
|
||||
let client_ca = client_ca.clone();
|
||||
self.tls_config = Some(TlsConfiguration {
|
||||
chain,
|
||||
key,
|
||||
client_ca,
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
eprintln!("ERROR: Invalid TLS configuration - must provide chain and key!");
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
use axum::{
|
||||
async_trait,
|
||||
extract::{ConnectInfo, FromRequestParts},
|
||||
http::{header::HeaderName, request::Parts, StatusCode},
|
||||
extract::connect_info::{ConnectInfo, Connected},
|
||||
extract::FromRequestParts,
|
||||
http::{
|
||||
header::HeaderName, header::AUTHORIZATION as AUTHORISATION, request::Parts, StatusCode,
|
||||
},
|
||||
RequestPartsExt,
|
||||
};
|
||||
use hyper::server::conn::AddrStream;
|
||||
use kanidm_proto::constants::X_FORWARDED_FOR;
|
||||
use kanidmd_lib::prelude::{ClientAuthInfo, ClientCertInfo, Source};
|
||||
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
|
||||
|
@ -24,9 +29,23 @@ impl FromRequestParts<ServerState> for TrustedClientIp {
|
|||
parts: &mut Parts,
|
||||
state: &ServerState,
|
||||
) -> Result<Self, Self::Rejection> {
|
||||
if state.trust_x_forward_for {
|
||||
let ConnectInfo(ClientConnInfo {
|
||||
addr,
|
||||
client_cert: _,
|
||||
}) = parts
|
||||
.extract::<ConnectInfo<ClientConnInfo>>()
|
||||
.await
|
||||
.map_err(|_| {
|
||||
error!("Connect info contains invalid data");
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"connect info contains invalid data",
|
||||
)
|
||||
})?;
|
||||
|
||||
let ip_addr = if state.trust_x_forward_for {
|
||||
if let Some(x_forward_for) = parts.headers.get(X_FORWARDED_FOR_HEADER) {
|
||||
// X forward for may be comma separate.
|
||||
// X forward for may be comma separated.
|
||||
let first = x_forward_for
|
||||
.to_str()
|
||||
.map(|s|
|
||||
|
@ -39,41 +58,116 @@ impl FromRequestParts<ServerState> for TrustedClientIp {
|
|||
)
|
||||
})?;
|
||||
|
||||
first.parse::<IpAddr>().map(TrustedClientIp).map_err(|_| {
|
||||
first.parse::<IpAddr>().map_err(|_| {
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"X-Forwarded-For contains invalid ip addr",
|
||||
)
|
||||
})
|
||||
})?
|
||||
} else {
|
||||
let ConnectInfo(addr) =
|
||||
parts
|
||||
.extract::<ConnectInfo<SocketAddr>>()
|
||||
.await
|
||||
.map_err(|_| {
|
||||
error!("Connect info contains invalid IP address");
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"connect info contains invalid IP address",
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(TrustedClientIp(addr.ip()))
|
||||
addr.ip()
|
||||
}
|
||||
} else {
|
||||
let ConnectInfo(addr) =
|
||||
parts
|
||||
.extract::<ConnectInfo<SocketAddr>>()
|
||||
.await
|
||||
addr.ip()
|
||||
};
|
||||
|
||||
Ok(TrustedClientIp(ip_addr))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VerifiedClientInformation(pub ClientAuthInfo);
|
||||
|
||||
#[async_trait]
|
||||
impl FromRequestParts<ServerState> for VerifiedClientInformation {
|
||||
type Rejection = (StatusCode, &'static str);
|
||||
|
||||
#[instrument(level = "debug", skip(state))]
|
||||
async fn from_request_parts(
|
||||
parts: &mut Parts,
|
||||
state: &ServerState,
|
||||
) -> Result<Self, Self::Rejection> {
|
||||
let ConnectInfo(ClientConnInfo { addr, client_cert }) = parts
|
||||
.extract::<ConnectInfo<ClientConnInfo>>()
|
||||
.await
|
||||
.map_err(|_| {
|
||||
error!("Connect info contains invalid data");
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"connect info contains invalid data",
|
||||
)
|
||||
})?;
|
||||
|
||||
let ip_addr = if state.trust_x_forward_for {
|
||||
if let Some(x_forward_for) = parts.headers.get(X_FORWARDED_FOR_HEADER) {
|
||||
// X forward for may be comma separated.
|
||||
let first = x_forward_for
|
||||
.to_str()
|
||||
.map(|s|
|
||||
// Split on an optional comma, return the first result.
|
||||
s.split(',').next().unwrap_or(s))
|
||||
.map_err(|_| {
|
||||
error!("Connect info contains invalid IP address");
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"connect info contains invalid IP address",
|
||||
"X-Forwarded-For contains invalid data",
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(TrustedClientIp(addr.ip()))
|
||||
first.parse::<IpAddr>().map_err(|_| {
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"X-Forwarded-For contains invalid ip addr",
|
||||
)
|
||||
})?
|
||||
} else {
|
||||
addr.ip()
|
||||
}
|
||||
} else {
|
||||
addr.ip()
|
||||
};
|
||||
|
||||
let bearer_token = if let Some(header) = parts.headers.get(AUTHORISATION) {
|
||||
header
|
||||
.to_str()
|
||||
.map_err(|err| {
|
||||
warn!(?err, "Invalid bearer token, ignoring");
|
||||
})
|
||||
.ok()
|
||||
.and_then(|s| s.split_once(' '))
|
||||
.map(|(_, s)| s.to_string())
|
||||
.or_else(|| {
|
||||
warn!("bearer token format invalid, ignoring");
|
||||
None
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(VerifiedClientInformation(ClientAuthInfo {
|
||||
source: Source::Https(ip_addr),
|
||||
bearer_token,
|
||||
client_cert,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClientConnInfo {
|
||||
pub addr: SocketAddr,
|
||||
// Only set if the certificate is VALID
|
||||
pub client_cert: Option<ClientCertInfo>,
|
||||
}
|
||||
|
||||
impl Connected<ClientConnInfo> for ClientConnInfo {
|
||||
fn connect_info(target: ClientConnInfo) -> Self {
|
||||
target
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Connected<&'a AddrStream> for ClientConnInfo {
|
||||
fn connect_info(target: &'a AddrStream) -> Self {
|
||||
ClientConnInfo {
|
||||
addr: target.remote_addr(),
|
||||
client_cert: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use axum::{
|
||||
headers::{authorization::Bearer, Authorization},
|
||||
http::{HeaderValue, Request},
|
||||
middleware::Next,
|
||||
response::Response,
|
||||
TypedHeader,
|
||||
};
|
||||
use kanidm_proto::constants::{KOPID, KVERSION};
|
||||
use uuid::Uuid;
|
||||
|
@ -24,18 +22,9 @@ pub async fn version_middleware<B>(request: Request<B>, next: Next<B>) -> Respon
|
|||
response
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// For holding onto the event ID and other handy request-based things
|
||||
pub struct KOpId {
|
||||
/// The event correlation ID
|
||||
pub eventid: Uuid,
|
||||
/// The User Access Token, if present
|
||||
pub uat: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(any(test, debug_assertions))]
|
||||
/// This is a debug middleware to ensure that /v1/ endpoints only return JSON
|
||||
#[instrument(name = "are_we_json_yet", skip_all)]
|
||||
#[instrument(level = "debug", name = "are_we_json_yet", skip_all)]
|
||||
pub async fn are_we_json_yet<B>(request: Request<B>, next: Next<B>) -> Response {
|
||||
let uri = request.uri().path().to_string();
|
||||
|
||||
|
@ -55,21 +44,21 @@ pub async fn are_we_json_yet<B>(request: Request<B>, next: Next<B>) -> Response
|
|||
response
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// For holding onto the event ID and other handy request-based things
|
||||
pub struct KOpId {
|
||||
/// The event correlation ID
|
||||
pub eventid: Uuid,
|
||||
}
|
||||
|
||||
/// This runs at the start of the request, adding an extension with `KOpId` which has useful things inside it.
|
||||
#[instrument(name = "kopid_middleware", skip_all, level = "DEBUG")]
|
||||
pub async fn kopid_middleware<B>(
|
||||
auth: Option<TypedHeader<Authorization<Bearer>>>,
|
||||
mut request: Request<B>,
|
||||
next: Next<B>,
|
||||
) -> Response {
|
||||
#[instrument(level = "debug", name = "kopid_middleware", skip_all)]
|
||||
pub async fn kopid_middleware<B>(mut request: Request<B>, next: Next<B>) -> Response {
|
||||
// generate the event ID
|
||||
let eventid = sketching::tracing_forest::id();
|
||||
|
||||
// get the bearer token from the headers if present.
|
||||
let uat = auth.map(|bearer| bearer.token().to_string());
|
||||
|
||||
// insert the extension so we can pull it out later
|
||||
request.extensions_mut().insert(KOpId { eventid, uat });
|
||||
request.extensions_mut().insert(KOpId { eventid });
|
||||
let mut response = next.run(request).await;
|
||||
|
||||
// This conversion *should never* fail. If it does, rather than panic, we warn and
|
||||
|
|
|
@ -14,11 +14,12 @@ mod v1;
|
|||
mod v1_oauth2;
|
||||
mod v1_scim;
|
||||
|
||||
use self::extractors::ClientConnInfo;
|
||||
use self::javascript::*;
|
||||
use crate::actors::v1_read::QueryServerReadV1;
|
||||
use crate::actors::v1_write::QueryServerWriteV1;
|
||||
use crate::config::{Configuration, ServerRole, TlsConfiguration};
|
||||
use axum::extract::connect_info::{IntoMakeServiceWithConnectInfo, ResponseFuture};
|
||||
use axum::extract::connect_info::IntoMakeServiceWithConnectInfo;
|
||||
use axum::http::{HeaderMap, HeaderValue};
|
||||
use axum::middleware::{from_fn, from_fn_with_state};
|
||||
use axum::response::Redirect;
|
||||
|
@ -31,15 +32,19 @@ use hashbrown::HashMap;
|
|||
use hyper::server::accept::Accept;
|
||||
use hyper::server::conn::{AddrStream, Http};
|
||||
use kanidm_proto::constants::KSESSIONID;
|
||||
use kanidmd_lib::idm::ClientCertInfo;
|
||||
use kanidmd_lib::status::StatusActor;
|
||||
use openssl::ssl::{Ssl, SslAcceptor, SslFiletype, SslMethod};
|
||||
use openssl::nid;
|
||||
use openssl::ssl::{Ssl, SslAcceptor, SslFiletype, SslMethod, SslSessionCacheMode, SslVerifyMode};
|
||||
use openssl::x509::X509;
|
||||
use sketching::*;
|
||||
use tokio_openssl::SslStream;
|
||||
|
||||
use futures_util::future::poll_fn;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
use std::io::ErrorKind;
|
||||
use std::fs;
|
||||
use std::io::{ErrorKind, Read};
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
@ -311,7 +316,7 @@ pub async fn create_https_server(
|
|||
.layer(trace_layer)
|
||||
.with_state(state)
|
||||
// the connect_info bit here lets us pick up the remote address of the client
|
||||
.into_make_service_with_connect_info::<SocketAddr>();
|
||||
.into_make_service_with_connect_info::<ClientConnInfo>();
|
||||
|
||||
let addr = SocketAddr::from_str(&config.address).map_err(|err| {
|
||||
error!(
|
||||
|
@ -361,10 +366,10 @@ pub async fn create_https_server(
|
|||
async fn server_loop(
|
||||
tls_param: TlsConfiguration,
|
||||
listener: TcpListener,
|
||||
app: IntoMakeServiceWithConnectInfo<Router, SocketAddr>,
|
||||
app: IntoMakeServiceWithConnectInfo<Router, ClientConnInfo>,
|
||||
) -> Result<(), std::io::Error> {
|
||||
let mut tls_builder = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls())?;
|
||||
let mut app = app;
|
||||
|
||||
tls_builder
|
||||
.set_certificate_chain_file(tls_param.chain.clone())
|
||||
.map_err(|err| {
|
||||
|
@ -373,6 +378,7 @@ async fn server_loop(
|
|||
format!("Failed to create TLS listener: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
|
||||
tls_builder
|
||||
.set_private_key_file(tls_param.key.clone(), SslFiletype::PEM)
|
||||
.map_err(|err| {
|
||||
|
@ -381,13 +387,113 @@ async fn server_loop(
|
|||
format!("Failed to create TLS listener: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
|
||||
tls_builder.check_private_key().map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to create TLS listener: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
let acceptor = tls_builder.build();
|
||||
|
||||
// If configured, setup TLS client authentication.
|
||||
if let Some(client_ca) = tls_param.client_ca.as_ref() {
|
||||
debug!("Configuring client certificates from {}", client_ca);
|
||||
|
||||
let verify = SslVerifyMode::PEER;
|
||||
// In future we may add a "require mTLS option" which would necesitate this.
|
||||
// verify.insert(SslVerifyMode::FAIL_IF_NO_PEER_CERT);
|
||||
tls_builder.set_verify(verify);
|
||||
|
||||
// When client certs are available, we disable the TLS session cache.
|
||||
// This is so that when the smartcard is *removed* on the client, it forces
|
||||
// the client session to immediately expire.
|
||||
//
|
||||
// https://stackoverflow.com/questions/12393711/session-disconnect-the-client-after-smart-card-is-removed
|
||||
//
|
||||
// Alternately, on logout we need to trigger https://docs.rs/openssl/latest/openssl/ssl/struct.Ssl.html#method.set_ssl_context
|
||||
// with https://docs.rs/openssl/latest/openssl/ssl/struct.Ssl.html#method.ssl_context +
|
||||
// https://docs.rs/openssl/latest/openssl/ssl/struct.SslContextRef.html#method.remove_session
|
||||
//
|
||||
// Or we lower session time outs etc.
|
||||
tls_builder.set_session_cache_mode(SslSessionCacheMode::OFF);
|
||||
|
||||
let read_dir = fs::read_dir(client_ca).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to create TLS listener: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
|
||||
for cert_dir_ent in read_dir.filter_map(|item| item.ok()).filter(|item| {
|
||||
item.file_name()
|
||||
.to_str()
|
||||
// Hashed certs end in .0
|
||||
// Hsahed crls are .r0
|
||||
.map(|fname| fname.ends_with(".0"))
|
||||
.unwrap_or_default()
|
||||
}) {
|
||||
let mut cert_pem = String::new();
|
||||
fs::File::open(cert_dir_ent.path())
|
||||
.and_then(|mut file| file.read_to_string(&mut cert_pem))
|
||||
.map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to create TLS listener: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
|
||||
let cert = X509::from_pem(cert_pem.as_bytes()).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to create TLS listener: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
|
||||
let cert_store = tls_builder.cert_store_mut();
|
||||
cert_store.add_cert(cert.clone()).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to create TLS listener: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
// This tells the client what CA's they should use. It DOES NOT
|
||||
// verify them. That's the job of the cert store above!
|
||||
tls_builder.add_client_ca(&cert).map_err(|err| {
|
||||
std::io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Failed to create TLS listener: {:?}", err),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
// TODO: Build our own CRL map HERE!
|
||||
|
||||
// Allow dumping client cert chains for dev debugging
|
||||
// In the case this is status=false, should we be dumping these anyway?
|
||||
if enabled!(tracing::Level::TRACE) {
|
||||
tls_builder.set_verify_callback(verify, |status, x509store| {
|
||||
if let Some(current_cert) = x509store.current_cert() {
|
||||
let cert_text_bytes = current_cert.to_text().unwrap_or_default();
|
||||
let cert_text = String::from_utf8_lossy(cert_text_bytes.as_slice());
|
||||
tracing::warn!(client_cert = %cert_text);
|
||||
};
|
||||
|
||||
if let Some(chain) = x509store.chain() {
|
||||
for cert in chain.iter() {
|
||||
let cert_text_bytes = cert.to_text().unwrap_or_default();
|
||||
let cert_text = String::from_utf8_lossy(cert_text_bytes.as_slice());
|
||||
tracing::warn!(chain_cert = %cert_text);
|
||||
}
|
||||
}
|
||||
|
||||
status
|
||||
});
|
||||
}
|
||||
|
||||
// End tls_client setup
|
||||
}
|
||||
|
||||
let tls_acceptor = tls_builder.build();
|
||||
|
||||
let protocol = Arc::new(Http::new());
|
||||
let mut listener =
|
||||
|
@ -399,9 +505,12 @@ async fn server_loop(
|
|||
})?;
|
||||
loop {
|
||||
if let Some(Ok(stream)) = poll_fn(|cx| Pin::new(&mut listener).poll_accept(cx)).await {
|
||||
let acceptor = acceptor.clone();
|
||||
let svc = tower::MakeService::make_service(&mut app, &stream);
|
||||
tokio::spawn(handle_conn(acceptor, stream, svc, protocol.clone()));
|
||||
let tls_acceptor = tls_acceptor.clone();
|
||||
let app = app.clone();
|
||||
|
||||
// let svc = tower::MakeService::make_service(&mut app, &stream);
|
||||
// tokio::spawn(handle_conn(tls_acceptor, stream, svc, protocol.clone()));
|
||||
tokio::spawn(handle_conn(tls_acceptor, stream, app, protocol.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -410,7 +519,8 @@ async fn server_loop(
|
|||
pub(crate) async fn handle_conn(
|
||||
acceptor: SslAcceptor,
|
||||
stream: AddrStream,
|
||||
svc: ResponseFuture<Router, SocketAddr>,
|
||||
// svc: ResponseFuture<Router, ClientConnInfo>,
|
||||
mut app: IntoMakeServiceWithConnectInfo<Router, ClientConnInfo>,
|
||||
protocol: Arc<Http>,
|
||||
) -> Result<(), std::io::Error> {
|
||||
let ssl = Ssl::new(acceptor.context()).map_err(|e| {
|
||||
|
@ -418,6 +528,8 @@ pub(crate) async fn handle_conn(
|
|||
std::io::Error::from(ErrorKind::ConnectionAborted)
|
||||
})?;
|
||||
|
||||
let addr = stream.remote_addr();
|
||||
|
||||
let mut tls_stream = SslStream::new(ssl, stream).map_err(|e| {
|
||||
error!("Failed to create TLS stream: {:?}", e);
|
||||
std::io::Error::from(ErrorKind::ConnectionAborted)
|
||||
|
@ -425,6 +537,39 @@ pub(crate) async fn handle_conn(
|
|||
|
||||
match SslStream::accept(Pin::new(&mut tls_stream)).await {
|
||||
Ok(_) => {
|
||||
// Process the client cert (if any)
|
||||
let client_cert = if let Some(peer_cert) = tls_stream.ssl().peer_certificate() {
|
||||
// TODO: This is where we should be checking the CRL!!!
|
||||
|
||||
let subject_key_id = peer_cert
|
||||
.subject_key_id()
|
||||
.map(|ski| ski.as_slice().to_vec());
|
||||
|
||||
let cn = if let Some(cn) = peer_cert
|
||||
.subject_name()
|
||||
.entries_by_nid(nid::Nid::COMMONNAME)
|
||||
.next()
|
||||
{
|
||||
String::from_utf8(cn.data().as_slice().to_vec())
|
||||
.map_err(|err| {
|
||||
warn!(?err, "client certificate CN contains invalid utf-8 - the CN will be ignored!");
|
||||
})
|
||||
.ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Some(ClientCertInfo { subject_key_id, cn })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let client_conn_info = ClientConnInfo { addr, client_cert };
|
||||
|
||||
debug!(?client_conn_info);
|
||||
|
||||
let svc = tower::MakeService::make_service(&mut app, client_conn_info);
|
||||
|
||||
let svc = svc.await.map_err(|e| {
|
||||
error!("Failed to build HTTP response: {:?}", e);
|
||||
std::io::Error::from(ErrorKind::Other)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::errors::WebError;
|
||||
use super::middleware::KOpId;
|
||||
use super::ServerState;
|
||||
use crate::https::extractors::VerifiedClientInformation;
|
||||
use axum::extract::{Path, Query, State};
|
||||
use axum::http::header::{
|
||||
ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_ORIGIN, AUTHORIZATION, CONTENT_TYPE,
|
||||
|
@ -93,13 +94,13 @@ pub(crate) fn oauth2_id(rs_name: &str) -> Filter<FilterInvalid> {
|
|||
///
|
||||
pub(crate) async fn oauth2_image_get(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path(rs_name): Path<String>,
|
||||
) -> Response {
|
||||
let rs_filter = oauth2_id(&rs_name);
|
||||
let res = state
|
||||
.qe_r_ref
|
||||
.handle_oauth2_rs_image_get_image(kopid.uat, rs_filter)
|
||||
.handle_oauth2_rs_image_get_image(client_auth_info, rs_filter)
|
||||
.await;
|
||||
|
||||
match res {
|
||||
|
@ -186,9 +187,10 @@ pub(crate) async fn oauth2_image_get(
|
|||
pub async fn oauth2_authorise_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(auth_req): Json<AuthorisationRequest>,
|
||||
) -> impl IntoResponse {
|
||||
let mut res = oauth2_authorise(state, auth_req, kopid)
|
||||
let mut res = oauth2_authorise(state, auth_req, kopid, client_auth_info)
|
||||
.await
|
||||
.into_response();
|
||||
if res.status() == StatusCode::FOUND {
|
||||
|
@ -202,20 +204,22 @@ pub async fn oauth2_authorise_post(
|
|||
pub async fn oauth2_authorise_get(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Query(auth_req): Query<AuthorisationRequest>,
|
||||
) -> impl IntoResponse {
|
||||
// Start the oauth2 authorisation flow to present to the user.
|
||||
oauth2_authorise(state, auth_req, kopid).await
|
||||
oauth2_authorise(state, auth_req, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
async fn oauth2_authorise(
|
||||
state: ServerState,
|
||||
auth_req: AuthorisationRequest,
|
||||
kopid: KOpId,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
) -> impl IntoResponse {
|
||||
let res: Result<AuthoriseResponse, Oauth2Error> = state
|
||||
.qe_r_ref
|
||||
.handle_oauth2_authorise(kopid.uat.clone(), auth_req, kopid.eventid)
|
||||
.handle_oauth2_authorise(client_auth_info, auth_req, kopid.eventid)
|
||||
.await;
|
||||
|
||||
match res {
|
||||
|
@ -321,9 +325,10 @@ async fn oauth2_authorise(
|
|||
pub async fn oauth2_authorise_permit_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(consent_req): Json<String>,
|
||||
) -> impl IntoResponse {
|
||||
let mut res = oauth2_authorise_permit(state, consent_req, kopid)
|
||||
let mut res = oauth2_authorise_permit(state, consent_req, kopid, client_auth_info)
|
||||
.await
|
||||
.into_response();
|
||||
if res.status() == StatusCode::FOUND {
|
||||
|
@ -342,19 +347,21 @@ pub async fn oauth2_authorise_permit_get(
|
|||
State(state): State<ServerState>,
|
||||
Query(token): Query<ConsentRequestData>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> impl IntoResponse {
|
||||
// When this is called, this indicates consent to proceed from the user.
|
||||
oauth2_authorise_permit(state, token.token, kopid).await
|
||||
oauth2_authorise_permit(state, token.token, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
async fn oauth2_authorise_permit(
|
||||
state: ServerState,
|
||||
consent_req: String,
|
||||
kopid: KOpId,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
) -> impl IntoResponse {
|
||||
let res = state
|
||||
.qe_w_ref
|
||||
.handle_oauth2_authorise_permit(kopid.uat, consent_req, kopid.eventid)
|
||||
.handle_oauth2_authorise_permit(client_auth_info, consent_req, kopid.eventid)
|
||||
.await;
|
||||
|
||||
match res {
|
||||
|
@ -404,17 +411,19 @@ async fn oauth2_authorise_permit(
|
|||
pub async fn oauth2_authorise_reject_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Form(consent_req): Form<ConsentRequestData>,
|
||||
) -> Response<Body> {
|
||||
oauth2_authorise_reject(state, consent_req.token, kopid).await
|
||||
oauth2_authorise_reject(state, consent_req.token, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
pub async fn oauth2_authorise_reject_get(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Query(consent_req): Query<ConsentRequestData>,
|
||||
) -> Response<Body> {
|
||||
oauth2_authorise_reject(state, consent_req.token, kopid).await
|
||||
oauth2_authorise_reject(state, consent_req.token, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
// // https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1
|
||||
|
@ -424,13 +433,14 @@ async fn oauth2_authorise_reject(
|
|||
state: ServerState,
|
||||
consent_req: String,
|
||||
kopid: KOpId,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
) -> Response<Body> {
|
||||
// Need to go back to the redir_uri
|
||||
// For this, we'll need to lookup where to go.
|
||||
|
||||
let res = state
|
||||
.qe_r_ref
|
||||
.handle_oauth2_authorise_reject(kopid.uat, consent_req, kopid.eventid)
|
||||
.handle_oauth2_authorise_reject(client_auth_info, consent_req, kopid.eventid)
|
||||
.await;
|
||||
|
||||
match res {
|
||||
|
@ -525,9 +535,10 @@ pub async fn oauth2_openid_userinfo_get(
|
|||
State(state): State<ServerState>,
|
||||
Path(client_id): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> Result<Json<OidcToken>, HTTPOauth2Error> {
|
||||
// The token we want to inspect is in the authorisation header.
|
||||
let client_token = match kopid.uat {
|
||||
let client_token = match client_auth_info.bearer_token {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
error!("Bearer Authentication Not Provided");
|
||||
|
@ -564,10 +575,11 @@ pub async fn oauth2_openid_publickey_get(
|
|||
pub async fn oauth2_token_introspect_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
headers: HeaderMap,
|
||||
Form(intr_req): Form<AccessTokenIntrospectRequest>,
|
||||
) -> impl IntoResponse {
|
||||
let client_authz = match kopid.uat {
|
||||
let client_authz = match client_auth_info.bearer_token {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
error!("Bearer Authentication Not Provided, trying basic");
|
||||
|
@ -652,10 +664,11 @@ pub async fn oauth2_token_introspect_post(
|
|||
pub async fn oauth2_token_revoke_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Form(intr_req): Form<TokenRevokeRequest>,
|
||||
) -> impl IntoResponse {
|
||||
// TODO: we should handle the session-based auth bit here I think maybe possibly there's no tests
|
||||
let client_authz = match kopid.uat {
|
||||
let client_authz = match client_auth_info.bearer_token {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return (
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -5,6 +5,7 @@ use super::oauth2::oauth2_id;
|
|||
use super::v1::{json_rest_event_get, json_rest_event_post};
|
||||
use super::ServerState;
|
||||
|
||||
use crate::https::extractors::VerifiedClientInformation;
|
||||
use axum::extract::{Path, State};
|
||||
use axum::{Extension, Json};
|
||||
use kanidm_proto::internal::{ImageType, ImageValue};
|
||||
|
@ -27,12 +28,13 @@ use sketching::admin_error;
|
|||
pub(crate) async fn oauth2_get(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> Result<Json<Vec<ProtoEntry>>, WebError> {
|
||||
let filter = filter_all!(f_eq(
|
||||
Attribute::Class,
|
||||
EntryClass::OAuth2ResourceServer.into()
|
||||
));
|
||||
json_rest_event_get(state, None, filter, kopid).await
|
||||
json_rest_event_get(state, None, filter, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
@ -49,6 +51,7 @@ pub(crate) async fn oauth2_get(
|
|||
pub(crate) async fn oauth2_basic_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(obj): Json<ProtoEntry>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let classes = vec![
|
||||
|
@ -56,7 +59,7 @@ pub(crate) async fn oauth2_basic_post(
|
|||
EntryClass::OAuth2ResourceServerBasic.to_string(),
|
||||
EntryClass::Object.to_string(),
|
||||
];
|
||||
json_rest_event_post(state, classes, obj, kopid).await
|
||||
json_rest_event_post(state, classes, obj, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
@ -73,6 +76,7 @@ pub(crate) async fn oauth2_basic_post(
|
|||
pub(crate) async fn oauth2_public_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(obj): Json<ProtoEntry>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let classes = vec![
|
||||
|
@ -80,7 +84,7 @@ pub(crate) async fn oauth2_public_post(
|
|||
EntryClass::OAuth2ResourceServerPublic.to_string(),
|
||||
EntryClass::Object.to_string(),
|
||||
];
|
||||
json_rest_event_post(state, classes, obj, kopid).await
|
||||
json_rest_event_post(state, classes, obj, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
@ -98,11 +102,12 @@ pub(crate) async fn oauth2_id_get(
|
|||
State(state): State<ServerState>,
|
||||
Path(rs_name): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> Result<Json<Option<ProtoEntry>>, WebError> {
|
||||
let filter = oauth2_id(&rs_name);
|
||||
state
|
||||
.qe_r_ref
|
||||
.handle_internalsearch(kopid.uat, filter, None, kopid.eventid)
|
||||
.handle_internalsearch(client_auth_info, filter, None, kopid.eventid)
|
||||
.await
|
||||
.map(|mut r| r.pop())
|
||||
.map(Json::from)
|
||||
|
@ -124,12 +129,13 @@ pub(crate) async fn oauth2_id_get(
|
|||
pub(crate) async fn oauth2_id_get_basic_secret(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path(rs_name): Path<String>,
|
||||
) -> Result<Json<Option<String>>, WebError> {
|
||||
let filter = oauth2_id(&rs_name);
|
||||
state
|
||||
.qe_r_ref
|
||||
.handle_oauth2_basic_secret_read(kopid.uat, filter, kopid.eventid)
|
||||
.handle_oauth2_basic_secret_read(client_auth_info, filter, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -150,13 +156,14 @@ pub(crate) async fn oauth2_id_patch(
|
|||
State(state): State<ServerState>,
|
||||
Path(rs_name): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(obj): Json<ProtoEntry>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let filter = oauth2_id(&rs_name);
|
||||
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_internalpatch(kopid.uat, filter, obj, kopid.eventid)
|
||||
.handle_internalpatch(client_auth_info, filter, obj, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -176,13 +183,14 @@ pub(crate) async fn oauth2_id_patch(
|
|||
pub(crate) async fn oauth2_id_scopemap_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path((rs_name, group)): Path<(String, String)>,
|
||||
Json(scopes): Json<Vec<String>>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let filter = oauth2_id(&rs_name);
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_oauth2_scopemap_update(kopid.uat, group, scopes, filter, kopid.eventid)
|
||||
.handle_oauth2_scopemap_update(client_auth_info, group, scopes, filter, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -201,12 +209,13 @@ pub(crate) async fn oauth2_id_scopemap_post(
|
|||
pub(crate) async fn oauth2_id_scopemap_delete(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path((rs_name, group)): Path<(String, String)>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let filter = oauth2_id(&rs_name);
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_oauth2_scopemap_delete(kopid.uat, group, filter, kopid.eventid)
|
||||
.handle_oauth2_scopemap_delete(client_auth_info, group, filter, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -225,13 +234,14 @@ pub(crate) async fn oauth2_id_scopemap_delete(
|
|||
pub(crate) async fn oauth2_id_sup_scopemap_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path((rs_name, group)): Path<(String, String)>,
|
||||
Json(scopes): Json<Vec<String>>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let filter = oauth2_id(&rs_name);
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_oauth2_sup_scopemap_update(kopid.uat, group, scopes, filter, kopid.eventid)
|
||||
.handle_oauth2_sup_scopemap_update(client_auth_info, group, scopes, filter, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -250,12 +260,13 @@ pub(crate) async fn oauth2_id_sup_scopemap_post(
|
|||
pub(crate) async fn oauth2_id_sup_scopemap_delete(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path((rs_name, group)): Path<(String, String)>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let filter = oauth2_id(&rs_name);
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_oauth2_sup_scopemap_delete(kopid.uat, group, filter, kopid.eventid)
|
||||
.handle_oauth2_sup_scopemap_delete(client_auth_info, group, filter, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -275,12 +286,13 @@ pub(crate) async fn oauth2_id_sup_scopemap_delete(
|
|||
pub(crate) async fn oauth2_id_delete(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path(rs_name): Path<String>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let filter = oauth2_id(&rs_name);
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_internaldelete(kopid.uat, filter, kopid.eventid)
|
||||
.handle_internaldelete(client_auth_info, filter, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -298,12 +310,12 @@ pub(crate) async fn oauth2_id_delete(
|
|||
// API endpoint for deleting the image associated with an OAuth2 Resource Server.
|
||||
pub(crate) async fn oauth2_id_image_delete(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path(rs_name): Path<String>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_oauth2_rs_image_delete(kopid.uat, oauth2_id(&rs_name))
|
||||
.handle_oauth2_rs_image_delete(client_auth_info, oauth2_id(&rs_name))
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -324,7 +336,7 @@ pub(crate) async fn oauth2_id_image_delete(
|
|||
/// [VALID_IMAGE_UPLOAD_CONTENT_TYPES].
|
||||
pub(crate) async fn oauth2_id_image_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path(rs_name): Path<String>,
|
||||
mut multipart: axum::extract::Multipart,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
|
@ -380,7 +392,7 @@ pub(crate) async fn oauth2_id_image_post(
|
|||
let rs_name = oauth2_id(&rs_name);
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_oauth2_rs_image_update(kopid.uat, rs_name, image)
|
||||
.handle_oauth2_rs_image_update(client_auth_info, rs_name, image)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
|
|
@ -6,6 +6,7 @@ use super::v1::{
|
|||
json_rest_event_put_id_attr,
|
||||
};
|
||||
use super::ServerState;
|
||||
use crate::https::extractors::VerifiedClientInformation;
|
||||
use axum::extract::{Path, State};
|
||||
use axum::response::Html;
|
||||
use axum::routing::{get, post};
|
||||
|
@ -29,9 +30,10 @@ use kanidmd_lib::prelude::*;
|
|||
pub async fn sync_account_get(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> Result<Json<Vec<ProtoEntry>>, WebError> {
|
||||
let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SyncAccount.into()));
|
||||
json_rest_event_get(state, None, filter, kopid).await
|
||||
json_rest_event_get(state, None, filter, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
@ -47,10 +49,11 @@ pub async fn sync_account_get(
|
|||
pub async fn sync_account_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(obj): Json<ProtoEntry>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let classes: Vec<String> = vec![EntryClass::SyncAccount.into(), EntryClass::Object.into()];
|
||||
json_rest_event_post(state, classes, obj, kopid).await
|
||||
json_rest_event_post(state, classes, obj, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
@ -68,9 +71,10 @@ pub async fn sync_account_id_get(
|
|||
State(state): State<ServerState>,
|
||||
Path(id): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> Result<Json<Option<ProtoEntry>>, WebError> {
|
||||
let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SyncAccount.into()));
|
||||
json_rest_event_get_id(state, id, filter, None, kopid).await
|
||||
json_rest_event_get_id(state, id, filter, None, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
@ -88,6 +92,7 @@ pub async fn sync_account_id_patch(
|
|||
State(state): State<ServerState>,
|
||||
Path(id): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(obj): Json<ProtoEntry>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SyncAccount.into()));
|
||||
|
@ -95,7 +100,7 @@ pub async fn sync_account_id_patch(
|
|||
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_internalpatch(kopid.uat, filter, obj, kopid.eventid)
|
||||
.handle_internalpatch(client_auth_info, filter, obj, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -115,10 +120,11 @@ pub async fn sync_account_id_finalise_get(
|
|||
State(state): State<ServerState>,
|
||||
Path(id): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_sync_account_finalise(kopid.uat, id, kopid.eventid)
|
||||
.handle_sync_account_finalise(client_auth_info, id, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -138,10 +144,11 @@ pub async fn sync_account_id_terminate_get(
|
|||
State(state): State<ServerState>,
|
||||
Path(id): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_sync_account_terminate(kopid.uat, id, kopid.eventid)
|
||||
.handle_sync_account_terminate(client_auth_info, id, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -161,11 +168,12 @@ pub async fn sync_account_token_post(
|
|||
State(state): State<ServerState>,
|
||||
Path(id): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(label): Json<String>,
|
||||
) -> Result<Json<String>, WebError> {
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_sync_account_token_generate(kopid.uat, id, label, kopid.eventid)
|
||||
.handle_sync_account_token_generate(client_auth_info, id, label, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -184,10 +192,11 @@ pub async fn sync_account_token_delete(
|
|||
State(state): State<ServerState>,
|
||||
Path(id): Path<String>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_sync_account_token_destroy(kopid.uat, id, kopid.eventid)
|
||||
.handle_sync_account_token_destroy(client_auth_info, id, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -206,12 +215,12 @@ pub async fn sync_account_token_delete(
|
|||
async fn scim_sync_post(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
AuthBearer(bearer): AuthBearer,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Json(changes): Json<ScimSyncRequest>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
state
|
||||
.qe_w_ref
|
||||
.handle_scim_sync_apply(Some(bearer), changes, kopid.eventid)
|
||||
.handle_scim_sync_apply(client_auth_info, changes, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -230,13 +239,14 @@ async fn scim_sync_post(
|
|||
async fn scim_sync_get(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
AuthBearer(bearer): AuthBearer,
|
||||
) -> Result<Json<ScimSyncState>, WebError> {
|
||||
// Given the token, what is it's connected sync state?
|
||||
trace!(?bearer);
|
||||
state
|
||||
.qe_r_ref
|
||||
.handle_scim_sync_status(Some(bearer), kopid.eventid)
|
||||
.handle_scim_sync_status(client_auth_info, kopid.eventid)
|
||||
.await
|
||||
.map(Json::from)
|
||||
.map_err(WebError::from)
|
||||
|
@ -254,10 +264,11 @@ async fn scim_sync_get(
|
|||
pub async fn sync_account_id_attr_get(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path((id, attr)): Path<(String, String)>,
|
||||
) -> Result<Json<Option<Vec<String>>>, WebError> {
|
||||
let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SyncAccount.into()));
|
||||
json_rest_event_get_id_attr(state, id, attr, filter, kopid).await
|
||||
json_rest_event_get_id_attr(state, id, attr, filter, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
|
@ -273,11 +284,12 @@ pub async fn sync_account_id_attr_get(
|
|||
pub async fn sync_account_id_attr_put(
|
||||
State(state): State<ServerState>,
|
||||
Extension(kopid): Extension<KOpId>,
|
||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||
Path((id, attr)): Path<(String, String)>,
|
||||
Json(values): Json<Vec<String>>,
|
||||
) -> Result<Json<()>, WebError> {
|
||||
let filter = filter_all!(f_eq(Attribute::Class, EntryClass::SyncAccount.into()));
|
||||
json_rest_event_put_id_attr(state, id, attr, filter, values, kopid).await
|
||||
json_rest_event_put_id_attr(state, id, attr, filter, values, kopid, client_auth_info).await
|
||||
}
|
||||
|
||||
/// When you want the kitchen Sink
|
||||
|
|
|
@ -43,7 +43,9 @@ async fn client_process_msg(
|
|||
client_port = %client_address.port(),
|
||||
"LDAP client"
|
||||
);
|
||||
qe_r_ref.handle_ldaprequest(eventid, protomsg, uat).await
|
||||
qe_r_ref
|
||||
.handle_ldaprequest(eventid, protomsg, uat, client_address.ip())
|
||||
.await
|
||||
}
|
||||
|
||||
async fn client_process(
|
||||
|
|
|
@ -18,6 +18,8 @@ if [ ! -d "${KANI_TMP}" ]; then
|
|||
mkdir -p "${KANI_TMP}"
|
||||
fi
|
||||
|
||||
mkdir -p "${KANI_TMP}"/client_ca
|
||||
|
||||
CONFIG_FILE=${CONFIG_FILE:="../../examples/insecure_server.toml"}
|
||||
|
||||
if [ ! -f "${CONFIG_FILE}" ]; then
|
||||
|
|
|
@ -7,6 +7,7 @@ use time::OffsetDateTime;
|
|||
pub enum AuditSource {
|
||||
Internal,
|
||||
Https(IpAddr),
|
||||
Ldaps(IpAddr),
|
||||
}
|
||||
|
||||
impl From<Source> for AuditSource {
|
||||
|
@ -14,6 +15,7 @@ impl From<Source> for AuditSource {
|
|||
match value {
|
||||
Source::Internal => AuditSource::Internal,
|
||||
Source::Https(ip) => AuditSource::Https(ip),
|
||||
Source::Ldaps(ip) => AuditSource::Ldaps(ip),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -889,7 +889,7 @@ pub(crate) struct AuthSessionData<'a> {
|
|||
pub(crate) issue: AuthIssueSession,
|
||||
pub(crate) webauthn: &'a Webauthn,
|
||||
pub(crate) ct: Duration,
|
||||
pub(crate) source: Source,
|
||||
pub(crate) client_auth_info: ClientAuthInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -1008,7 +1008,7 @@ impl AuthSession {
|
|||
state,
|
||||
issue: asd.issue,
|
||||
intent: AuthIntent::InitialAuth { privileged },
|
||||
source: asd.source,
|
||||
source: asd.client_auth_info.source,
|
||||
};
|
||||
// Get the set of mechanisms that can proceed. This is tied
|
||||
// to the session so that it can mutate state and have progression
|
||||
|
@ -1149,7 +1149,7 @@ impl AuthSession {
|
|||
session_id,
|
||||
session_expiry,
|
||||
},
|
||||
source: asd.source,
|
||||
source: asd.client_auth_info.source,
|
||||
};
|
||||
|
||||
let as_state = AuthState::Continue(allow);
|
||||
|
@ -1548,7 +1548,7 @@ mod tests {
|
|||
issue: AuthIssueSession::Token,
|
||||
webauthn: &webauthn,
|
||||
ct: duration_from_epoch_now(),
|
||||
source: Source::Internal,
|
||||
client_auth_info: Source::Internal.into(),
|
||||
};
|
||||
let (session, state) = AuthSession::new(asd, false);
|
||||
if let AuthState::Choose(auth_mechs) = state {
|
||||
|
@ -1584,7 +1584,7 @@ mod tests {
|
|||
issue: AuthIssueSession::Token,
|
||||
webauthn: $webauthn,
|
||||
ct: duration_from_epoch_now(),
|
||||
source: Source::Internal,
|
||||
client_auth_info: Source::Internal.into(),
|
||||
};
|
||||
let (session, state) = AuthSession::new(asd, $privileged);
|
||||
let mut session = session.unwrap();
|
||||
|
@ -1771,7 +1771,7 @@ mod tests {
|
|||
issue: AuthIssueSession::Token,
|
||||
webauthn: $webauthn,
|
||||
ct: duration_from_epoch_now(),
|
||||
source: Source::Internal,
|
||||
client_auth_info: Source::Internal.into(),
|
||||
};
|
||||
let (session, state) = AuthSession::new(asd, false);
|
||||
let mut session = session.expect("Session was unable to be created.");
|
||||
|
@ -2099,7 +2099,7 @@ mod tests {
|
|||
issue: AuthIssueSession::Token,
|
||||
webauthn: $webauthn,
|
||||
ct: duration_from_epoch_now(),
|
||||
source: Source::Internal,
|
||||
client_auth_info: Source::Internal.into(),
|
||||
};
|
||||
let (session, state) = AuthSession::new(asd, false);
|
||||
let mut session = session.unwrap();
|
||||
|
|
|
@ -2534,7 +2534,9 @@ mod tests {
|
|||
|
||||
let auth_init = AuthEvent::named_init("testperson");
|
||||
|
||||
let r1 = idms_auth.auth(&auth_init, ct, Source::Internal).await;
|
||||
let r1 = idms_auth
|
||||
.auth(&auth_init, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r1.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2545,7 +2547,9 @@ mod tests {
|
|||
|
||||
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::Password);
|
||||
|
||||
let r2 = idms_auth.auth(&auth_begin, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&auth_begin, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2554,7 +2558,7 @@ mod tests {
|
|||
let pw_step = AuthEvent::cred_step_password(sessionid, pw);
|
||||
|
||||
// Expect success
|
||||
let r2 = idms_auth.auth(&pw_step, ct, Source::Internal).await;
|
||||
let r2 = idms_auth.auth(&pw_step, ct, Source::Internal.into()).await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
idms_auth.commit().expect("Must not fail");
|
||||
|
||||
|
@ -2584,7 +2588,9 @@ mod tests {
|
|||
|
||||
let auth_init = AuthEvent::named_init("testperson");
|
||||
|
||||
let r1 = idms_auth.auth(&auth_init, ct, Source::Internal).await;
|
||||
let r1 = idms_auth
|
||||
.auth(&auth_init, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r1.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2595,7 +2601,9 @@ mod tests {
|
|||
|
||||
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::PasswordMfa);
|
||||
|
||||
let r2 = idms_auth.auth(&auth_begin, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&auth_begin, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2606,7 +2614,9 @@ mod tests {
|
|||
.expect("Failed to perform totp step");
|
||||
|
||||
let totp_step = AuthEvent::cred_step_totp(sessionid, totp);
|
||||
let r2 = idms_auth.auth(&totp_step, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&totp_step, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2615,7 +2625,7 @@ mod tests {
|
|||
let pw_step = AuthEvent::cred_step_password(sessionid, pw);
|
||||
|
||||
// Expect success
|
||||
let r3 = idms_auth.auth(&pw_step, ct, Source::Internal).await;
|
||||
let r3 = idms_auth.auth(&pw_step, ct, Source::Internal.into()).await;
|
||||
debug!("r3 ==> {:?}", r3);
|
||||
idms_auth.commit().expect("Must not fail");
|
||||
|
||||
|
@ -2644,7 +2654,9 @@ mod tests {
|
|||
|
||||
let auth_init = AuthEvent::named_init("testperson");
|
||||
|
||||
let r1 = idms_auth.auth(&auth_init, ct, Source::Internal).await;
|
||||
let r1 = idms_auth
|
||||
.auth(&auth_init, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r1.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2655,14 +2667,18 @@ mod tests {
|
|||
|
||||
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::PasswordMfa);
|
||||
|
||||
let r2 = idms_auth.auth(&auth_begin, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&auth_begin, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
assert!(matches!(state, AuthState::Continue(_)));
|
||||
|
||||
let code_step = AuthEvent::cred_step_backup_code(sessionid, code);
|
||||
let r2 = idms_auth.auth(&code_step, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&code_step, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2671,7 +2687,7 @@ mod tests {
|
|||
let pw_step = AuthEvent::cred_step_password(sessionid, pw);
|
||||
|
||||
// Expect success
|
||||
let r3 = idms_auth.auth(&pw_step, ct, Source::Internal).await;
|
||||
let r3 = idms_auth.auth(&pw_step, ct, Source::Internal.into()).await;
|
||||
debug!("r3 ==> {:?}", r3);
|
||||
idms_auth.commit().expect("Must not fail");
|
||||
|
||||
|
@ -2706,7 +2722,9 @@ mod tests {
|
|||
|
||||
let auth_init = AuthEvent::named_init("testperson");
|
||||
|
||||
let r1 = idms_auth.auth(&auth_init, ct, Source::Internal).await;
|
||||
let r1 = idms_auth
|
||||
.auth(&auth_init, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r1.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2717,7 +2735,9 @@ mod tests {
|
|||
|
||||
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::Passkey);
|
||||
|
||||
let r2 = idms_auth.auth(&auth_begin, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&auth_begin, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2739,7 +2759,9 @@ mod tests {
|
|||
|
||||
let passkey_step = AuthEvent::cred_step_passkey(sessionid, resp);
|
||||
|
||||
let r3 = idms_auth.auth(&passkey_step, ct, Source::Internal).await;
|
||||
let r3 = idms_auth
|
||||
.auth(&passkey_step, ct, Source::Internal.into())
|
||||
.await;
|
||||
debug!("r3 ==> {:?}", r3);
|
||||
idms_auth.commit().expect("Must not fail");
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use kanidm_proto::constants::*;
|
|||
use kanidm_proto::v1::{ApiToken, OperationError, UserAuthToken};
|
||||
use ldap3_proto::simple::*;
|
||||
use regex::Regex;
|
||||
use std::net::IpAddr;
|
||||
use tracing::trace;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -138,6 +139,7 @@ impl LdapServer {
|
|||
idms: &IdmServer,
|
||||
sr: &SearchRequest,
|
||||
uat: &LdapBoundToken,
|
||||
source: Source,
|
||||
// eventid: &Uuid,
|
||||
) -> Result<Vec<LdapMsg>, OperationError> {
|
||||
admin_info!("Attempt LDAP Search for {}", uat.spn);
|
||||
|
@ -320,7 +322,7 @@ impl LdapServer {
|
|||
//
|
||||
// ! Remember, searchEvent wraps to ignore hidden for us.
|
||||
let ident = idm_read
|
||||
.validate_ldap_session(&uat.effective_session, ct)
|
||||
.validate_ldap_session(&uat.effective_session, source, ct)
|
||||
.map_err(|e| {
|
||||
admin_error!("Invalid identity: {:?}", e);
|
||||
e
|
||||
|
@ -456,8 +458,11 @@ impl LdapServer {
|
|||
idms: &IdmServer,
|
||||
server_op: ServerOps,
|
||||
uat: Option<LdapBoundToken>,
|
||||
ip_addr: IpAddr,
|
||||
eventid: Uuid,
|
||||
) -> Result<LdapResponseState, OperationError> {
|
||||
let source = Source::Ldaps(ip_addr);
|
||||
|
||||
match server_op {
|
||||
ServerOps::SimpleBind(sbr) => self
|
||||
.do_bind(idms, sbr.dn.as_str(), sbr.pw.as_str())
|
||||
|
@ -472,7 +477,7 @@ impl LdapServer {
|
|||
}),
|
||||
ServerOps::Search(sr) => match uat {
|
||||
Some(u) => self
|
||||
.do_search(idms, &sr, &u)
|
||||
.do_search(idms, &sr, &u, source)
|
||||
.await
|
||||
.map(LdapResponseState::MultiPartResponse)
|
||||
.or_else(|e| {
|
||||
|
@ -494,7 +499,7 @@ impl LdapServer {
|
|||
}
|
||||
};
|
||||
// If okay, do the search.
|
||||
self.do_search(idms, &sr, &lbt)
|
||||
self.do_search(idms, &sr, &lbt, Source::Internal)
|
||||
.await
|
||||
.map(|r| LdapResponseState::BindMultiPartResponse(lbt, r))
|
||||
.or_else(|e| {
|
||||
|
@ -895,7 +900,10 @@ mod tests {
|
|||
filter: LdapFilter::Equality(Attribute::Name.to_string(), "testperson1".to_string()),
|
||||
attrs: vec!["*".to_string()],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_t, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// The result, and the ldap proto success msg.
|
||||
assert!(r1.len() == 2);
|
||||
|
@ -927,7 +935,10 @@ mod tests {
|
|||
filter: LdapFilter::Equality(Attribute::Name.to_string(), "testperson1".to_string()),
|
||||
attrs: vec!["+".to_string()],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_t, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// The result, and the ldap proto success msg.
|
||||
assert!(r1.len() == 2);
|
||||
|
@ -971,7 +982,10 @@ mod tests {
|
|||
Attribute::UidNumber.to_string(),
|
||||
],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_t, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// The result, and the ldap proto success msg.
|
||||
assert!(r1.len() == 2);
|
||||
|
@ -1102,7 +1116,10 @@ mod tests {
|
|||
let anon_lbt = ldaps.do_bind(idms, "", "").await.unwrap().unwrap();
|
||||
assert!(anon_lbt.effective_session == LdapSession::UnixBind(UUID_ANONYMOUS));
|
||||
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_lbt).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_lbt, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(r1.len() == 2);
|
||||
match &r1[0].op {
|
||||
LdapOp::SearchResultEntry(lsre) => {
|
||||
|
@ -1141,7 +1158,10 @@ mod tests {
|
|||
assert!(sa_lbt.effective_session == LdapSession::ApiToken(apitoken_inner));
|
||||
|
||||
// Search and retrieve mail that's now accessible.
|
||||
let r1 = ldaps.do_search(idms, &sr, &sa_lbt).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &sa_lbt, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(r1.len() == 2);
|
||||
match &r1[0].op {
|
||||
LdapOp::SearchResultEntry(lsre) => {
|
||||
|
@ -1216,7 +1236,10 @@ mod tests {
|
|||
Attribute::EntryUuid.to_string(),
|
||||
],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_t, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// The result, and the ldap proto success msg.
|
||||
assert!(r1.len() == 2);
|
||||
|
@ -1252,7 +1275,10 @@ mod tests {
|
|||
filter: LdapFilter::Present(Attribute::ObjectClass.to_string()),
|
||||
attrs: vec!["*".to_string()],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_t, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
trace!(?r1);
|
||||
|
||||
|
@ -1302,7 +1328,10 @@ mod tests {
|
|||
filter: LdapFilter::Present(Attribute::ObjectClass.to_string()),
|
||||
attrs: vec!["*".to_string()],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_t, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
trace!(?r1);
|
||||
|
||||
|
@ -1378,7 +1407,10 @@ mod tests {
|
|||
Attribute::EntryUuid.to_string(),
|
||||
],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_t, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Empty results and ldap proto success msg.
|
||||
assert!(r1.len() == 1);
|
||||
|
@ -1399,7 +1431,10 @@ mod tests {
|
|||
"entryuuid".to_string(),
|
||||
],
|
||||
};
|
||||
let r1 = ldaps.do_search(idms, &sr, &anon_t).await.unwrap();
|
||||
let r1 = ldaps
|
||||
.do_search(idms, &sr, &anon_t, Source::Internal)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
trace!(?r1);
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ pub mod server;
|
|||
pub mod serviceaccount;
|
||||
pub(crate) mod unix;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::server::identity::Source;
|
||||
use kanidm_proto::v1::{AuthAllowed, AuthIssueSession, AuthMech};
|
||||
use std::fmt;
|
||||
|
||||
pub enum AuthState {
|
||||
Choose(Vec<AuthMech>),
|
||||
|
@ -43,3 +43,49 @@ impl fmt::Debug for AuthState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClientAuthInfo {
|
||||
pub source: Source,
|
||||
pub client_cert: Option<ClientCertInfo>,
|
||||
pub bearer_token: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClientCertInfo {
|
||||
pub subject_key_id: Option<Vec<u8>>,
|
||||
pub cn: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<Source> for ClientAuthInfo {
|
||||
fn from(value: Source) -> ClientAuthInfo {
|
||||
ClientAuthInfo {
|
||||
source: value,
|
||||
client_cert: None,
|
||||
bearer_token: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<&str> for ClientAuthInfo {
|
||||
fn from(value: &str) -> ClientAuthInfo {
|
||||
ClientAuthInfo {
|
||||
source: Source::Internal,
|
||||
client_cert: None,
|
||||
bearer_token: Some(value.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<ClientCertInfo> for ClientAuthInfo {
|
||||
fn from(value: ClientCertInfo) -> ClientAuthInfo {
|
||||
ClientAuthInfo {
|
||||
source: Source::Internal,
|
||||
client_cert: Some(value),
|
||||
bearer_token: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ use kanidm_proto::oauth2::{
|
|||
ClaimType, DisplayValue, GrantType, IdTokenSignAlg, ResponseMode, ResponseType, SubjectType,
|
||||
TokenEndpointAuthMethod,
|
||||
};
|
||||
use kanidm_proto::v1::UserAuthToken;
|
||||
use openssl::sha;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::OffsetDateTime;
|
||||
|
@ -112,7 +111,10 @@ struct ConsentToken {
|
|||
struct TokenExchangeCode {
|
||||
// We don't need the client_id here, because it's signed with an RS specific
|
||||
// key which gives us the assurance that it's the correct combination.
|
||||
pub uat: UserAuthToken,
|
||||
// pub uat: UserAuthToken,
|
||||
pub account_uuid: Uuid,
|
||||
pub session_id: Uuid,
|
||||
|
||||
// The S256 code challenge.
|
||||
pub code_challenge: Option<Base64UrlSafeData>,
|
||||
// The original redirect uri
|
||||
|
@ -683,10 +685,14 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
pub fn check_oauth2_authorise_permit(
|
||||
&mut self,
|
||||
ident: &Identity,
|
||||
uat: &UserAuthToken,
|
||||
consent_token: &str,
|
||||
ct: Duration,
|
||||
) -> Result<AuthorisePermitSuccess, OperationError> {
|
||||
let Some(account_uuid) = ident.get_uuid() else {
|
||||
error!("consent request ident does not have a valid uuid, unable to proceed");
|
||||
return Err(OperationError::InvalidSessionState);
|
||||
};
|
||||
|
||||
// Decode the consent req with our system fernet key. Use a ttl of 5 minutes.
|
||||
let consent_req: ConsentToken = self
|
||||
.oauth2rs
|
||||
|
@ -711,7 +717,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
}
|
||||
|
||||
// Validate that the session id matches our uat.
|
||||
if consent_req.session_id != uat.session_id {
|
||||
if consent_req.session_id != ident.get_session_id() {
|
||||
security_info!("consent request session id does not match the session id of our UAT.");
|
||||
return Err(OperationError::InvalidSessionState);
|
||||
}
|
||||
|
@ -729,7 +735,9 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
|
||||
// Extract the state, code challenge, redirect_uri
|
||||
let xchg_code = TokenExchangeCode {
|
||||
uat: uat.clone(),
|
||||
// uat: uat.clone(),
|
||||
account_uuid,
|
||||
session_id: ident.get_session_id(),
|
||||
code_challenge: consent_req.code_challenge,
|
||||
redirect_uri: consent_req.redirect_uri.clone(),
|
||||
scopes: consent_req.scopes.clone(),
|
||||
|
@ -760,7 +768,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
]);
|
||||
|
||||
self.qs_write.internal_modify(
|
||||
&filter_all!(f_eq(Attribute::Uuid, PartialValue::Uuid(uat.uuid))),
|
||||
&filter_all!(f_eq(Attribute::Uuid, PartialValue::Uuid(account_uuid))),
|
||||
&modlist,
|
||||
)?;
|
||||
|
||||
|
@ -840,7 +848,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
return Err(Oauth2Error::InvalidOrigin);
|
||||
}
|
||||
|
||||
/*
|
||||
// Check that the UAT we are issuing for still is valid.
|
||||
//
|
||||
// Not sure this is actually needed. To create the token exchange code you need to have
|
||||
// a valid, non-expired session, so why do we double check this here?
|
||||
let odt_ct = OffsetDateTime::UNIX_EPOCH + ct;
|
||||
if let Some(expiry) = code_xchg.uat.expiry {
|
||||
if expiry <= odt_ct {
|
||||
|
@ -850,14 +862,15 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
return Err(Oauth2Error::AccessDenied);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// ==== We are now GOOD TO GO! ====
|
||||
// Grant the access token response.
|
||||
let parent_session_id = code_xchg.uat.session_id;
|
||||
let parent_session_id = code_xchg.session_id;
|
||||
let session_id = Uuid::new_v4();
|
||||
|
||||
let scopes = code_xchg.scopes;
|
||||
let account_uuid = code_xchg.uat.uuid;
|
||||
let account_uuid = code_xchg.account_uuid;
|
||||
let nonce = code_xchg.nonce;
|
||||
|
||||
self.generate_access_token_response(
|
||||
|
@ -1239,7 +1252,6 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
pub fn check_oauth2_authorisation(
|
||||
&self,
|
||||
ident: &Identity,
|
||||
uat: &UserAuthToken,
|
||||
auth_req: &AuthorisationRequest,
|
||||
ct: Duration,
|
||||
) -> Result<AuthoriseResponse, Oauth2Error> {
|
||||
|
@ -1340,8 +1352,13 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
|
||||
// NOTE: login_hint is handled in the UI code, not here.
|
||||
|
||||
let Some(account_uuid) = ident.get_uuid() else {
|
||||
error!("consent request ident does not have a valid uuid, unable to proceed");
|
||||
return Err(Oauth2Error::InvalidRequest);
|
||||
};
|
||||
|
||||
// Deny anonymous access to oauth2
|
||||
if uat.uuid == UUID_ANONYMOUS {
|
||||
if account_uuid == UUID_ANONYMOUS {
|
||||
admin_error!(
|
||||
"Invalid OAuth2 request - refusing to allow user that authenticated with anonymous"
|
||||
);
|
||||
|
@ -1451,6 +1468,8 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
false
|
||||
};
|
||||
|
||||
let session_id = ident.get_session_id();
|
||||
|
||||
if consent_previously_granted {
|
||||
let pretty_scopes: Vec<String> = granted_scopes.iter().map(|s| s.to_owned()).collect();
|
||||
admin_info!(
|
||||
|
@ -1460,7 +1479,8 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
|
||||
// Setup for the permit success
|
||||
let xchg_code = TokenExchangeCode {
|
||||
uat: uat.clone(),
|
||||
account_uuid,
|
||||
session_id,
|
||||
code_challenge,
|
||||
redirect_uri: auth_req.redirect_uri.clone(),
|
||||
scopes: granted_scopes.into_iter().collect(),
|
||||
|
@ -1511,7 +1531,7 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
let consent_req = ConsentToken {
|
||||
client_id: auth_req.client_id.clone(),
|
||||
ident_id: ident.get_event_origin_id(),
|
||||
session_id: uat.session_id,
|
||||
session_id,
|
||||
state: auth_req.state.clone(),
|
||||
code_challenge,
|
||||
redirect_uri: auth_req.redirect_uri.clone(),
|
||||
|
@ -1543,7 +1563,6 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
pub fn check_oauth2_authorise_reject(
|
||||
&self,
|
||||
ident: &Identity,
|
||||
uat: &UserAuthToken,
|
||||
consent_token: &str,
|
||||
ct: Duration,
|
||||
) -> Result<Url, OperationError> {
|
||||
|
@ -1570,8 +1589,8 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
return Err(OperationError::InvalidSessionState);
|
||||
}
|
||||
|
||||
// Validate that the session id matches our uat.
|
||||
if consent_req.session_id != uat.session_id {
|
||||
// Validate that the session id matches our session
|
||||
if consent_req.session_id != ident.get_session_id() {
|
||||
security_info!("consent request sessien id does not match the session id of our UAT.");
|
||||
return Err(OperationError::InvalidSessionState);
|
||||
}
|
||||
|
@ -2047,7 +2066,6 @@ mod tests {
|
|||
(
|
||||
$idms_prox_read:expr,
|
||||
$ident:expr,
|
||||
$uat:expr,
|
||||
$ct:expr,
|
||||
$code_challenge:expr,
|
||||
$scope:expr
|
||||
|
@ -2068,7 +2086,7 @@ mod tests {
|
|||
};
|
||||
|
||||
$idms_prox_read
|
||||
.check_oauth2_authorisation($ident, $uat, &auth_req, $ct)
|
||||
.check_oauth2_authorisation($ident, &auth_req, $ct)
|
||||
.expect("OAuth2 authorisation failed")
|
||||
}};
|
||||
}
|
||||
|
@ -2215,7 +2233,7 @@ mod tests {
|
|||
.expect("Failed to modify user");
|
||||
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
idms_prox_write.commit().expect("failed to commit");
|
||||
|
@ -2337,7 +2355,7 @@ mod tests {
|
|||
.expect("Failed to modify user");
|
||||
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
idms_prox_write.commit().expect("failed to commit");
|
||||
|
@ -2360,7 +2378,7 @@ mod tests {
|
|||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
idms_prox_write.commit().expect("failed to commit");
|
||||
|
@ -2374,7 +2392,7 @@ mod tests {
|
|||
_idms_delayed: &mut IdmServerDelayed,
|
||||
) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
|
@ -2387,7 +2405,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -2406,7 +2423,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// Check we are reflecting the CSRF properly.
|
||||
|
@ -2441,7 +2458,7 @@ mod tests {
|
|||
_idms_delayed: &mut IdmServerDelayed,
|
||||
) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (uat, ident, _) = setup_oauth2_resource_server_public(idms, ct).await;
|
||||
let (_uat, ident, _) = setup_oauth2_resource_server_public(idms, ct).await;
|
||||
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
|
||||
|
@ -2453,7 +2470,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -2472,7 +2488,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// Check we are reflecting the CSRF properly.
|
||||
|
@ -2508,11 +2524,11 @@ mod tests {
|
|||
) {
|
||||
// Test invalid OAuth2 authorisation states/requests.
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (_secret, uat, ident, _) =
|
||||
let (_secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
|
||||
let (anon_uat, anon_ident) = setup_idm_admin(idms, ct).await;
|
||||
let (idm_admin_uat, idm_admin_ident) = setup_idm_admin(idms, ct).await;
|
||||
let (_anon_uat, anon_ident) = setup_idm_admin(idms, ct).await;
|
||||
let (_idm_admin_uat, idm_admin_ident) = setup_idm_admin(idms, ct).await;
|
||||
|
||||
// Need a uat from a user not in the group. Probs anonymous.
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
|
@ -2539,7 +2555,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::UnsupportedResponseType
|
||||
);
|
||||
|
@ -2559,7 +2575,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::InvalidRequest
|
||||
);
|
||||
|
@ -2579,7 +2595,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::InvalidClientId
|
||||
);
|
||||
|
@ -2599,7 +2615,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::InvalidOrigin
|
||||
);
|
||||
|
@ -2619,7 +2635,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::AccessDenied
|
||||
);
|
||||
|
@ -2639,7 +2655,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&idm_admin_ident, &idm_admin_uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&idm_admin_ident, &auth_req, ct)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::AccessDenied
|
||||
);
|
||||
|
@ -2659,7 +2675,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&anon_ident, &anon_uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&anon_ident, &auth_req, ct)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::AccessDenied
|
||||
);
|
||||
|
@ -2675,25 +2691,33 @@ mod tests {
|
|||
let (_secret, uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
|
||||
let (uat2, ident2) = {
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
let account = idms_prox_write
|
||||
.target_to_account(UUID_IDM_ADMIN)
|
||||
.expect("account must exist");
|
||||
let session_id = uuid::Uuid::new_v4();
|
||||
let uat2 = account
|
||||
.to_userauthtoken(
|
||||
session_id,
|
||||
SessionScope::ReadWrite,
|
||||
ct,
|
||||
DEFAULT_AUTH_SESSION_EXPIRY,
|
||||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident2 = idms_prox_write
|
||||
.process_uat_to_identity(&uat2, ct)
|
||||
.expect("Unable to process uat");
|
||||
(uat2, ident2)
|
||||
};
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let mut uat_wrong_session_id = uat.clone();
|
||||
uat_wrong_session_id.session_id = uuid::Uuid::new_v4();
|
||||
let ident_wrong_session_id = idms_prox_write
|
||||
.process_uat_to_identity(&uat_wrong_session_id, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
let account = idms_prox_write
|
||||
.target_to_account(UUID_IDM_ADMIN)
|
||||
.expect("account must exist");
|
||||
let session_id = uuid::Uuid::new_v4();
|
||||
let uat2 = account
|
||||
.to_userauthtoken(
|
||||
session_id,
|
||||
SessionScope::ReadWrite,
|
||||
ct,
|
||||
DEFAULT_AUTH_SESSION_EXPIRY,
|
||||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident2 = idms_prox_write
|
||||
.process_uat_to_identity(&uat2, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
||||
// Now start the test
|
||||
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
|
||||
|
@ -2702,7 +2726,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -2724,7 +2747,6 @@ mod tests {
|
|||
idms_prox_write
|
||||
.check_oauth2_authorise_permit(
|
||||
&ident,
|
||||
&uat,
|
||||
&consent_token,
|
||||
ct + Duration::from_secs(TOKEN_EXPIRE),
|
||||
)
|
||||
|
@ -2738,7 +2760,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident2, &uat, &consent_token, ct,)
|
||||
.check_oauth2_authorise_permit(&ident2, &consent_token, ct,)
|
||||
.unwrap_err()
|
||||
== OperationError::InvalidSessionState
|
||||
);
|
||||
|
@ -2746,7 +2768,7 @@ mod tests {
|
|||
// * incorrect session id
|
||||
assert!(
|
||||
idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat2, &consent_token, ct,)
|
||||
.check_oauth2_authorise_permit(&ident_wrong_session_id, &consent_token, ct,)
|
||||
.unwrap_err()
|
||||
== OperationError::InvalidSessionState
|
||||
);
|
||||
|
@ -2784,7 +2806,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -2802,7 +2823,7 @@ mod tests {
|
|||
|
||||
// == Manually submit the consent token to the permit for the permit_success
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// == Submit the token exchange code.
|
||||
|
@ -2867,19 +2888,6 @@ mod tests {
|
|||
== Oauth2Error::InvalidRequest
|
||||
);
|
||||
|
||||
// * Uat has expired!
|
||||
// NOTE: This is setup EARLY in the test, by manipulation of the UAT expiry.
|
||||
assert!(
|
||||
idms_prox_write
|
||||
.check_oauth2_token_exchange(
|
||||
client_authz.as_deref(),
|
||||
&token_req,
|
||||
ct + Duration::from_secs(UAT_EXPIRE)
|
||||
)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::AccessDenied
|
||||
);
|
||||
|
||||
/*
|
||||
// * incorrect grant_type
|
||||
// No longer possible due to changes in json api
|
||||
|
@ -2936,7 +2944,7 @@ mod tests {
|
|||
_idms_delayed: &mut IdmServerDelayed,
|
||||
) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
let client_authz =
|
||||
Some(general_purpose::STANDARD.encode(format!("test_resource_server:{secret}")));
|
||||
|
@ -2948,7 +2956,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -2966,7 +2973,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
let token_req: AccessTokenRequest = GrantTypeReq::AuthorizationCode {
|
||||
|
@ -3032,7 +3039,7 @@ mod tests {
|
|||
async fn test_idm_oauth2_token_revoke(idms: &IdmServer, _idms_delayed: &mut IdmServerDelayed) {
|
||||
// First, setup to get a token.
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
let client_authz =
|
||||
Some(general_purpose::STANDARD.encode(format!("test_resource_server:{secret}")));
|
||||
|
@ -3044,7 +3051,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -3062,7 +3068,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// Assert that the consent was submitted
|
||||
|
@ -3149,7 +3155,10 @@ mod tests {
|
|||
|
||||
// Force trim the session and wait for the grace window to pass. The token will be invalidated
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
let filt = filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(uat.uuid)));
|
||||
let filt = filter!(f_eq(
|
||||
Attribute::Uuid,
|
||||
PartialValue::Uuid(ident.get_uuid().unwrap())
|
||||
));
|
||||
let mut work_set = idms_prox_write
|
||||
.qs_write
|
||||
.internal_search_writeable(&filt)
|
||||
|
@ -3199,7 +3208,7 @@ mod tests {
|
|||
) {
|
||||
// First, setup to get a token.
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
let client_authz =
|
||||
Some(general_purpose::STANDARD.encode(format!("test_resource_server:{secret}")));
|
||||
|
@ -3211,7 +3220,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -3229,7 +3237,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
let token_req: AccessTokenRequest = GrantTypeReq::AuthorizationCode {
|
||||
|
@ -3300,10 +3308,10 @@ mod tests {
|
|||
_idms_delayed: &mut IdmServerDelayed,
|
||||
) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (_secret, uat, ident, _) =
|
||||
let (_secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
|
||||
let (uat2, ident2) = {
|
||||
let ident2 = {
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
let account = idms_prox_write
|
||||
.target_to_account(UUID_IDM_ADMIN)
|
||||
|
@ -3318,9 +3326,9 @@ mod tests {
|
|||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident2 = idms_prox_write
|
||||
.process_uat_to_identity(&uat2, ct)
|
||||
.process_uat_to_identity(&uat2, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
(uat2, ident2)
|
||||
ident2
|
||||
};
|
||||
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
|
@ -3331,7 +3339,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -3345,7 +3352,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let reject_success = idms_prox_read
|
||||
.check_oauth2_authorise_reject(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_reject(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 reject");
|
||||
|
||||
assert!(reject_success == redirect_uri);
|
||||
|
@ -3354,7 +3361,7 @@ mod tests {
|
|||
let past_ct = Duration::from_secs(TEST_CURRENT_TIME + 301);
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorise_reject(&ident, &uat, &consent_token, past_ct)
|
||||
.check_oauth2_authorise_reject(&ident, &consent_token, past_ct)
|
||||
.unwrap_err()
|
||||
== OperationError::CryptographyError
|
||||
);
|
||||
|
@ -3362,22 +3369,15 @@ mod tests {
|
|||
// Invalid consent token
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorise_reject(&ident, &uat, "not a token", ct)
|
||||
.check_oauth2_authorise_reject(&ident, "not a token", ct)
|
||||
.unwrap_err()
|
||||
== OperationError::CryptographyError
|
||||
);
|
||||
|
||||
// Wrong UAT
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorise_reject(&ident, &uat2, &consent_token, ct)
|
||||
.unwrap_err()
|
||||
== OperationError::InvalidSessionState
|
||||
);
|
||||
// Wrong ident
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorise_reject(&ident2, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_reject(&ident2, &consent_token, ct)
|
||||
.unwrap_err()
|
||||
== OperationError::InvalidSessionState
|
||||
);
|
||||
|
@ -3529,7 +3529,7 @@ mod tests {
|
|||
_idms_delayed: &mut IdmServerDelayed,
|
||||
) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
let client_authz =
|
||||
Some(general_purpose::STANDARD.encode(format!("test_resource_server:{secret}")));
|
||||
|
@ -3541,7 +3541,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -3559,7 +3558,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// == Submit the token exchange code.
|
||||
|
@ -3712,7 +3711,7 @@ mod tests {
|
|||
// we run the same test as test_idm_oauth2_openid_extensions()
|
||||
// but change the preferred_username setting on the RS
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, true).await;
|
||||
let client_authz =
|
||||
Some(general_purpose::STANDARD.encode(format!("test_resource_server:{secret}")));
|
||||
|
@ -3724,7 +3723,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -3742,7 +3740,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// == Submit the token exchange code.
|
||||
|
@ -3801,7 +3799,7 @@ mod tests {
|
|||
// we run the same test as test_idm_oauth2_openid_extensions()
|
||||
// but change the preferred_username setting on the RS
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, true).await;
|
||||
let client_authz =
|
||||
Some(general_purpose::STANDARD.encode(format!("test_resource_server:{secret}")));
|
||||
|
@ -3813,7 +3811,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
"openid groups".to_string()
|
||||
|
@ -3831,7 +3828,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// == Submit the token exchange code.
|
||||
|
@ -3898,7 +3895,7 @@ mod tests {
|
|||
#[idm_test]
|
||||
async fn test_idm_oauth2_insecure_pkce(idms: &IdmServer, _idms_delayed: &mut IdmServerDelayed) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (_secret, uat, ident, _) =
|
||||
let (_secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, false, false, false).await;
|
||||
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
|
@ -3910,7 +3907,6 @@ mod tests {
|
|||
let _consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -3930,7 +3926,7 @@ mod tests {
|
|||
};
|
||||
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.expect("Oauth2 authorisation failed");
|
||||
}
|
||||
|
||||
|
@ -3940,7 +3936,7 @@ mod tests {
|
|||
_idms_delayed: &mut IdmServerDelayed,
|
||||
) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, false, true, false).await;
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
// The public key url should offer an rs key
|
||||
|
@ -3977,7 +3973,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -3995,7 +3990,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// == Submit the token exchange code.
|
||||
|
@ -4052,7 +4047,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -4071,7 +4065,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let _permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
@ -4081,14 +4075,13 @@ mod tests {
|
|||
|
||||
// We need to reload our identity
|
||||
let ident = idms_prox_read
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
|
||||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -4134,7 +4127,7 @@ mod tests {
|
|||
|
||||
// We need to reload our identity
|
||||
let ident = idms_prox_read
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
|
||||
|
@ -4155,7 +4148,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let consent_request = idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.expect("Oauth2 authorisation failed");
|
||||
|
||||
// Should be in the consent phase;
|
||||
|
@ -4194,7 +4187,7 @@ mod tests {
|
|||
|
||||
// We need to reload our identity
|
||||
let ident = idms_prox_read
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
|
||||
|
@ -4216,7 +4209,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let consent_request = idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.expect("Oauth2 authorisation failed");
|
||||
|
||||
// Should be present in the consent phase however!
|
||||
|
@ -4251,7 +4244,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -4270,11 +4262,11 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let _permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
// Assert that the ident now has the consents.
|
||||
|
@ -4295,7 +4287,7 @@ mod tests {
|
|||
assert!(idms_prox_write.qs_write.delete(&de).is_ok());
|
||||
// Assert the consent maps are gone.
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
dbg!(&o2rs_uuid);
|
||||
dbg!(&ident);
|
||||
|
@ -4332,7 +4324,7 @@ mod tests {
|
|||
) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
// Enable pkce is set to FALSE
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, false, false, false).await;
|
||||
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
|
@ -4357,7 +4349,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let consent_request = idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.expect("Failed to perform OAuth2 authorisation request.");
|
||||
|
||||
// Should be in the consent phase;
|
||||
|
@ -4373,7 +4365,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// == Submit the token exchange code.
|
||||
|
@ -4409,7 +4401,7 @@ mod tests {
|
|||
) {
|
||||
let ct = Duration::from_secs(TEST_CURRENT_TIME);
|
||||
// Enable pkce is set to FALSE
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, false, false, false).await;
|
||||
|
||||
let idms_prox_read = idms.proxy_read().await;
|
||||
|
@ -4438,7 +4430,7 @@ mod tests {
|
|||
|
||||
assert!(
|
||||
idms_prox_read
|
||||
.check_oauth2_authorisation(&ident, &uat, &auth_req, ct)
|
||||
.check_oauth2_authorisation(&ident, &auth_req, ct)
|
||||
.unwrap_err()
|
||||
== Oauth2Error::InvalidOrigin
|
||||
);
|
||||
|
@ -4447,7 +4439,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -4466,7 +4457,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
// == Submit the token exchange code.
|
||||
|
@ -4497,7 +4488,7 @@ mod tests {
|
|||
ct: Duration,
|
||||
) -> (AccessTokenResponse, Option<String>) {
|
||||
// First, setup to get a token.
|
||||
let (secret, uat, ident, _) =
|
||||
let (secret, _uat, ident, _) =
|
||||
setup_oauth2_resource_server_basic(idms, ct, true, false, false).await;
|
||||
let client_authz =
|
||||
Some(general_purpose::STANDARD.encode(format!("test_resource_server:{secret}")));
|
||||
|
@ -4509,7 +4500,6 @@ mod tests {
|
|||
let consent_request = good_authorisation_request!(
|
||||
idms_prox_read,
|
||||
&ident,
|
||||
&uat,
|
||||
ct,
|
||||
code_challenge,
|
||||
OAUTH2_SCOPE_OPENID.to_string()
|
||||
|
@ -4527,7 +4517,7 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let permit_success = idms_prox_write
|
||||
.check_oauth2_authorise_permit(&ident, &uat, &consent_token, ct)
|
||||
.check_oauth2_authorise_permit(&ident, &consent_token, ct)
|
||||
.expect("Failed to perform OAuth2 permit");
|
||||
|
||||
let token_req: AccessTokenRequest = GrantTypeReq::AuthorizationCode {
|
||||
|
|
|
@ -23,7 +23,7 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
ident: Identity,
|
||||
issue: AuthIssueSession,
|
||||
ct: Duration,
|
||||
source: Source,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
) -> Result<AuthResult, OperationError> {
|
||||
// re-auth only works on users, so lets get the user account.
|
||||
// hint - it's in the ident!
|
||||
|
@ -135,7 +135,7 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
issue,
|
||||
webauthn: self.webauthn,
|
||||
ct,
|
||||
source,
|
||||
client_auth_info,
|
||||
};
|
||||
let (auth_session, state) =
|
||||
AuthSession::new_reauth(asd, ident.session_id, session, session_cred_id);
|
||||
|
@ -330,7 +330,9 @@ mod tests {
|
|||
|
||||
let auth_init = AuthEvent::named_init("testperson");
|
||||
|
||||
let r1 = idms_auth.auth(&auth_init, ct, Source::Internal).await;
|
||||
let r1 = idms_auth
|
||||
.auth(&auth_init, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r1.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -341,7 +343,9 @@ mod tests {
|
|||
|
||||
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::Passkey);
|
||||
|
||||
let r2 = idms_auth.auth(&auth_begin, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&auth_begin, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -363,7 +367,9 @@ mod tests {
|
|||
|
||||
let passkey_step = AuthEvent::cred_step_passkey(sessionid, resp);
|
||||
|
||||
let r3 = idms_auth.auth(&passkey_step, ct, Source::Internal).await;
|
||||
let r3 = idms_auth
|
||||
.auth(&passkey_step, ct, Source::Internal.into())
|
||||
.await;
|
||||
debug!("r3 ==> {:?}", r3);
|
||||
idms_auth.commit().expect("Must not fail");
|
||||
|
||||
|
@ -403,7 +409,9 @@ mod tests {
|
|||
|
||||
let auth_init = AuthEvent::named_init("testperson");
|
||||
|
||||
let r1 = idms_auth.auth(&auth_init, ct, Source::Internal).await;
|
||||
let r1 = idms_auth
|
||||
.auth(&auth_init, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r1.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -414,7 +422,9 @@ mod tests {
|
|||
|
||||
let auth_begin = AuthEvent::begin_mech(sessionid, AuthMech::PasswordMfa);
|
||||
|
||||
let r2 = idms_auth.auth(&auth_begin, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&auth_begin, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -425,7 +435,9 @@ mod tests {
|
|||
.expect("Failed to perform totp step");
|
||||
|
||||
let totp_step = AuthEvent::cred_step_totp(sessionid, totp);
|
||||
let r2 = idms_auth.auth(&totp_step, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&totp_step, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -434,7 +446,7 @@ mod tests {
|
|||
let pw_step = AuthEvent::cred_step_password(sessionid, pw);
|
||||
|
||||
// Expect success
|
||||
let r3 = idms_auth.auth(&pw_step, ct, Source::Internal).await;
|
||||
let r3 = idms_auth.auth(&pw_step, ct, Source::Internal.into()).await;
|
||||
debug!("r3 ==> {:?}", r3);
|
||||
idms_auth.commit().expect("Must not fail");
|
||||
|
||||
|
@ -457,11 +469,15 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
async fn token_to_ident(idms: &IdmServer, ct: Duration, token: Option<&str>) -> Identity {
|
||||
async fn token_to_ident(
|
||||
idms: &IdmServer,
|
||||
ct: Duration,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
) -> Identity {
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
|
||||
idms_prox_read
|
||||
.validate_and_parse_token_to_ident(token, ct)
|
||||
.validate_client_auth_info_to_ident(client_auth_info, ct)
|
||||
.expect("Invalid UAT")
|
||||
}
|
||||
|
||||
|
@ -476,7 +492,12 @@ mod tests {
|
|||
let origin = idms_auth.get_origin().clone();
|
||||
|
||||
let auth_allowed = idms_auth
|
||||
.reauth_init(ident.clone(), AuthIssueSession::Token, ct, Source::Internal)
|
||||
.reauth_init(
|
||||
ident.clone(),
|
||||
AuthIssueSession::Token,
|
||||
ct,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to start reauth.");
|
||||
|
||||
|
@ -500,7 +521,9 @@ mod tests {
|
|||
|
||||
let passkey_step = AuthEvent::cred_step_passkey(sessionid, resp);
|
||||
|
||||
let r3 = idms_auth.auth(&passkey_step, ct, Source::Internal).await;
|
||||
let r3 = idms_auth
|
||||
.auth(&passkey_step, ct, Source::Internal.into())
|
||||
.await;
|
||||
debug!("r3 ==> {:?}", r3);
|
||||
idms_auth.commit().expect("Must not fail");
|
||||
|
||||
|
@ -535,7 +558,12 @@ mod tests {
|
|||
let mut idms_auth = idms.auth().await;
|
||||
|
||||
let auth_allowed = idms_auth
|
||||
.reauth_init(ident.clone(), AuthIssueSession::Token, ct, Source::Internal)
|
||||
.reauth_init(
|
||||
ident.clone(),
|
||||
AuthIssueSession::Token,
|
||||
ct,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to start reauth.");
|
||||
|
||||
|
@ -560,7 +588,9 @@ mod tests {
|
|||
.expect("Failed to perform totp step");
|
||||
|
||||
let totp_step = AuthEvent::cred_step_totp(sessionid, totp);
|
||||
let r2 = idms_auth.auth(&totp_step, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&totp_step, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -569,7 +599,7 @@ mod tests {
|
|||
let pw_step = AuthEvent::cred_step_password(sessionid, pw);
|
||||
|
||||
// Expect success
|
||||
let r3 = idms_auth.auth(&pw_step, ct, Source::Internal).await;
|
||||
let r3 = idms_auth.auth(&pw_step, ct, Source::Internal.into()).await;
|
||||
debug!("r3 ==> {:?}", r3);
|
||||
idms_auth.commit().expect("Must not fail");
|
||||
|
||||
|
@ -601,7 +631,7 @@ mod tests {
|
|||
.expect("failed to authenticate with passkey");
|
||||
|
||||
// Token_str to uat
|
||||
let ident = token_to_ident(idms, ct, Some(token.as_str())).await;
|
||||
let ident = token_to_ident(idms, ct, token.as_str().into()).await;
|
||||
|
||||
// Check that the rw entitlement is not present
|
||||
debug!(?ident);
|
||||
|
@ -620,7 +650,7 @@ mod tests {
|
|||
.expect("Failed to get new session token");
|
||||
|
||||
// Token_str to uat
|
||||
let ident = token_to_ident(idms, ct, Some(token.as_str())).await;
|
||||
let ident = token_to_ident(idms, ct, token.as_str().into()).await;
|
||||
|
||||
// They now have the entitlement.
|
||||
debug!(?ident);
|
||||
|
@ -647,7 +677,7 @@ mod tests {
|
|||
.expect("failed to authenticate with passkey");
|
||||
|
||||
// Token_str to uat
|
||||
let ident = token_to_ident(idms, ct, Some(token.as_str())).await;
|
||||
let ident = token_to_ident(idms, ct, token.as_str().into()).await;
|
||||
|
||||
// Check that the rw entitlement is not present
|
||||
debug!(?ident);
|
||||
|
|
|
@ -1594,7 +1594,7 @@ mod tests {
|
|||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_sync_token_to_ident(Some(sync_token.as_str()), ct)
|
||||
.validate_sync_client_auth_info_to_ident(sync_token.as_str().into(), ct)
|
||||
.expect("Failed to validate sync token");
|
||||
|
||||
assert!(Some(sync_uuid) == ident.get_uuid());
|
||||
|
@ -1650,7 +1650,7 @@ mod tests {
|
|||
// -- Check the happy path.
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
let ident = idms_prox_read
|
||||
.validate_and_parse_sync_token_to_ident(Some(sync_token.as_str()), ct)
|
||||
.validate_sync_client_auth_info_to_ident(sync_token.as_str().into(), ct)
|
||||
.expect("Failed to validate sync token");
|
||||
assert!(Some(sync_uuid) == ident.get_uuid());
|
||||
drop(idms_prox_read);
|
||||
|
@ -1671,7 +1671,7 @@ mod tests {
|
|||
// Must fail
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
let fail =
|
||||
idms_prox_read.validate_and_parse_sync_token_to_ident(Some(sync_token.as_str()), ct);
|
||||
idms_prox_read.validate_sync_client_auth_info_to_ident(sync_token.as_str().into(), ct);
|
||||
assert!(matches!(fail, Err(OperationError::NotAuthenticated)));
|
||||
drop(idms_prox_read);
|
||||
|
||||
|
@ -1695,7 +1695,7 @@ mod tests {
|
|||
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
let fail =
|
||||
idms_prox_read.validate_and_parse_sync_token_to_ident(Some(sync_token.as_str()), ct);
|
||||
idms_prox_read.validate_sync_client_auth_info_to_ident(sync_token.as_str().into(), ct);
|
||||
assert!(matches!(fail, Err(OperationError::NotAuthenticated)));
|
||||
|
||||
// -- Forge a session, use wrong types
|
||||
|
@ -1737,8 +1737,8 @@ mod tests {
|
|||
.map(|jws_signed| jws_signed.to_string())
|
||||
.expect("Unable to sign forged token");
|
||||
|
||||
let fail =
|
||||
idms_prox_read.validate_and_parse_sync_token_to_ident(Some(forged_token.as_str()), ct);
|
||||
let fail = idms_prox_read
|
||||
.validate_sync_client_auth_info_to_ident(forged_token.as_str().into(), ct);
|
||||
assert!(matches!(fail, Err(OperationError::NotAuthenticated)));
|
||||
}
|
||||
|
||||
|
@ -1770,7 +1770,7 @@ mod tests {
|
|||
.expect("failed to generate new scim sync token");
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_sync_token_to_ident(Some(sync_token.as_str()), ct)
|
||||
.validate_sync_client_auth_info_to_ident(sync_token.as_str().into(), ct)
|
||||
.expect("Failed to process sync token to ident");
|
||||
|
||||
(sync_uuid, ident)
|
||||
|
|
|
@ -407,27 +407,63 @@ pub trait IdmServerTransaction<'a> {
|
|||
/// that we internally sign with. We can use this to select the appropriate token type
|
||||
/// and validation method.
|
||||
#[instrument(level = "info", skip_all)]
|
||||
fn validate_and_parse_token_to_ident(
|
||||
fn validate_client_auth_info_to_ident(
|
||||
&mut self,
|
||||
token: Option<&str>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
ct: Duration,
|
||||
) -> Result<Identity, OperationError> {
|
||||
match self.validate_and_parse_token_to_token(token, ct)? {
|
||||
Token::UserAuthToken(uat) => self.process_uat_to_identity(&uat, ct),
|
||||
Token::ApiToken(apit, entry) => self.process_apit_to_identity(&apit, entry, ct),
|
||||
let ClientAuthInfo {
|
||||
client_cert,
|
||||
bearer_token,
|
||||
source,
|
||||
} = client_auth_info;
|
||||
|
||||
match (client_cert, bearer_token) {
|
||||
(Some(_client_cert_info), _) => {
|
||||
// TODO: Cert validation here.
|
||||
warn!("Unable to process client certificate identity");
|
||||
Err(OperationError::NotAuthenticated)
|
||||
}
|
||||
(None, Some(token)) => match self.validate_and_parse_token_to_token(&token, ct)? {
|
||||
Token::UserAuthToken(uat) => self.process_uat_to_identity(&uat, ct, source),
|
||||
Token::ApiToken(apit, entry) => {
|
||||
self.process_apit_to_identity(&apit, source, entry, ct)
|
||||
}
|
||||
},
|
||||
(None, None) => {
|
||||
warn!("No client certificate or bearer tokens were supplied");
|
||||
Err(OperationError::NotAuthenticated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip_all)]
|
||||
fn validate_and_parse_token_to_uat(
|
||||
fn validate_client_auth_info_to_uat(
|
||||
&mut self,
|
||||
token: Option<&str>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
ct: Duration,
|
||||
) -> Result<UserAuthToken, OperationError> {
|
||||
match self.validate_and_parse_token_to_token(token, ct)? {
|
||||
Token::UserAuthToken(uat) => Ok(uat),
|
||||
Token::ApiToken(_apit, _entry) => {
|
||||
warn!("Unable to process non user auth token");
|
||||
let ClientAuthInfo {
|
||||
client_cert,
|
||||
bearer_token,
|
||||
source: _,
|
||||
} = client_auth_info;
|
||||
|
||||
match (client_cert, bearer_token) {
|
||||
(Some(_client_cert_info), _) => {
|
||||
// TODO: Cert validation here.
|
||||
warn!("Unable to process client certificate identity");
|
||||
Err(OperationError::NotAuthenticated)
|
||||
}
|
||||
(None, Some(token)) => match self.validate_and_parse_token_to_token(&token, ct)? {
|
||||
Token::UserAuthToken(uat) => Ok(uat),
|
||||
Token::ApiToken(_apit, _entry) => {
|
||||
warn!("Unable to process non user auth token");
|
||||
Err(OperationError::NotAuthenticated)
|
||||
}
|
||||
},
|
||||
(None, None) => {
|
||||
warn!("No client certificate or bearer tokens were supplied");
|
||||
Err(OperationError::NotAuthenticated)
|
||||
}
|
||||
}
|
||||
|
@ -435,20 +471,13 @@ pub trait IdmServerTransaction<'a> {
|
|||
|
||||
fn validate_and_parse_token_to_token(
|
||||
&mut self,
|
||||
token: Option<&str>,
|
||||
token: &str,
|
||||
ct: Duration,
|
||||
) -> Result<Token, OperationError> {
|
||||
let jwsu = token
|
||||
.ok_or_else(|| {
|
||||
security_info!("No token provided");
|
||||
OperationError::NotAuthenticated
|
||||
})
|
||||
.and_then(|s| {
|
||||
JwsCompact::from_str(s).map_err(|e| {
|
||||
security_info!(?e, "Unable to decode token");
|
||||
OperationError::NotAuthenticated
|
||||
})
|
||||
})?;
|
||||
let jwsu = JwsCompact::from_str(token).map_err(|e| {
|
||||
security_info!(?e, "Unable to decode token");
|
||||
OperationError::NotAuthenticated
|
||||
})?;
|
||||
|
||||
// Frow the unverified token we can now get the kid, and use that to locate the correct
|
||||
// key to id the token.
|
||||
|
@ -692,6 +721,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
&mut self,
|
||||
uat: &UserAuthToken,
|
||||
ct: Duration,
|
||||
source: Source,
|
||||
) -> Result<Identity, OperationError> {
|
||||
// From a UAT, get the current identity and associated information.
|
||||
let entry = self
|
||||
|
@ -744,6 +774,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
|
||||
Ok(Identity {
|
||||
origin: IdentType::User(IdentUser { entry }),
|
||||
source,
|
||||
session_id: uat.session_id,
|
||||
scope,
|
||||
limits,
|
||||
|
@ -754,6 +785,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
fn process_apit_to_identity(
|
||||
&mut self,
|
||||
apit: &ApiToken,
|
||||
source: Source,
|
||||
entry: Arc<EntrySealedCommitted>,
|
||||
ct: Duration,
|
||||
) -> Result<Identity, OperationError> {
|
||||
|
@ -769,6 +801,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
let limits = Limits::default();
|
||||
Ok(Identity {
|
||||
origin: IdentType::User(IdentUser { entry }),
|
||||
source,
|
||||
session_id: apit.token_id,
|
||||
scope,
|
||||
limits,
|
||||
|
@ -779,6 +812,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
fn validate_ldap_session(
|
||||
&mut self,
|
||||
session: &LdapSession,
|
||||
source: Source,
|
||||
ct: Duration,
|
||||
) -> Result<Identity, OperationError> {
|
||||
match session {
|
||||
|
@ -815,6 +849,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
|
||||
Ok(Identity {
|
||||
origin: IdentType::User(IdentUser { entry: anon_entry }),
|
||||
source,
|
||||
session_id,
|
||||
scope: AccessScope::ReadOnly,
|
||||
limits,
|
||||
|
@ -824,7 +859,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
Err(OperationError::SessionExpired)
|
||||
}
|
||||
}
|
||||
LdapSession::UserAuthToken(uat) => self.process_uat_to_identity(uat, ct),
|
||||
LdapSession::UserAuthToken(uat) => self.process_uat_to_identity(uat, ct, source),
|
||||
LdapSession::ApiToken(apit) => {
|
||||
let entry = self
|
||||
.get_qs_txn()
|
||||
|
@ -834,24 +869,27 @@ pub trait IdmServerTransaction<'a> {
|
|||
e
|
||||
})?;
|
||||
|
||||
self.process_apit_to_identity(apit, entry, ct)
|
||||
self.process_apit_to_identity(apit, source, entry, ct)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip_all)]
|
||||
fn validate_and_parse_sync_token_to_ident(
|
||||
fn validate_sync_client_auth_info_to_ident(
|
||||
&mut self,
|
||||
token: Option<&str>,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
ct: Duration,
|
||||
) -> Result<Identity, OperationError> {
|
||||
let jwsu = token
|
||||
// FUTURE: Could allow mTLS here instead?
|
||||
|
||||
let jwsu = client_auth_info
|
||||
.bearer_token
|
||||
.ok_or_else(|| {
|
||||
security_info!("No token provided");
|
||||
OperationError::NotAuthenticated
|
||||
})
|
||||
.and_then(|s| {
|
||||
JwsCompact::from_str(s).map_err(|e| {
|
||||
JwsCompact::from_str(s.as_str()).map_err(|e| {
|
||||
security_info!(?e, "Unable to decode token");
|
||||
OperationError::NotAuthenticated
|
||||
})
|
||||
|
@ -921,6 +959,7 @@ pub trait IdmServerTransaction<'a> {
|
|||
let limits = Limits::unlimited();
|
||||
Ok(Identity {
|
||||
origin: IdentType::Synch(entry.get_uuid()),
|
||||
source: client_auth_info.source,
|
||||
session_id: sync_token.token_id,
|
||||
scope,
|
||||
limits,
|
||||
|
@ -969,7 +1008,7 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
&mut self,
|
||||
ae: &AuthEvent,
|
||||
ct: Duration,
|
||||
source: Source,
|
||||
client_auth_info: ClientAuthInfo,
|
||||
) -> Result<AuthResult, OperationError> {
|
||||
// Match on the auth event, to see what we need to do.
|
||||
match &ae.step {
|
||||
|
@ -1051,7 +1090,7 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
issue: init.issue,
|
||||
webauthn: self.webauthn,
|
||||
ct,
|
||||
source,
|
||||
client_auth_info,
|
||||
};
|
||||
|
||||
let (auth_session, state) = AuthSession::new(asd, init.privileged);
|
||||
|
@ -1289,7 +1328,7 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
lae: &LdapTokenAuthEvent,
|
||||
ct: Duration,
|
||||
) -> Result<Option<LdapBoundToken>, OperationError> {
|
||||
match self.validate_and_parse_token_to_token(Some(&lae.token), ct)? {
|
||||
match self.validate_and_parse_token_to_token(&lae.token, ct)? {
|
||||
Token::UserAuthToken(uat) => {
|
||||
let spn = uat.spn.clone();
|
||||
Ok(Some(LdapBoundToken {
|
||||
|
@ -2143,7 +2182,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_init,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
/* Some weird lifetime things happen here ... */
|
||||
|
@ -2185,7 +2224,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_begin,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -2227,7 +2266,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -2275,7 +2314,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -2318,7 +2357,9 @@ mod tests {
|
|||
let mut idms_auth = idms.auth().await;
|
||||
let admin_init = AuthEvent::named_init(name);
|
||||
|
||||
let r1 = idms_auth.auth(&admin_init, ct, Source::Internal).await;
|
||||
let r1 = idms_auth
|
||||
.auth(&admin_init, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r1.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2327,7 +2368,9 @@ mod tests {
|
|||
// Now push that we want the Password Mech.
|
||||
let admin_begin = AuthEvent::begin_mech(sessionid, AuthMech::Password);
|
||||
|
||||
let r2 = idms_auth.auth(&admin_begin, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&admin_begin, ct, Source::Internal.into())
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
let AuthResult { sessionid, state } = ar;
|
||||
|
||||
|
@ -2356,7 +2399,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -2428,7 +2471,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -2483,7 +2526,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -2906,7 +2949,7 @@ mod tests {
|
|||
let mut idms_auth = idms.auth().await;
|
||||
let admin_init = AuthEvent::named_init("admin");
|
||||
let r1 = idms_auth
|
||||
.auth(&admin_init, time_low, Source::Internal)
|
||||
.auth(&admin_init, time_low, Source::Internal.into())
|
||||
.await;
|
||||
|
||||
let ar = r1.unwrap();
|
||||
|
@ -2928,7 +2971,7 @@ mod tests {
|
|||
let mut idms_auth = idms.auth().await;
|
||||
let admin_init = AuthEvent::named_init("admin");
|
||||
let r1 = idms_auth
|
||||
.auth(&admin_init, time_high, Source::Internal)
|
||||
.auth(&admin_init, time_high, Source::Internal.into())
|
||||
.await;
|
||||
|
||||
let ar = r1.unwrap();
|
||||
|
@ -3081,7 +3124,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -3126,7 +3169,7 @@ mod tests {
|
|||
.auth(
|
||||
&admin_init,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
let ar = r1.unwrap();
|
||||
|
@ -3140,7 +3183,7 @@ mod tests {
|
|||
.auth(
|
||||
&admin_begin,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
let ar = r2.unwrap();
|
||||
|
@ -3177,7 +3220,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME + 2),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -3245,7 +3288,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -3288,7 +3331,7 @@ mod tests {
|
|||
.auth(
|
||||
&anon_step,
|
||||
Duration::from_secs(TEST_CURRENT_TIME),
|
||||
Source::Internal,
|
||||
Source::Internal.into(),
|
||||
)
|
||||
.await;
|
||||
debug!("r2 ==> {:?}", r2);
|
||||
|
@ -3394,11 +3437,11 @@ mod tests {
|
|||
|
||||
// Check it's valid - This is within the time window so will pass.
|
||||
idms_prox_read
|
||||
.validate_and_parse_token_to_ident(Some(token.as_str()), ct)
|
||||
.validate_client_auth_info_to_ident(token.as_str().into(), ct)
|
||||
.expect("Failed to validate");
|
||||
|
||||
// In X time it should be INVALID
|
||||
match idms_prox_read.validate_and_parse_token_to_ident(Some(token.as_str()), expiry) {
|
||||
match idms_prox_read.validate_client_auth_info_to_ident(token.as_str().into(), expiry) {
|
||||
Err(OperationError::SessionExpired) => {}
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
@ -3539,12 +3582,12 @@ mod tests {
|
|||
|
||||
// Check it's valid.
|
||||
idms_prox_read
|
||||
.validate_and_parse_token_to_ident(Some(token.as_str()), ct)
|
||||
.validate_client_auth_info_to_ident(token.as_str().into(), ct)
|
||||
.expect("Failed to validate");
|
||||
|
||||
// If the auth session record wasn't processed, this will fail.
|
||||
idms_prox_read
|
||||
.validate_and_parse_token_to_ident(Some(token.as_str()), post_grace)
|
||||
.validate_client_auth_info_to_ident(token.as_str().into(), post_grace)
|
||||
.expect("Failed to validate");
|
||||
|
||||
drop(idms_prox_read);
|
||||
|
@ -3560,7 +3603,7 @@ mod tests {
|
|||
|
||||
// Now, within gracewindow, it's NOT valid because the session entry exists and is in
|
||||
// the revoked state!
|
||||
match idms_prox_read.validate_and_parse_token_to_ident(Some(token.as_str()), post_grace) {
|
||||
match idms_prox_read.validate_client_auth_info_to_ident(token.as_str().into(), post_grace) {
|
||||
Err(OperationError::SessionExpired) => {}
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
@ -3585,11 +3628,11 @@ mod tests {
|
|||
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
idms_prox_read
|
||||
.validate_and_parse_token_to_ident(Some(token.as_str()), ct)
|
||||
.validate_client_auth_info_to_ident(token.as_str().into(), ct)
|
||||
.expect("Failed to validate");
|
||||
|
||||
// post grace, it's not valid.
|
||||
match idms_prox_read.validate_and_parse_token_to_ident(Some(token.as_str()), post_grace) {
|
||||
match idms_prox_read.validate_client_auth_info_to_ident(token.as_str().into(), post_grace) {
|
||||
Err(OperationError::SessionExpired) => {}
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
@ -3623,7 +3666,9 @@ mod tests {
|
|||
// Send the initial auth event for initialising the session
|
||||
let anon_init = AuthEvent::anonymous_init();
|
||||
// Expect success
|
||||
let r1 = idms_auth.auth(&anon_init, ct, Source::Internal).await;
|
||||
let r1 = idms_auth
|
||||
.auth(&anon_init, ct, Source::Internal.into())
|
||||
.await;
|
||||
/* Some weird lifetime things happen here ... */
|
||||
|
||||
let sid = match r1 {
|
||||
|
@ -3657,7 +3702,9 @@ mod tests {
|
|||
let mut idms_auth = idms.auth().await;
|
||||
let anon_begin = AuthEvent::begin_mech(sid, AuthMech::Anonymous);
|
||||
|
||||
let r2 = idms_auth.auth(&anon_begin, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&anon_begin, ct, Source::Internal.into())
|
||||
.await;
|
||||
|
||||
match r2 {
|
||||
Ok(ar) => {
|
||||
|
@ -3692,7 +3739,9 @@ mod tests {
|
|||
let anon_step = AuthEvent::cred_step_anonymous(sid);
|
||||
|
||||
// Expect success
|
||||
let r2 = idms_auth.auth(&anon_step, ct, Source::Internal).await;
|
||||
let r2 = idms_auth
|
||||
.auth(&anon_step, ct, Source::Internal.into())
|
||||
.await;
|
||||
|
||||
let token = match r2 {
|
||||
Ok(ar) => {
|
||||
|
@ -3723,7 +3772,7 @@ mod tests {
|
|||
let Token::UserAuthToken(uat) = idms
|
||||
.proxy_read()
|
||||
.await
|
||||
.validate_and_parse_token_to_token(Some(&token), ct)
|
||||
.validate_and_parse_token_to_token(&token, ct)
|
||||
.expect("Must not fail")
|
||||
else {
|
||||
panic!("Unexpected auth token type for anonymous auth");
|
||||
|
@ -3761,7 +3810,7 @@ mod tests {
|
|||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
assert!(!ident.has_claim("authtype_anonymous"));
|
||||
|
@ -3780,7 +3829,7 @@ mod tests {
|
|||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
assert!(!ident.has_claim("authtype_unixpassword"));
|
||||
|
@ -3799,7 +3848,7 @@ mod tests {
|
|||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
assert!(!ident.has_claim("authtype_password"));
|
||||
|
@ -3818,7 +3867,7 @@ mod tests {
|
|||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
assert!(!ident.has_claim("authtype_generatedpassword"));
|
||||
|
@ -3837,7 +3886,7 @@ mod tests {
|
|||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
assert!(!ident.has_claim("authtype_webauthn"));
|
||||
|
@ -3856,7 +3905,7 @@ mod tests {
|
|||
)
|
||||
.expect("Unable to create uat");
|
||||
let ident = idms_prox_write
|
||||
.process_uat_to_identity(&uat, ct)
|
||||
.process_uat_to_identity(&uat, ct, Source::Internal)
|
||||
.expect("Unable to process uat");
|
||||
|
||||
assert!(!ident.has_claim("authtype_passwordmfa"));
|
||||
|
@ -3887,7 +3936,7 @@ mod tests {
|
|||
|
||||
// Check it's valid.
|
||||
idms_prox_read
|
||||
.validate_and_parse_token_to_ident(Some(token.as_str()), ct)
|
||||
.validate_client_auth_info_to_ident(token.as_str().into(), ct)
|
||||
.expect("Failed to validate");
|
||||
|
||||
drop(idms_prox_read);
|
||||
|
@ -3918,11 +3967,11 @@ mod tests {
|
|||
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
assert!(idms_prox_read
|
||||
.validate_and_parse_token_to_ident(Some(token.as_str()), ct)
|
||||
.validate_client_auth_info_to_ident(token.as_str().into(), ct)
|
||||
.is_err());
|
||||
// A new token will work due to the matching key.
|
||||
idms_prox_read
|
||||
.validate_and_parse_token_to_ident(Some(new_token.as_str()), ct)
|
||||
.validate_client_auth_info_to_ident(new_token.as_str().into(), ct)
|
||||
.expect("Failed to validate");
|
||||
}
|
||||
|
||||
|
|
|
@ -490,7 +490,7 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(Some(&api_token), ct)
|
||||
.validate_client_auth_info_to_ident(api_token.as_str().into(), ct)
|
||||
.expect("Unable to verify api token.");
|
||||
|
||||
assert!(ident.get_uuid() == Some(testaccount_uuid));
|
||||
|
@ -500,7 +500,7 @@ mod tests {
|
|||
// Check the expiry
|
||||
assert!(
|
||||
idms_prox_write
|
||||
.validate_and_parse_token_to_ident(Some(&api_token), post_exp)
|
||||
.validate_client_auth_info_to_ident(api_token.as_str().into(), post_exp)
|
||||
.expect_err("Should not succeed")
|
||||
== OperationError::SessionExpired
|
||||
);
|
||||
|
@ -515,14 +515,14 @@ mod tests {
|
|||
// Within gracewindow?
|
||||
// This is okay, because we are within the gracewindow.
|
||||
let ident = idms_prox_write
|
||||
.validate_and_parse_token_to_ident(Some(&api_token), ct)
|
||||
.validate_client_auth_info_to_ident(api_token.as_str().into(), ct)
|
||||
.expect("Unable to verify api token.");
|
||||
assert!(ident.get_uuid() == Some(testaccount_uuid));
|
||||
|
||||
// Past gracewindow?
|
||||
assert!(
|
||||
idms_prox_write
|
||||
.validate_and_parse_token_to_ident(Some(&api_token), past_grc)
|
||||
.validate_client_auth_info_to_ident(api_token.as_str().into(), past_grc)
|
||||
.expect_err("Should not succeed")
|
||||
== OperationError::SessionExpired
|
||||
);
|
||||
|
|
|
@ -89,6 +89,7 @@ pub mod prelude {
|
|||
FilterInvalid, FilterValid, FC,
|
||||
};
|
||||
pub use crate::idm::server::{IdmServer, IdmServerAudit, IdmServerDelayed};
|
||||
pub use crate::idm::{ClientAuthInfo, ClientCertInfo};
|
||||
pub use crate::modify::{
|
||||
m_assert, m_pres, m_purge, m_remove, Modify, ModifyInvalid, ModifyList, ModifyValid,
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::value::Session;
|
|||
pub enum Source {
|
||||
Internal,
|
||||
Https(IpAddr),
|
||||
// Ldaps,
|
||||
Ldaps(IpAddr),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
@ -102,7 +102,7 @@ impl From<&IdentType> for IdentityId {
|
|||
/// and other info that can assist with server decision making.
|
||||
pub struct Identity {
|
||||
pub origin: IdentType,
|
||||
// pub(crate) source:
|
||||
pub(crate) source: Source,
|
||||
// pub(crate) impersonate: bool,
|
||||
// In a way I guess these are session claims?
|
||||
pub(crate) session_id: Uuid,
|
||||
|
@ -131,9 +131,14 @@ impl std::fmt::Display for Identity {
|
|||
}
|
||||
|
||||
impl Identity {
|
||||
pub fn source(&self) -> &Source {
|
||||
&self.source
|
||||
}
|
||||
|
||||
pub fn from_internal() -> Self {
|
||||
Identity {
|
||||
origin: IdentType::Internal,
|
||||
source: Source::Internal,
|
||||
session_id: uuid!("00000000-0000-0000-0000-000000000000"),
|
||||
scope: AccessScope::ReadWrite,
|
||||
limits: Limits::unlimited(),
|
||||
|
@ -144,6 +149,7 @@ impl Identity {
|
|||
pub fn from_impersonate_entry_readonly(entry: Arc<Entry<EntrySealed, EntryCommitted>>) -> Self {
|
||||
Identity {
|
||||
origin: IdentType::User(IdentUser { entry }),
|
||||
source: Source::Internal,
|
||||
session_id: uuid!("00000000-0000-0000-0000-000000000000"),
|
||||
scope: AccessScope::ReadOnly,
|
||||
limits: Limits::unlimited(),
|
||||
|
@ -156,6 +162,7 @@ impl Identity {
|
|||
) -> Self {
|
||||
Identity {
|
||||
origin: IdentType::User(IdentUser { entry }),
|
||||
source: Source::Internal,
|
||||
session_id: uuid!("00000000-0000-0000-0000-000000000000"),
|
||||
scope: AccessScope::ReadWrite,
|
||||
limits: Limits::unlimited(),
|
||||
|
@ -213,6 +220,17 @@ impl Identity {
|
|||
}
|
||||
}
|
||||
|
||||
/// Indicate if the session associated with this identity has a session
|
||||
/// that can logout. Examples of sessions that *can not* logout are anonymous,
|
||||
/// tokens, or PIV sessions.
|
||||
pub fn can_logout(&self) -> bool {
|
||||
match &self.origin {
|
||||
IdentType::Internal => false,
|
||||
IdentType::User(u) => u.entry.get_uuid() != UUID_ANONYMOUS,
|
||||
IdentType::Synch(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_event_origin_id(&self) -> IdentityId {
|
||||
IdentityId::from(&self.origin)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue