mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Resolve kanidm-unix auth-test bug (#3405)
* Resolve kanidm-unix auth-test bug When reworking the unix daemon, we missed changing the auth-test tool to handle the new challenge-response flow correctly which would cause the session to disconnect. * Cleanup
This commit is contained in:
parent
f68906bf1b
commit
1f5ce2617d
|
@ -162,7 +162,7 @@ impl PersonOpt {
|
||||||
}
|
}
|
||||||
PersonPosix::SetPassword(aopt) => {
|
PersonPosix::SetPassword(aopt) => {
|
||||||
let client = aopt.copt.to_client(OpType::Write).await;
|
let client = aopt.copt.to_client(OpType::Write).await;
|
||||||
let password = match password_prompt("Enter new posix (sudo) password: ") {
|
let password = match password_prompt("Enter new posix (sudo) password") {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => {
|
None => {
|
||||||
println!("Passwords do not match");
|
println!("Passwords do not match");
|
||||||
|
|
|
@ -254,7 +254,7 @@ async fn do_password(
|
||||||
password.to_owned()
|
password.to_owned()
|
||||||
}
|
}
|
||||||
None => dialoguer::Password::new()
|
None => dialoguer::Password::new()
|
||||||
.with_prompt("Enter password: ")
|
.with_prompt("Enter password")
|
||||||
.interact()
|
.interact()
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
error!("Failed to create password prompt -- {:?}", e);
|
error!("Failed to create password prompt -- {:?}", e);
|
||||||
|
|
|
@ -29,11 +29,11 @@ impl Decoder for ClientCodec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encoder<ClientRequest> for ClientCodec {
|
impl Encoder<&ClientRequest> for ClientCodec {
|
||||||
type Error = IoError;
|
type Error = IoError;
|
||||||
|
|
||||||
fn encode(&mut self, msg: ClientRequest, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
fn encode(&mut self, msg: &ClientRequest, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||||
let data = serde_json::to_vec(&msg).map_err(|e| {
|
let data = serde_json::to_vec(msg).map_err(|e| {
|
||||||
error!("socket encoding error -> {:?}", e);
|
error!("socket encoding error -> {:?}", e);
|
||||||
IoError::new(ErrorKind::Other, "JSON encode error")
|
IoError::new(ErrorKind::Other, "JSON encode error")
|
||||||
})?;
|
})?;
|
||||||
|
@ -49,21 +49,36 @@ impl ClientCodec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn call_daemon_inner(
|
pub struct DaemonClient {
|
||||||
path: &str,
|
req_stream: Framed<UnixStream, ClientCodec>,
|
||||||
req: ClientRequest,
|
default_timeout: u64,
|
||||||
) -> Result<ClientResponse, Box<dyn Error>> {
|
}
|
||||||
trace!(?path, ?req);
|
|
||||||
let stream = UnixStream::connect(path).await?;
|
impl DaemonClient {
|
||||||
|
pub async fn new(path: &str, default_timeout: u64) -> Result<Self, Box<dyn Error>> {
|
||||||
|
trace!(?path);
|
||||||
|
let stream = UnixStream::connect(path).await.inspect_err(|e| {
|
||||||
|
error!(
|
||||||
|
"Unix socket stream setup error while connecting to {} -> {:?}",
|
||||||
|
path, e
|
||||||
|
);
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let req_stream = Framed::new(stream, ClientCodec::new());
|
||||||
|
|
||||||
trace!("connected");
|
trace!("connected");
|
||||||
|
|
||||||
let mut reqs = Framed::new(stream, ClientCodec::new());
|
Ok(DaemonClient {
|
||||||
|
req_stream,
|
||||||
|
default_timeout,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
reqs.send(req).await?;
|
async fn call_inner(&mut self, req: &ClientRequest) -> Result<ClientResponse, Box<dyn Error>> {
|
||||||
reqs.flush().await?;
|
self.req_stream.send(req).await?;
|
||||||
|
self.req_stream.flush().await?;
|
||||||
trace!("flushed, waiting ...");
|
trace!("flushed, waiting ...");
|
||||||
|
match self.req_stream.next().await {
|
||||||
match reqs.next().await {
|
|
||||||
Some(Ok(res)) => {
|
Some(Ok(res)) => {
|
||||||
debug!("Response -> {:?}", res);
|
debug!("Response -> {:?}", res);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
@ -75,13 +90,12 @@ async fn call_daemon_inner(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a call to kanidm_unixd via a unix socket at `path`
|
pub async fn call(
|
||||||
pub async fn call_daemon(
|
&mut self,
|
||||||
path: &str,
|
req: &ClientRequest,
|
||||||
req: ClientRequest,
|
timeout: Option<u64>,
|
||||||
timeout: u64,
|
|
||||||
) -> Result<ClientResponse, Box<dyn Error>> {
|
) -> Result<ClientResponse, Box<dyn Error>> {
|
||||||
let sleep = time::sleep(Duration::from_secs(timeout));
|
let sleep = time::sleep(Duration::from_secs(timeout.unwrap_or(self.default_timeout)));
|
||||||
tokio::pin!(sleep);
|
tokio::pin!(sleep);
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
@ -89,8 +103,9 @@ pub async fn call_daemon(
|
||||||
error!(?timeout, "Timed out making request to kanidm_unixd");
|
error!(?timeout, "Timed out making request to kanidm_unixd");
|
||||||
Err(Box::new(IoError::new(ErrorKind::Other, "timeout")))
|
Err(Box::new(IoError::new(ErrorKind::Other, "timeout")))
|
||||||
}
|
}
|
||||||
res = call_daemon_inner(path, req) => {
|
res = self.call_inner(req) => {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,17 +16,55 @@ extern crate tracing;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use kanidm_unix_common::client::call_daemon;
|
use kanidm_unix_common::client::DaemonClient;
|
||||||
use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
|
use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
|
||||||
use kanidm_unix_common::unix_config::KanidmUnixdConfig;
|
use kanidm_unix_common::unix_config::KanidmUnixdConfig;
|
||||||
use kanidm_unix_common::unix_proto::{
|
use kanidm_unix_common::unix_proto::{
|
||||||
ClientRequest, ClientResponse, PamAuthRequest, PamAuthResponse, PamServiceInfo,
|
ClientRequest, ClientResponse, PamAuthRequest, PamAuthResponse, PamServiceInfo,
|
||||||
};
|
};
|
||||||
// use std::io;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
include!("../opt/tool.rs");
|
include!("../opt/tool.rs");
|
||||||
|
|
||||||
|
macro_rules! setup_client {
|
||||||
|
() => {{
|
||||||
|
let Ok(cfg) =
|
||||||
|
KanidmUnixdConfig::new().read_options_from_optional_config(DEFAULT_CONFIG_PATH)
|
||||||
|
else {
|
||||||
|
error!("Failed to parse {}", DEFAULT_CONFIG_PATH);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Connecting to resolver ...");
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"Using kanidm_unixd socket path: {:?}",
|
||||||
|
cfg.sock_path.as_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
// see if the kanidm_unixd socket exists and quit if not
|
||||||
|
if !PathBuf::from(&cfg.sock_path).exists() {
|
||||||
|
error!(
|
||||||
|
"Failed to find unix socket at {}, quitting!",
|
||||||
|
cfg.sock_path.as_str()
|
||||||
|
);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
match DaemonClient::new(cfg.sock_path.as_str(), cfg.unix_sock_timeout).await {
|
||||||
|
Ok(dc) => dc,
|
||||||
|
Err(err) => {
|
||||||
|
error!(
|
||||||
|
"Failed to connect to resolver at {}-> {:?}",
|
||||||
|
cfg.sock_path.as_str(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> ExitCode {
|
async fn main() -> ExitCode {
|
||||||
let opt = KanidmUnixParser::parse();
|
let opt = KanidmUnixParser::parse();
|
||||||
|
@ -54,12 +92,7 @@ async fn main() -> ExitCode {
|
||||||
} => {
|
} => {
|
||||||
debug!("Starting PAM auth tester tool ...");
|
debug!("Starting PAM auth tester tool ...");
|
||||||
|
|
||||||
let Ok(cfg) =
|
let mut daemon_client = setup_client!();
|
||||||
KanidmUnixdConfig::new().read_options_from_optional_config(DEFAULT_CONFIG_PATH)
|
|
||||||
else {
|
|
||||||
error!("Failed to parse {}", DEFAULT_CONFIG_PATH);
|
|
||||||
return ExitCode::FAILURE;
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("Sending request for user {}", &account_id);
|
info!("Sending request for user {}", &account_id);
|
||||||
|
|
||||||
|
@ -72,7 +105,7 @@ async fn main() -> ExitCode {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
match call_daemon(cfg.sock_path.as_str(), req, cfg.unix_sock_timeout).await {
|
match daemon_client.call(&req, None).await {
|
||||||
Ok(r) => match r {
|
Ok(r) => match r {
|
||||||
ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Success) => {
|
ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Success) => {
|
||||||
println!("auth success!");
|
println!("auth success!");
|
||||||
|
@ -90,7 +123,7 @@ async fn main() -> ExitCode {
|
||||||
ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Password) => {
|
ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Password) => {
|
||||||
// Prompt for and get the password
|
// Prompt for and get the password
|
||||||
let cred = match dialoguer::Password::new()
|
let cred = match dialoguer::Password::new()
|
||||||
.with_prompt("Enter Unix password: ")
|
.with_prompt("Enter Unix password")
|
||||||
.interact()
|
.interact()
|
||||||
{
|
{
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
|
@ -133,7 +166,7 @@ async fn main() -> ExitCode {
|
||||||
|
|
||||||
let sereq = ClientRequest::PamAccountAllowed(account_id);
|
let sereq = ClientRequest::PamAccountAllowed(account_id);
|
||||||
|
|
||||||
match call_daemon(cfg.sock_path.as_str(), sereq, cfg.unix_sock_timeout).await {
|
match daemon_client.call(&sereq, None).await {
|
||||||
Ok(r) => match r {
|
Ok(r) => match r {
|
||||||
ClientResponse::PamStatus(Some(true)) => {
|
ClientResponse::PamStatus(Some(true)) => {
|
||||||
println!("account success!");
|
println!("account success!");
|
||||||
|
@ -158,15 +191,7 @@ async fn main() -> ExitCode {
|
||||||
KanidmUnixOpt::CacheClear { debug: _, really } => {
|
KanidmUnixOpt::CacheClear { debug: _, really } => {
|
||||||
debug!("Starting cache clear tool ...");
|
debug!("Starting cache clear tool ...");
|
||||||
|
|
||||||
let cfg = match KanidmUnixdConfig::new()
|
let mut daemon_client = setup_client!();
|
||||||
.read_options_from_optional_config(DEFAULT_CONFIG_PATH)
|
|
||||||
{
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(_e) => {
|
|
||||||
error!("Failed to parse {}", DEFAULT_CONFIG_PATH);
|
|
||||||
return ExitCode::FAILURE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if !really {
|
if !really {
|
||||||
error!("Are you sure you want to proceed? If so use --really");
|
error!("Are you sure you want to proceed? If so use --really");
|
||||||
|
@ -175,7 +200,7 @@ async fn main() -> ExitCode {
|
||||||
|
|
||||||
let req = ClientRequest::ClearCache;
|
let req = ClientRequest::ClearCache;
|
||||||
|
|
||||||
match call_daemon(cfg.sock_path.as_str(), req, cfg.unix_sock_timeout).await {
|
match daemon_client.call(&req, None).await {
|
||||||
Ok(r) => match r {
|
Ok(r) => match r {
|
||||||
ClientResponse::Ok => info!("success"),
|
ClientResponse::Ok => info!("success"),
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -192,19 +217,11 @@ async fn main() -> ExitCode {
|
||||||
KanidmUnixOpt::CacheInvalidate { debug: _ } => {
|
KanidmUnixOpt::CacheInvalidate { debug: _ } => {
|
||||||
debug!("Starting cache invalidate tool ...");
|
debug!("Starting cache invalidate tool ...");
|
||||||
|
|
||||||
let cfg = match KanidmUnixdConfig::new()
|
let mut daemon_client = setup_client!();
|
||||||
.read_options_from_optional_config(DEFAULT_CONFIG_PATH)
|
|
||||||
{
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(_e) => {
|
|
||||||
error!("Failed to parse {}", DEFAULT_CONFIG_PATH);
|
|
||||||
return ExitCode::FAILURE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let req = ClientRequest::InvalidateCache;
|
let req = ClientRequest::InvalidateCache;
|
||||||
|
|
||||||
match call_daemon(cfg.sock_path.as_str(), req, cfg.unix_sock_timeout).await {
|
match daemon_client.call(&req, None).await {
|
||||||
Ok(r) => match r {
|
Ok(r) => match r {
|
||||||
ClientResponse::Ok => info!("success"),
|
ClientResponse::Ok => info!("success"),
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -221,26 +238,10 @@ async fn main() -> ExitCode {
|
||||||
KanidmUnixOpt::Status { debug: _ } => {
|
KanidmUnixOpt::Status { debug: _ } => {
|
||||||
trace!("Starting cache status tool ...");
|
trace!("Starting cache status tool ...");
|
||||||
|
|
||||||
let cfg = match KanidmUnixdConfig::new()
|
let mut daemon_client = setup_client!();
|
||||||
.read_options_from_optional_config(DEFAULT_CONFIG_PATH)
|
|
||||||
{
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(_e) => {
|
|
||||||
error!("Failed to parse {}", DEFAULT_CONFIG_PATH);
|
|
||||||
return ExitCode::FAILURE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let req = ClientRequest::Status;
|
let req = ClientRequest::Status;
|
||||||
|
|
||||||
let spath = PathBuf::from(cfg.sock_path.as_str());
|
match daemon_client.call(&req, None).await {
|
||||||
if !spath.exists() {
|
|
||||||
error!(
|
|
||||||
"kanidm_unixd socket {} does not exist - is the service running?",
|
|
||||||
cfg.sock_path
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
match call_daemon(cfg.sock_path.as_str(), req, cfg.unix_sock_timeout).await {
|
|
||||||
Ok(r) => match r {
|
Ok(r) => match r {
|
||||||
ClientResponse::ProviderStatus(results) => {
|
ClientResponse::ProviderStatus(results) => {
|
||||||
for provider in results {
|
for provider in results {
|
||||||
|
@ -259,7 +260,6 @@ async fn main() -> ExitCode {
|
||||||
error!("Error -> {:?}", e);
|
error!("Error -> {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ExitCode::SUCCESS
|
ExitCode::SUCCESS
|
||||||
}
|
}
|
||||||
KanidmUnixOpt::Version { debug: _ } => {
|
KanidmUnixOpt::Version { debug: _ } => {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use std::path::PathBuf;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use kanidm_unix_common::client::call_daemon;
|
use kanidm_unix_common::client::DaemonClient;
|
||||||
use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
|
use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
|
||||||
use kanidm_unix_common::unix_config::KanidmUnixdConfig;
|
use kanidm_unix_common::unix_config::KanidmUnixdConfig;
|
||||||
use kanidm_unix_common::unix_proto::{ClientRequest, ClientResponse};
|
use kanidm_unix_common::unix_proto::{ClientRequest, ClientResponse};
|
||||||
|
@ -66,21 +66,37 @@ async fn main() -> ExitCode {
|
||||||
);
|
);
|
||||||
return ExitCode::FAILURE;
|
return ExitCode::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut daemon_client =
|
||||||
|
match DaemonClient::new(cfg.sock_path.as_str(), cfg.unix_sock_timeout).await {
|
||||||
|
Ok(dc) => dc,
|
||||||
|
Err(err) => {
|
||||||
|
error!(
|
||||||
|
"Failed to connect to resolver at {}-> {:?}",
|
||||||
|
cfg.sock_path.as_str(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// safe because we've already thrown an error if it's not there
|
// safe because we've already thrown an error if it's not there
|
||||||
let req = ClientRequest::SshKey(opt.account_id.unwrap_or("".to_string()));
|
let req = ClientRequest::SshKey(opt.account_id.unwrap_or("".to_string()));
|
||||||
|
|
||||||
match call_daemon(cfg.sock_path.as_str(), req, cfg.unix_sock_timeout).await {
|
match daemon_client.call(&req, None).await {
|
||||||
Ok(r) => match r {
|
Ok(ClientResponse::SshKeys(sk)) => {
|
||||||
ClientResponse::SshKeys(sk) => sk.iter().for_each(|k| {
|
sk.iter().for_each(|k| {
|
||||||
println!("{}", k);
|
println!("{}", k);
|
||||||
}),
|
});
|
||||||
_ => {
|
|
||||||
error!("Error calling kanidm_unixd: unexpected response -> {:?}", r);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
error!("Error calling kanidm_unixd -> {:?}", e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ExitCode::SUCCESS
|
ExitCode::SUCCESS
|
||||||
}
|
}
|
||||||
|
Ok(r) => {
|
||||||
|
error!("Error calling kanidm_unixd: unexpected response -> {:?}", r);
|
||||||
|
ExitCode::FAILURE
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error calling kanidm_unixd -> {:?}", e);
|
||||||
|
ExitCode::FAILURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue