From c4441c1fca4f5a98db5827b4f1fd9a1ddfbaf256 Mon Sep 17 00:00:00 2001 From: Firstyear Date: Sat, 21 Dec 2024 17:08:39 +1000 Subject: [PATCH] nss/pam resolver should reauth faster (#3309) This can have visible impacts on accounts that don't have a pam password cached yet, but then appear to "stall" for a minute or two until it works due to the fact that the provider was offline and waiting to reauth. When we are still connected but our provider auth session has expired we should reconnect faster. This reduces the timeout for reauthentication for the provider so that it can return to the online state sooner. We also loop when we detect the provider session is no longer authenticated so that we can reauth immediately, rather than causing a noticable interuption. --- .../resolver/src/idprovider/kanidm.rs | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/unix_integration/resolver/src/idprovider/kanidm.rs b/unix_integration/resolver/src/idprovider/kanidm.rs index b72fd289b..d0a6a8159 100644 --- a/unix_integration/resolver/src/idprovider/kanidm.rs +++ b/unix_integration/resolver/src/idprovider/kanidm.rs @@ -23,6 +23,7 @@ use kanidm_unix_common::unix_proto::PamAuthRequest; const KANIDM_HMAC_KEY: &str = "kanidm-hmac-key"; const KANIDM_PWV1_KEY: &str = "kanidm-pw-v1"; +// If the provider is offline, we need to backoff and wait a bit. const OFFLINE_NEXT_CHECK: Duration = Duration::from_secs(60); #[derive(Debug, Clone)] @@ -243,6 +244,7 @@ impl UserToken { } impl KanidmProviderInternal { + #[instrument(level = "debug", skip_all)] async fn check_online(&mut self, tpm: &mut tpm::BoxedDynTpm, now: SystemTime) -> bool { match self.state { // Proceed @@ -255,23 +257,35 @@ impl KanidmProviderInternal { } } + #[instrument(level = "debug", skip_all)] async fn attempt_online(&mut self, _tpm: &mut tpm::BoxedDynTpm, now: SystemTime) -> bool { - match self.client.auth_anonymous().await { - Ok(_uat) => { - self.state = CacheState::Online; - true - } - Err(ClientError::Transport(err)) => { - warn!(?err, "transport failure"); - self.state = CacheState::OfflineNextCheck(now + OFFLINE_NEXT_CHECK); - false - } - Err(err) => { - error!(?err, "Provider authentication failed"); - self.state = CacheState::OfflineNextCheck(now + OFFLINE_NEXT_CHECK); - false + let mut max_attempts = 3; + while max_attempts > 0 { + max_attempts -= 1; + match self.client.auth_anonymous().await { + Ok(_uat) => { + debug!("provider is now online"); + self.state = CacheState::Online; + return true; + } + Err(ClientError::Http(StatusCode::UNAUTHORIZED, reason, opid)) => { + error!(?reason, ?opid, "Provider authentication returned unauthorized, {max_attempts} attempts remaining."); + // Provider needs to re-auth ASAP. We set this state value here + // so that if we exceed max attempts, the next caller knows to check + // online immediately. + self.state = CacheState::OfflineNextCheck(now); + // attempt again immediately!!!! + continue; + } + Err(err) => { + error!(?err, "Provider online failed"); + self.state = CacheState::OfflineNextCheck(now + OFFLINE_NEXT_CHECK); + return false; + } } } + warn!("Exceeded maximum number of attempts to bring provider online"); + return false; } } @@ -351,7 +365,8 @@ impl IdProvider for KanidmProvider { e, opid ), }; - inner.state = CacheState::OfflineNextCheck(now + OFFLINE_NEXT_CHECK); + // Provider needs to re-auth ASAP + inner.state = CacheState::OfflineNextCheck(now); Ok(UserTokenState::UseCached) } // 404 / Removed.