more errors for the people (#3121)

This commit is contained in:
James Hodgkinson 2024-10-19 09:51:45 +10:00 committed by GitHub
parent dc5f40d404
commit 68119e1067
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 70 additions and 36 deletions

1
Cargo.lock generated
View file

@ -3369,6 +3369,7 @@ dependencies = [
"csv", "csv",
"futures", "futures",
"kanidm_build_profiles", "kanidm_build_profiles",
"kanidm_proto",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",

View file

@ -143,6 +143,11 @@ pub enum OperationError {
// Specific internal errors. // Specific internal errors.
// Kanidm Generic Errors
KG001TaskTimeout,
KG002TaskCommFailure,
KG003CacheClearFailed,
// What about something like this for unique errors? // What about something like this for unique errors?
// Credential Update Errors // Credential Update Errors
CU0001WebauthnAttestationNotTrusted, CU0001WebauthnAttestationNotTrusted,
@ -230,6 +235,14 @@ pub enum OperationError {
// Web UI // Web UI
UI0001ChallengeSerialisation, UI0001ChallengeSerialisation,
UI0002InvalidState, UI0002InvalidState,
// Unixd Things
KU001InitWhileSessionActive,
KU002ContinueWhileSessionInActive,
KU003PamAuthFailed,
KU004PamInitFailed,
KU005ErrorCheckingAccount,
KU006OnlyRootAllowed,
} }
impl PartialEq for OperationError { impl PartialEq for OperationError {
@ -324,29 +337,16 @@ impl OperationError {
Self::TransactionAlreadyCommitted => None, Self::TransactionAlreadyCommitted => None,
Self::ValueDenyName => None, Self::ValueDenyName => None,
Self::DatabaseLockAcquisitionTimeout => Some("Unable to acquire a database lock - the current server may be too busy. Try again later.".into()), Self::DatabaseLockAcquisitionTimeout => Some("Unable to acquire a database lock - the current server may be too busy. Try again later.".into()),
Self::CU0001WebauthnAttestationNotTrusted => None,
Self::CU0002WebauthnRegistrationError => None, Self::CU0002WebauthnRegistrationError => None,
Self::CU0003WebauthnUserNotVerified => Some("User Verification bit not set while registering credential, you may need to configure a PIN on this device.".into()), Self::CU0003WebauthnUserNotVerified => Some("User Verification bit not set while registering credential, you may need to configure a PIN on this device.".into()),
Self::CU0001WebauthnAttestationNotTrusted => None,
Self::VS0001IncomingReplSshPublicKey => None,
Self::VS0003CertificateDerDecode => Some("Decoding the stored certificate from DER failed.".into()),
Self::VS0002CertificatePublicKeyDigest |
Self::VS0004CertificatePublicKeyDigest |
Self::VS0005CertificatePublicKeyDigest => Some("The certificates public key is unabled to be digested.".into()),
Self::VL0001ValueSshPublicKeyString => None,
Self::LD0001AnonymousNotAllowed => Some("Anonymous is not allowed to access LDAP with this method.".into()),
Self::SC0001IncomingSshPublicKey => None,
Self::MG0001InvalidReMigrationLevel => None,
Self::MG0002RaiseDomainLevelExceedsMaximum => None,
Self::MG0003ServerPhaseInvalidForMigration => None,
Self::DB0001MismatchedRestoreVersion => None, Self::DB0001MismatchedRestoreVersion => None,
Self::DB0002MismatchedRestoreVersion => None, Self::DB0002MismatchedRestoreVersion => None,
Self::DB0003FilterResolveCacheBuild => None, Self::DB0003FilterResolveCacheBuild => None,
Self::DB0004DatabaseTooOld => Some("The database is too old to be migrated.".into()), Self::DB0004DatabaseTooOld => Some("The database is too old to be migrated.".into()),
Self::MG0004DomainLevelInDevelopment => None, Self::KG001TaskTimeout => Some("Task timed out".into()),
Self::MG0005GidConstraintsNotMet => None, Self::KG002TaskCommFailure => Some("Inter-Task communication failure".into()),
Self::MG0006SKConstraintsNotMet => Some("Migration Constraints Not Met - Security Keys should not be present.".into()), Self::KG003CacheClearFailed => Some("Failed to clear cache".into()),
Self::MG0007Oauth2StrictConstraintsNotMet => Some("Migration Constraints Not Met - All OAuth2 clients must have strict-redirect-uri mode enabled.".into()),
Self::MG0008SkipUpgradeAttempted => Some("Skip Upgrade Attempted.".into()),
Self::KP0001KeyProviderNotLoaded => None, Self::KP0001KeyProviderNotLoaded => None,
Self::KP0002KeyProviderInvalidClass => None, Self::KP0002KeyProviderInvalidClass => None,
Self::KP0003KeyProviderInvalidType => None, Self::KP0003KeyProviderInvalidType => None,
@ -392,9 +392,31 @@ impl OperationError {
Self::KP0042KeyObjectNoActiveEncryptionKeys => None, Self::KP0042KeyObjectNoActiveEncryptionKeys => None,
Self::KP0043KeyObjectJweA128GCMEncryption => None, Self::KP0043KeyObjectJweA128GCMEncryption => None,
Self::KP0044KeyObjectJwsPublicJwk => None, Self::KP0044KeyObjectJwsPublicJwk => None,
Self::KU001InitWhileSessionActive => Some("The session was active when the init function was called.".into()),
Self::KU002ContinueWhileSessionInActive => Some("Attempted to continue auth session while current session is inactive".into()),
Self::KU003PamAuthFailed => Some("Failed PAM account authentication step".into()),
Self::KU004PamInitFailed => Some("Failed to initialise PAM authentication".into()),
Self::KU005ErrorCheckingAccount => Some("Error checking account".into()),
Self::KU006OnlyRootAllowed => Some("Only root is allowed to perform this operation".into()),
Self::LD0001AnonymousNotAllowed => Some("Anonymous is not allowed to access LDAP with this method.".into()),
Self::MG0001InvalidReMigrationLevel => None,
Self::MG0002RaiseDomainLevelExceedsMaximum => None,
Self::MG0003ServerPhaseInvalidForMigration => None,
Self::MG0004DomainLevelInDevelopment => None,
Self::MG0005GidConstraintsNotMet => None,
Self::MG0006SKConstraintsNotMet => Some("Migration Constraints Not Met - Security Keys should not be present.".into()),
Self::MG0007Oauth2StrictConstraintsNotMet => Some("Migration Constraints Not Met - All OAuth2 clients must have strict-redirect-uri mode enabled.".into()),
Self::MG0008SkipUpgradeAttempted => Some("Skip Upgrade Attempted.".into()),
Self::PL0001GidOverlapsSystemRange => None, Self::PL0001GidOverlapsSystemRange => None,
Self::SC0001IncomingSshPublicKey => None,
Self::UI0001ChallengeSerialisation => Some("The WebAuthn challenge was unable to be serialised.".into()), Self::UI0001ChallengeSerialisation => Some("The WebAuthn challenge was unable to be serialised.".into()),
Self::UI0002InvalidState => Some("The credential update process returned an invalid state transition.".into()), Self::UI0002InvalidState => Some("The credential update process returned an invalid state transition.".into()),
Self::VL0001ValueSshPublicKeyString => None,
Self::VS0001IncomingReplSshPublicKey => None,
Self::VS0002CertificatePublicKeyDigest |
Self::VS0003CertificateDerDecode => Some("Decoding the stored certificate from DER failed.".into()),
Self::VS0004CertificatePublicKeyDigest |
Self::VS0005CertificatePublicKeyDigest => Some("The certificates public key is unabled to be digested.".into()),
} }
} }
} }

View file

@ -25,14 +25,15 @@ doctest = false
bytes = { workspace = true } bytes = { workspace = true }
csv = { workspace = true } csv = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
kanidm_proto = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true } serde_json = { workspace = true }
serde_with = { workspace = true } serde_with = { workspace = true }
toml = { workspace = true }
tokio = { workspace = true, features = ["time","net","macros"] }
tokio-util = { workspace = true, features = ["codec"] }
tracing = { workspace = true }
sha-crypt = { workspace = true } sha-crypt = { workspace = true }
tokio = { workspace = true, features = ["time", "net", "macros"] }
tokio-util = { workspace = true, features = ["codec"] }
toml = { workspace = true }
tracing = { workspace = true }
[build-dependencies] [build-dependencies]
kanidm_build_profiles = { workspace = true } kanidm_build_profiles = { workspace = true }

View file

@ -1,4 +1,5 @@
use crate::unix_passwd::{EtcGroup, EtcUser}; use crate::unix_passwd::{EtcGroup, EtcUser};
use kanidm_proto::internal::OperationError;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -177,7 +178,7 @@ pub enum ClientResponse {
ProviderStatus(Vec<ProviderStatus>), ProviderStatus(Vec<ProviderStatus>),
Ok, Ok,
Error, Error(OperationError),
} }
impl From<PamAuthResponse> for ClientResponse { impl From<PamAuthResponse> for ClientResponse {

View file

@ -298,8 +298,11 @@ pub fn sm_authenticate_connected<P: PamHandler>(
continue; continue;
} }
ClientResponse::Error(err) => {
error!("Error from kanidm-unixd: {}", err);
return PamResultCode::PAM_AUTH_ERR;
}
ClientResponse::Ok ClientResponse::Ok
| ClientResponse::Error
| ClientResponse::SshKeys(_) | ClientResponse::SshKeys(_)
| ClientResponse::NssAccounts(_) | ClientResponse::NssAccounts(_)
| ClientResponse::NssAccount(_) | ClientResponse::NssAccount(_)

View file

@ -103,6 +103,10 @@ async fn main() -> ExitCode {
}); });
continue; continue;
} }
ClientResponse::Error(err) => {
error!("Error from kanidm-unixd: {}", err);
break;
}
ClientResponse::PamAuthenticateStepResponse(_) ClientResponse::PamAuthenticateStepResponse(_)
| ClientResponse::SshKeys(_) | ClientResponse::SshKeys(_)
| ClientResponse::NssAccounts(_) | ClientResponse::NssAccounts(_)
@ -111,7 +115,6 @@ async fn main() -> ExitCode {
| ClientResponse::NssGroups(_) | ClientResponse::NssGroups(_)
| ClientResponse::ProviderStatus(_) | ClientResponse::ProviderStatus(_)
| ClientResponse::Ok | ClientResponse::Ok
| ClientResponse::Error
| ClientResponse::PamStatus(_) => { | ClientResponse::PamStatus(_) => {
// unexpected response. // unexpected response.
error!("Error: unexpected response -> {:?}", r); error!("Error: unexpected response -> {:?}", r);

View file

@ -26,6 +26,7 @@ use clap::{Arg, ArgAction, Command};
use futures::{SinkExt, StreamExt}; use futures::{SinkExt, StreamExt};
use kanidm_client::KanidmClientBuilder; use kanidm_client::KanidmClientBuilder;
use kanidm_proto::constants::DEFAULT_CLIENT_CONFIG_PATH; use kanidm_proto::constants::DEFAULT_CLIENT_CONFIG_PATH;
use kanidm_proto::internal::OperationError;
use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH; use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
use kanidm_unix_common::unix_passwd::{parse_etc_group, parse_etc_passwd, parse_etc_shadow}; use kanidm_unix_common::unix_passwd::{parse_etc_group, parse_etc_passwd, parse_etc_shadow};
use kanidm_unix_common::unix_proto::{ClientRequest, ClientResponse, TaskRequest, TaskResponse}; use kanidm_unix_common::unix_proto::{ClientRequest, ClientResponse, TaskRequest, TaskResponse};
@ -281,7 +282,7 @@ async fn handle_client(
warn!("Attempt to init auth session while current session is active"); warn!("Attempt to init auth session while current session is active");
// Clean the former session, something is wrong. // Clean the former session, something is wrong.
pam_auth_session_state = None; pam_auth_session_state = None;
ClientResponse::Error ClientResponse::Error(OperationError::KU001InitWhileSessionActive)
} }
None => { None => {
let current_time = OffsetDateTime::now_utc(); let current_time = OffsetDateTime::now_utc();
@ -299,7 +300,7 @@ async fn handle_client(
pam_auth_session_state = Some(auth_session); pam_auth_session_state = Some(auth_session);
pam_auth_response.into() pam_auth_response.into()
} }
Err(_) => ClientResponse::Error, Err(_) => ClientResponse::Error(OperationError::KU004PamInitFailed),
} }
} }
} }
@ -309,17 +310,19 @@ async fn handle_client(
.pam_account_authenticate_step(auth_session, pam_next_req) .pam_account_authenticate_step(auth_session, pam_next_req)
.await .await
.map(|pam_auth_response| pam_auth_response.into()) .map(|pam_auth_response| pam_auth_response.into())
.unwrap_or(ClientResponse::Error), .unwrap_or(ClientResponse::Error(OperationError::KU003PamAuthFailed)),
None => { None => {
warn!("Attempt to continue auth session while current session is inactive"); warn!("Attempt to continue auth session while current session is inactive");
ClientResponse::Error ClientResponse::Error(OperationError::KU002ContinueWhileSessionInActive)
} }
}, },
ClientRequest::PamAccountAllowed(account_id) => cachelayer ClientRequest::PamAccountAllowed(account_id) => cachelayer
.pam_account_allowed(account_id.as_str()) .pam_account_allowed(account_id.as_str())
.await .await
.map(ClientResponse::PamStatus) .map(ClientResponse::PamStatus)
.unwrap_or(ClientResponse::Error), .unwrap_or(ClientResponse::Error(
OperationError::KU005ErrorCheckingAccount,
)),
ClientRequest::PamAccountBeginSession(account_id) => { ClientRequest::PamAccountBeginSession(account_id) => {
match cachelayer match cachelayer
.pam_account_beginsession(account_id.as_str()) .pam_account_beginsession(account_id.as_str())
@ -349,13 +352,13 @@ async fn handle_client(
} }
_ => { _ => {
// Timeout or other error. // Timeout or other error.
ClientResponse::Error ClientResponse::Error(OperationError::KG001TaskTimeout)
} }
} }
} }
Err(_) => { Err(_) => {
// We could not submit the req. Move on! // We could not submit the req. Move on!
ClientResponse::Error ClientResponse::Error(OperationError::KG002TaskCommFailure)
} }
} }
} }
@ -363,24 +366,24 @@ async fn handle_client(
// The session can begin, but we do not need to create the home dir. // The session can begin, but we do not need to create the home dir.
ClientResponse::Ok ClientResponse::Ok
} }
_ => ClientResponse::Error, Err(_) => ClientResponse::Error(OperationError::KU005ErrorCheckingAccount),
} }
} }
ClientRequest::InvalidateCache => cachelayer ClientRequest::InvalidateCache => cachelayer
.invalidate() .invalidate()
.await .await
.map(|_| ClientResponse::Ok) .map(|_| ClientResponse::Ok)
.unwrap_or(ClientResponse::Error), .unwrap_or(ClientResponse::Error(OperationError::KG003CacheClearFailed)),
ClientRequest::ClearCache => { ClientRequest::ClearCache => {
if ucred.uid() == 0 { if ucred.uid() == 0 {
cachelayer cachelayer
.clear_cache() .clear_cache()
.await .await
.map(|_| ClientResponse::Ok) .map(|_| ClientResponse::Ok)
.unwrap_or(ClientResponse::Error) .unwrap_or(ClientResponse::Error(OperationError::KG003CacheClearFailed))
} else { } else {
error!("Only root may clear the cache"); error!("{}", OperationError::KU006OnlyRootAllowed);
ClientResponse::Error ClientResponse::Error(OperationError::KU006OnlyRootAllowed)
} }
} }
ClientRequest::Status => { ClientRequest::Status => {