From 8cf7f11269b9b0817ed3d2315fa5737528eba9dd Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sat, 27 May 2023 20:39:26 -0500 Subject: [PATCH] Refactor authentication into distant-auth --- .github/workflows/ci.yml | 4 + CHANGELOG.md | 5 + Cargo.lock | 14 + Cargo.toml | 2 +- distant-auth/Cargo.toml | 27 ++ distant-auth/src/authenticator.rs | 110 ++++++ .../src}/handler.rs | 85 ++++- .../src}/handler/methods.rs | 4 +- .../src}/handler/methods/prompt.rs | 6 +- .../src}/handler/methods/static_key.rs | 37 +- distant-auth/src/lib.rs | 14 + .../src}/methods.rs | 290 ++++++++-------- .../src}/methods/none.rs | 3 +- distant-auth/src/methods/static_key.rs | 131 ++++++++ .../src}/msg.rs | 0 distant-core/tests/stress/fixtures.rs | 2 +- distant-net/Cargo.toml | 2 + .../authenticator.rs => authentication.rs} | 315 ++++-------------- distant-net/src/client/builder.rs | 2 +- distant-net/src/common.rs | 5 +- distant-net/src/common/authentication.rs | 10 - .../authentication/methods/static_key.rs | 130 -------- distant-net/src/common/connection.rs | 12 +- .../framed/codec/encryption => }/key.rs | 0 .../common/{authentication => }/keychain.rs | 0 distant-net/src/common/transport/framed.rs | 1 + .../transport/framed/codec/encryption.rs | 4 +- .../src/common/transport/framed/exchange.rs | 2 +- distant-net/src/lib.rs | 4 + distant-net/src/manager/client.rs | 7 +- distant-net/src/manager/data/request.rs | 2 +- distant-net/src/manager/data/response.rs | 2 +- distant-net/src/manager/server.rs | 2 +- .../src/manager/server/authentication.rs | 4 +- distant-net/src/manager/server/handler.rs | 22 +- distant-net/src/server.rs | 6 +- distant-net/src/server/builder/tcp.rs | 4 +- distant-net/src/server/builder/unix.rs | 4 +- distant-net/src/server/connection.rs | 8 +- distant-net/src/server/state.rs | 3 +- distant-net/tests/manager_tests.rs | 2 +- distant-net/tests/typed_tests.rs | 2 +- distant-net/tests/untyped_tests.rs | 2 +- distant-ssh2/src/lib.rs | 2 +- src/cli/commands/manager/handlers.rs | 6 +- src/cli/commands/server.rs | 2 +- src/cli/common/client.rs | 6 +- src/cli/common/manager.rs | 2 +- 48 files changed, 668 insertions(+), 641 deletions(-) create mode 100644 distant-auth/Cargo.toml create mode 100644 distant-auth/src/authenticator.rs rename {distant-net/src/common/authentication => distant-auth/src}/handler.rs (79%) rename {distant-net/src/common/authentication => distant-auth/src}/handler/methods.rs (90%) rename {distant-net/src/common/authentication => distant-auth/src}/handler/methods/prompt.rs (94%) rename {distant-net/src/common/authentication => distant-auth/src}/handler/methods/static_key.rs (81%) create mode 100644 distant-auth/src/lib.rs rename {distant-net/src/common/authentication => distant-auth/src}/methods.rs (55%) rename {distant-net/src/common/authentication => distant-auth/src}/methods/none.rs (87%) create mode 100644 distant-auth/src/methods/static_key.rs rename {distant-net/src/common/authentication => distant-auth/src}/msg.rs (100%) rename distant-net/src/{common/authentication/authenticator.rs => authentication.rs} (58%) delete mode 100644 distant-net/src/common/authentication.rs delete mode 100644 distant-net/src/common/authentication/methods/static_key.rs rename distant-net/src/common/{transport/framed/codec/encryption => }/key.rs (100%) rename distant-net/src/common/{authentication => }/keychain.rs (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 951944b..47f953b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,8 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Check Cargo availability run: cargo --version + - name: distant-auth (all features) + run: cargo clippy -p distant-auth --all-targets --verbose --all-features - name: distant-net (all features) run: cargo clippy -p distant-net --all-targets --verbose --all-features - name: distant-core (all features) @@ -158,6 +160,8 @@ jobs: if: matrix.os == 'windows-latest' run: echo "NEXTEST_RETRIES=9" >> $GITHUB_ENV shell: bash + - name: Run auth tests (all features) + run: cargo nextest run --profile ci --release --all-features -p distant-net - name: Run net tests (default features) run: cargo nextest run --profile ci --release -p distant-net - name: Build core (default features) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64176ec..6fe1ab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - CLI `--lsp []` scheme now expects just the scheme and not `://` +- Moved `distant_net::common::authentication` to separate crate `distant-auth` +- Moved `distant_net::common::authentication::Keychain` to + `distant_net::common::Keychain` +- Moved `distant_net::common::transport::framed::codec::encryption::SecretKey` + and similar to `distant_net::common::SecretKey` ## [0.20.0-alpha.6] diff --git a/Cargo.lock b/Cargo.lock index aef47cb..919ddb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -849,6 +849,19 @@ dependencies = [ "winsplit", ] +[[package]] +name = "distant-auth" +version = "0.20.0-alpha.7" +dependencies = [ + "async-trait", + "derive_more", + "env_logger", + "log", + "serde", + "test-log", + "tokio", +] + [[package]] name = "distant-core" version = "0.20.0-alpha.7" @@ -896,6 +909,7 @@ dependencies = [ "bytes", "chacha20poly1305", "derive_more", + "distant-auth", "dyn-clone", "env_logger", "flate2", diff --git a/Cargo.toml b/Cargo.toml index 8d25bb2..8d30b04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" license = "MIT OR Apache-2.0" [workspace] -members = ["distant-core", "distant-net", "distant-ssh2"] +members = ["distant-auth", "distant-core", "distant-net", "distant-ssh2"] [profile.release] opt-level = 'z' diff --git a/distant-auth/Cargo.toml b/distant-auth/Cargo.toml new file mode 100644 index 0000000..ac02bc2 --- /dev/null +++ b/distant-auth/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "distant-auth" +description = "Authentication library for distant, providing various implementations" +categories = ["authentication"] +keywords = ["auth", "authentication", "async"] +version = "0.20.0-alpha.7" +authors = ["Chip Senkbeil "] +edition = "2021" +homepage = "https://github.com/chipsenkbeil/distant" +repository = "https://github.com/chipsenkbeil/distant" +readme = "README.md" +license = "MIT OR Apache-2.0" + +[features] +default = [] +tests = [] + +[dependencies] +async-trait = "0.1.68" +derive_more = { version = "0.99.17", default-features = false, features = ["display", "from", "error"] } +log = "0.4.17" +serde = { version = "1.0.159", features = ["derive"] } + +[dev-dependencies] +env_logger = "0.10.0" +test-log = "0.2.11" +tokio = { version = "1.27.0", features = ["full"] } diff --git a/distant-auth/src/authenticator.rs b/distant-auth/src/authenticator.rs new file mode 100644 index 0000000..65fd343 --- /dev/null +++ b/distant-auth/src/authenticator.rs @@ -0,0 +1,110 @@ +use std::io; + +use async_trait::async_trait; + +use crate::handler::AuthHandler; +use crate::msg::*; + +/// Represents an interface for authenticating with a server. +#[async_trait] +pub trait Authenticate { + /// Performs authentication by leveraging the `handler` for any received challenge. + async fn authenticate(&mut self, mut handler: impl AuthHandler + Send) -> io::Result<()>; +} + +/// Represents an interface for submitting challenges for authentication. +#[async_trait] +pub trait Authenticator: Send { + /// Issues an initialization notice and returns the response indicating which authentication + /// methods to pursue + async fn initialize( + &mut self, + initialization: Initialization, + ) -> io::Result; + + /// Issues a challenge and returns the answers to the `questions` asked. + async fn challenge(&mut self, challenge: Challenge) -> io::Result; + + /// Requests verification of some `kind` and `text`, returning true if passed verification. + async fn verify(&mut self, verification: Verification) -> io::Result; + + /// Reports information with no response expected. + async fn info(&mut self, info: Info) -> io::Result<()>; + + /// Reports an error occurred during authentication, consuming the authenticator since no more + /// challenges should be issued. + async fn error(&mut self, error: Error) -> io::Result<()>; + + /// Reports that the authentication has started for a specific method. + async fn start_method(&mut self, start_method: StartMethod) -> io::Result<()>; + + /// Reports that the authentication has finished successfully, consuming the authenticator + /// since no more challenges should be issued. + async fn finished(&mut self) -> io::Result<()>; +} + +/// Represents an implementator of [`Authenticator`] used purely for testing purposes. +#[cfg(any(test, feature = "tests"))] +pub struct TestAuthenticator { + pub initialize: Box io::Result + Send>, + pub challenge: Box io::Result + Send>, + pub verify: Box io::Result + Send>, + pub info: Box io::Result<()> + Send>, + pub error: Box io::Result<()> + Send>, + pub start_method: Box io::Result<()> + Send>, + pub finished: Box io::Result<()> + Send>, +} + +#[cfg(any(test, feature = "tests"))] +impl Default for TestAuthenticator { + fn default() -> Self { + Self { + initialize: Box::new(|x| Ok(InitializationResponse { methods: x.methods })), + challenge: Box::new(|x| { + Ok(ChallengeResponse { + answers: x.questions.into_iter().map(|x| x.text).collect(), + }) + }), + verify: Box::new(|_| Ok(VerificationResponse { valid: true })), + info: Box::new(|_| Ok(())), + error: Box::new(|_| Ok(())), + start_method: Box::new(|_| Ok(())), + finished: Box::new(|| Ok(())), + } + } +} + +#[cfg(any(test, feature = "tests"))] +#[async_trait] +impl Authenticator for TestAuthenticator { + async fn initialize( + &mut self, + initialization: Initialization, + ) -> io::Result { + (self.initialize)(initialization) + } + + async fn challenge(&mut self, challenge: Challenge) -> io::Result { + (self.challenge)(challenge) + } + + async fn verify(&mut self, verification: Verification) -> io::Result { + (self.verify)(verification) + } + + async fn info(&mut self, info: Info) -> io::Result<()> { + (self.info)(info) + } + + async fn error(&mut self, error: Error) -> io::Result<()> { + (self.error)(error) + } + + async fn start_method(&mut self, start_method: StartMethod) -> io::Result<()> { + (self.start_method)(start_method) + } + + async fn finished(&mut self) -> io::Result<()> { + (self.finished)() + } +} diff --git a/distant-net/src/common/authentication/handler.rs b/distant-auth/src/handler.rs similarity index 79% rename from distant-net/src/common/authentication/handler.rs rename to distant-auth/src/handler.rs index 662f288..0c7b8da 100644 --- a/distant-net/src/common/authentication/handler.rs +++ b/distant-auth/src/handler.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; +use std::fmt::Display; use std::io; use async_trait::async_trait; -use super::msg::*; -use crate::common::authentication::Authenticator; -use crate::common::HeapSecretKey; +use crate::authenticator::Authenticator; +use crate::msg::*; mod methods; pub use methods::*; @@ -176,7 +176,10 @@ impl AuthHandlerMap { impl AuthHandlerMap { /// Consumes the map, returning a new map that supports the `static_key` method. - pub fn with_static_key(mut self, key: impl Into) -> Self { + pub fn with_static_key(mut self, key: K) -> Self + where + K: Display + Send + 'static, + { self.insert_method_handler("static_key", StaticKeyAuthMethodHandler::simple(key)); self } @@ -343,3 +346,77 @@ impl<'a> AuthMethodHandler for DynAuthHandler<'a> { self.0.on_error(error).await } } + +/// Represents an implementator of [`AuthHandler`] used purely for testing purposes. +#[cfg(any(test, feature = "tests"))] +pub struct TestAuthHandler { + pub on_initialization: + Box io::Result + Send>, + pub on_challenge: Box io::Result + Send>, + pub on_verification: Box io::Result + Send>, + pub on_info: Box io::Result<()> + Send>, + pub on_error: Box io::Result<()> + Send>, + pub on_start_method: Box io::Result<()> + Send>, + pub on_finished: Box io::Result<()> + Send>, +} + +#[cfg(any(test, feature = "tests"))] +impl Default for TestAuthHandler { + fn default() -> Self { + Self { + on_initialization: Box::new(|x| Ok(InitializationResponse { methods: x.methods })), + on_challenge: Box::new(|x| { + Ok(ChallengeResponse { + answers: x.questions.into_iter().map(|x| x.text).collect(), + }) + }), + on_verification: Box::new(|_| Ok(VerificationResponse { valid: true })), + on_info: Box::new(|_| Ok(())), + on_error: Box::new(|_| Ok(())), + on_start_method: Box::new(|_| Ok(())), + on_finished: Box::new(|| Ok(())), + } + } +} + +#[cfg(any(test, feature = "tests"))] +#[async_trait] +impl AuthHandler for TestAuthHandler { + async fn on_initialization( + &mut self, + initialization: Initialization, + ) -> io::Result { + (self.on_initialization)(initialization) + } + + async fn on_start_method(&mut self, start_method: StartMethod) -> io::Result<()> { + (self.on_start_method)(start_method) + } + + async fn on_finished(&mut self) -> io::Result<()> { + (self.on_finished)() + } +} + +#[cfg(any(test, feature = "tests"))] +#[async_trait] +impl AuthMethodHandler for TestAuthHandler { + async fn on_challenge(&mut self, challenge: Challenge) -> io::Result { + (self.on_challenge)(challenge) + } + + async fn on_verification( + &mut self, + verification: Verification, + ) -> io::Result { + (self.on_verification)(verification) + } + + async fn on_info(&mut self, info: Info) -> io::Result<()> { + (self.on_info)(info) + } + + async fn on_error(&mut self, error: Error) -> io::Result<()> { + (self.on_error)(error) + } +} diff --git a/distant-net/src/common/authentication/handler/methods.rs b/distant-auth/src/handler/methods.rs similarity index 90% rename from distant-net/src/common/authentication/handler/methods.rs rename to distant-auth/src/handler/methods.rs index 5ee35e5..8d23ee9 100644 --- a/distant-net/src/common/authentication/handler/methods.rs +++ b/distant-auth/src/handler/methods.rs @@ -2,9 +2,7 @@ use std::io; use async_trait::async_trait; -use super::{ - Challenge, ChallengeResponse, Error, Info, Verification, VerificationKind, VerificationResponse, -}; +use crate::msg::{Challenge, ChallengeResponse, Error, Info, Verification, VerificationResponse}; /// Interface for a handler of authentication requests for a specific authentication method. #[async_trait] diff --git a/distant-net/src/common/authentication/handler/methods/prompt.rs b/distant-auth/src/handler/methods/prompt.rs similarity index 94% rename from distant-net/src/common/authentication/handler/methods/prompt.rs rename to distant-auth/src/handler/methods/prompt.rs index 57f141b..9eee7ed 100644 --- a/distant-net/src/common/authentication/handler/methods/prompt.rs +++ b/distant-auth/src/handler/methods/prompt.rs @@ -3,9 +3,9 @@ use std::io; use async_trait::async_trait; use log::*; -use super::{ - AuthMethodHandler, Challenge, ChallengeResponse, Error, Info, Verification, VerificationKind, - VerificationResponse, +use crate::handler::AuthMethodHandler; +use crate::msg::{ + Challenge, ChallengeResponse, Error, Info, Verification, VerificationKind, VerificationResponse, }; /// Blocking implementation of [`AuthMethodHandler`] that uses prompts to communicate challenge & diff --git a/distant-net/src/common/authentication/handler/methods/static_key.rs b/distant-auth/src/handler/methods/static_key.rs similarity index 81% rename from distant-net/src/common/authentication/handler/methods/static_key.rs rename to distant-auth/src/handler/methods/static_key.rs index f58b07b..c9770ff 100644 --- a/distant-net/src/common/authentication/handler/methods/static_key.rs +++ b/distant-auth/src/handler/methods/static_key.rs @@ -1,28 +1,26 @@ +use std::fmt::Display; use std::io; use async_trait::async_trait; use log::*; -use super::{ - AuthMethodHandler, Challenge, ChallengeResponse, Error, Info, Verification, - VerificationResponse, -}; -use crate::common::HeapSecretKey; +use crate::handler::AuthMethodHandler; +use crate::msg::{Challenge, ChallengeResponse, Error, Info, Verification, VerificationResponse}; /// Implementation of [`AuthMethodHandler`] that answers challenge requests using a static /// [`HeapSecretKey`]. All other portions of method authentication are handled by another /// [`AuthMethodHandler`]. -pub struct StaticKeyAuthMethodHandler { - key: HeapSecretKey, +pub struct StaticKeyAuthMethodHandler { + key: K, handler: Box, } -impl StaticKeyAuthMethodHandler { +impl StaticKeyAuthMethodHandler { /// Creates a new [`StaticKeyAuthMethodHandler`] that responds to challenges using a static /// `key`. All other requests are passed to the `handler`. - pub fn new(key: impl Into, handler: T) -> Self { + pub fn new(key: K, handler: T) -> Self { Self { - key: key.into(), + key, handler: Box::new(handler), } } @@ -30,7 +28,7 @@ impl StaticKeyAuthMethodHandler { /// Creates a new [`StaticKeyAuthMethodHandler`] that responds to challenges using a static /// `key`. All other requests are passed automatically, meaning that verification is always /// approvide and info/errors are ignored. - pub fn simple(key: impl Into) -> Self { + pub fn simple(key: K) -> Self { Self::new(key, { struct __AuthMethodHandler; @@ -62,7 +60,10 @@ impl StaticKeyAuthMethodHandler { } #[async_trait] -impl AuthMethodHandler for StaticKeyAuthMethodHandler { +impl AuthMethodHandler for StaticKeyAuthMethodHandler +where + K: Display + Send, +{ async fn on_challenge(&mut self, challenge: Challenge) -> io::Result { trace!("on_challenge({challenge:?})"); let mut answers = Vec::new(); @@ -103,11 +104,11 @@ mod tests { use test_log::test; use super::*; - use crate::common::authentication::msg::{ErrorKind, Question, VerificationKind}; + use crate::msg::{ErrorKind, Question, VerificationKind}; #[test(tokio::test)] async fn on_challenge_should_fail_if_non_key_question_received() { - let mut handler = StaticKeyAuthMethodHandler::simple(HeapSecretKey::generate(32).unwrap()); + let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key")); handler .on_challenge(Challenge { @@ -120,7 +121,7 @@ mod tests { #[test(tokio::test)] async fn on_challenge_should_answer_with_stringified_key_for_key_questions() { - let mut handler = StaticKeyAuthMethodHandler::simple(HeapSecretKey::generate(32).unwrap()); + let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key")); let response = handler .on_challenge(Challenge { @@ -135,7 +136,7 @@ mod tests { #[test(tokio::test)] async fn on_verification_should_leverage_fallback_handler() { - let mut handler = StaticKeyAuthMethodHandler::simple(HeapSecretKey::generate(32).unwrap()); + let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key")); let response = handler .on_verification(Verification { @@ -149,7 +150,7 @@ mod tests { #[test(tokio::test)] async fn on_info_should_leverage_fallback_handler() { - let mut handler = StaticKeyAuthMethodHandler::simple(HeapSecretKey::generate(32).unwrap()); + let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key")); handler .on_info(Info { @@ -161,7 +162,7 @@ mod tests { #[test(tokio::test)] async fn on_error_should_leverage_fallback_handler() { - let mut handler = StaticKeyAuthMethodHandler::simple(HeapSecretKey::generate(32).unwrap()); + let mut handler = StaticKeyAuthMethodHandler::simple(String::from("secret-key")); handler .on_error(Error { diff --git a/distant-auth/src/lib.rs b/distant-auth/src/lib.rs new file mode 100644 index 0000000..97be5d6 --- /dev/null +++ b/distant-auth/src/lib.rs @@ -0,0 +1,14 @@ +mod authenticator; +mod handler; +mod methods; +pub mod msg; + +pub use authenticator::*; +pub use handler::*; +pub use methods::*; + +#[cfg(any(test, feature = "tests"))] +pub mod tests { + pub use crate::TestAuthHandler; + pub use crate::TestAuthenticator; +} diff --git a/distant-net/src/common/authentication/methods.rs b/distant-auth/src/methods.rs similarity index 55% rename from distant-net/src/common/authentication/methods.rs rename to distant-auth/src/methods.rs index 496d40a..0537c96 100644 --- a/distant-net/src/common/authentication/methods.rs +++ b/distant-auth/src/methods.rs @@ -1,12 +1,12 @@ use std::collections::HashMap; use std::io; +use std::str::FromStr; use async_trait::async_trait; use log::*; -use super::super::HeapSecretKey; -use super::msg::*; -use super::Authenticator; +use crate::authenticator::Authenticator; +use crate::msg::*; mod none; mod static_key; @@ -48,7 +48,10 @@ impl Verifier { } /// Creates a verifier that uses the [`StaticKeyAuthenticationMethod`] exclusively. - pub fn static_key(key: impl Into) -> Self { + pub fn static_key(key: K) -> Self + where + K: FromStr + PartialEq + Send + Sync + 'static, + { Self::new(vec![ Box::new(StaticKeyAuthenticationMethod::new(key)) as Box ]) @@ -117,10 +120,12 @@ pub trait AuthenticationMethod: Send + Sync { #[cfg(test)] mod tests { + use std::sync::mpsc; use test_log::test; use super::*; - use crate::common::FramedTransport; + + use crate::authenticator::TestAuthenticator; struct SuccessAuthenticationMethod; @@ -150,147 +155,131 @@ mod tests { #[test(tokio::test)] async fn verifier_should_fail_to_verify_if_initialization_fails() { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame(b"invalid initialization response") - .await - .unwrap(); + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| Err(io::Error::from(io::ErrorKind::Other))), + ..Default::default() + }; let methods: Vec> = vec![Box::new(SuccessAuthenticationMethod)]; let verifier = Verifier::from(methods); - verifier.verify(&mut t1).await.unwrap_err(); + verifier.verify(&mut authenticator).await.unwrap_err(); } #[test(tokio::test)] async fn verifier_should_fail_to_verify_if_fails_to_send_finished_indicator_after_success() { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Initialization( - InitializationResponse { - methods: vec![SuccessAuthenticationMethod.id().to_string()] - .into_iter() - .collect(), - }, - )) - .await - .unwrap(); - - // Then drop the transport so it cannot receive anything else - drop(t2); + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| { + Ok(InitializationResponse { + methods: vec![SuccessAuthenticationMethod.id().to_string()] + .into_iter() + .collect(), + }) + }), + finished: Box::new(|| Err(io::Error::new(io::ErrorKind::Other, "test error"))), + ..Default::default() + }; let methods: Vec> = vec![Box::new(SuccessAuthenticationMethod)]; let verifier = Verifier::from(methods); - assert_eq!( - verifier.verify(&mut t1).await.unwrap_err().kind(), - io::ErrorKind::WriteZero - ); + + let err = verifier.verify(&mut authenticator).await.unwrap_err(); + assert_eq!(err.kind(), io::ErrorKind::Other); + assert_eq!(err.to_string(), "test error"); } #[test(tokio::test)] async fn verifier_should_fail_to_verify_if_has_no_authentication_methods() { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Initialization( - InitializationResponse { - methods: vec![SuccessAuthenticationMethod.id().to_string()] - .into_iter() - .collect(), - }, - )) - .await - .unwrap(); + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| { + Ok(InitializationResponse { + methods: vec![SuccessAuthenticationMethod.id().to_string()] + .into_iter() + .collect(), + }) + }), + ..Default::default() + }; let methods: Vec> = vec![]; let verifier = Verifier::from(methods); - verifier.verify(&mut t1).await.unwrap_err(); + verifier.verify(&mut authenticator).await.unwrap_err(); } #[test(tokio::test)] async fn verifier_should_fail_to_verify_if_initialization_yields_no_valid_authentication_methods( ) { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Initialization( - InitializationResponse { - methods: vec!["other".to_string()].into_iter().collect(), - }, - )) - .await - .unwrap(); + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| { + Ok(InitializationResponse { + methods: vec!["other".to_string()].into_iter().collect(), + }) + }), + ..Default::default() + }; let methods: Vec> = vec![Box::new(SuccessAuthenticationMethod)]; let verifier = Verifier::from(methods); - verifier.verify(&mut t1).await.unwrap_err(); + verifier.verify(&mut authenticator).await.unwrap_err(); } #[test(tokio::test)] async fn verifier_should_fail_to_verify_if_no_authentication_method_succeeds() { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Initialization( - InitializationResponse { - methods: vec![FailAuthenticationMethod.id().to_string()] - .into_iter() - .collect(), - }, - )) - .await - .unwrap(); + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| { + Ok(InitializationResponse { + methods: vec![FailAuthenticationMethod.id().to_string()] + .into_iter() + .collect(), + }) + }), + ..Default::default() + }; let methods: Vec> = vec![Box::new(FailAuthenticationMethod)]; let verifier = Verifier::from(methods); - verifier.verify(&mut t1).await.unwrap_err(); + verifier.verify(&mut authenticator).await.unwrap_err(); } #[test(tokio::test)] async fn verifier_should_return_id_of_authentication_method_upon_success() { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Initialization( - InitializationResponse { - methods: vec![SuccessAuthenticationMethod.id().to_string()] - .into_iter() - .collect(), - }, - )) - .await - .unwrap(); + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| { + Ok(InitializationResponse { + methods: vec![SuccessAuthenticationMethod.id().to_string()] + .into_iter() + .collect(), + }) + }), + ..Default::default() + }; let methods: Vec> = vec![Box::new(SuccessAuthenticationMethod)]; let verifier = Verifier::from(methods); assert_eq!( - verifier.verify(&mut t1).await.unwrap(), + verifier.verify(&mut authenticator).await.unwrap(), SuccessAuthenticationMethod.id() ); } #[test(tokio::test)] async fn verifier_should_try_authentication_methods_in_order_until_one_succeeds() { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Initialization( - InitializationResponse { - methods: vec![ - FailAuthenticationMethod.id().to_string(), - SuccessAuthenticationMethod.id().to_string(), - ] - .into_iter() - .collect(), - }, - )) - .await - .unwrap(); + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| { + Ok(InitializationResponse { + methods: vec![ + FailAuthenticationMethod.id().to_string(), + SuccessAuthenticationMethod.id().to_string(), + ] + .into_iter() + .collect(), + }) + }), + ..Default::default() + }; let methods: Vec> = vec![ Box::new(FailAuthenticationMethod), @@ -298,84 +287,79 @@ mod tests { ]; let verifier = Verifier::from(methods); assert_eq!( - verifier.verify(&mut t1).await.unwrap(), + verifier.verify(&mut authenticator).await.unwrap(), SuccessAuthenticationMethod.id() ); } #[test(tokio::test)] async fn verifier_should_send_start_method_before_attempting_each_method() { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Initialization( - InitializationResponse { - methods: vec![ - FailAuthenticationMethod.id().to_string(), - SuccessAuthenticationMethod.id().to_string(), - ] - .into_iter() - .collect(), - }, - )) - .await - .unwrap(); + let (tx, rx) = mpsc::channel(); + + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| { + Ok(InitializationResponse { + methods: vec![ + FailAuthenticationMethod.id().to_string(), + SuccessAuthenticationMethod.id().to_string(), + ] + .into_iter() + .collect(), + }) + }), + start_method: Box::new(move |method| { + tx.send(method.method).unwrap(); + Ok(()) + }), + ..Default::default() + }; let methods: Vec> = vec![ Box::new(FailAuthenticationMethod), Box::new(SuccessAuthenticationMethod), ]; - Verifier::from(methods).verify(&mut t1).await.unwrap(); + Verifier::from(methods) + .verify(&mut authenticator) + .await + .unwrap(); - // Check that we get a start method for each of the attempted methods - match t2.read_frame_as::().await.unwrap().unwrap() { - Authentication::Initialization(_) => (), - x => panic!("Unexpected response: {x:?}"), - } - match t2.read_frame_as::().await.unwrap().unwrap() { - Authentication::StartMethod(x) => assert_eq!(x.method, FailAuthenticationMethod.id()), - x => panic!("Unexpected response: {x:?}"), - } - match t2.read_frame_as::().await.unwrap().unwrap() { - Authentication::StartMethod(x) => { - assert_eq!(x.method, SuccessAuthenticationMethod.id()) - } - x => panic!("Unexpected response: {x:?}"), - } + assert_eq!(rx.try_recv().unwrap(), FailAuthenticationMethod.id()); + assert_eq!(rx.try_recv().unwrap(), SuccessAuthenticationMethod.id()); + assert_eq!(rx.try_recv().unwrap_err(), mpsc::TryRecvError::Empty); } #[test(tokio::test)] async fn verifier_should_send_finished_when_a_method_succeeds() { - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Initialization( - InitializationResponse { - methods: vec![ - FailAuthenticationMethod.id().to_string(), - SuccessAuthenticationMethod.id().to_string(), - ] - .into_iter() - .collect(), - }, - )) - .await - .unwrap(); + let (tx, rx) = mpsc::channel(); + + let mut authenticator = TestAuthenticator { + initialize: Box::new(|_| { + Ok(InitializationResponse { + methods: vec![ + FailAuthenticationMethod.id().to_string(), + SuccessAuthenticationMethod.id().to_string(), + ] + .into_iter() + .collect(), + }) + }), + finished: Box::new(move || { + tx.send(()).unwrap(); + Ok(()) + }), + ..Default::default() + }; let methods: Vec> = vec![ Box::new(FailAuthenticationMethod), Box::new(SuccessAuthenticationMethod), ]; - Verifier::from(methods).verify(&mut t1).await.unwrap(); - - // Clear out the initialization and start methods - t2.read_frame_as::().await.unwrap().unwrap(); - t2.read_frame_as::().await.unwrap().unwrap(); - t2.read_frame_as::().await.unwrap().unwrap(); + Verifier::from(methods) + .verify(&mut authenticator) + .await + .unwrap(); - match t2.read_frame_as::().await.unwrap().unwrap() { - Authentication::Finished => (), - x => panic!("Unexpected response: {x:?}"), - } + rx.try_recv().unwrap(); + assert_eq!(rx.try_recv().unwrap_err(), mpsc::TryRecvError::Empty); } } diff --git a/distant-net/src/common/authentication/methods/none.rs b/distant-auth/src/methods/none.rs similarity index 87% rename from distant-net/src/common/authentication/methods/none.rs rename to distant-auth/src/methods/none.rs index e9f3057..237598d 100644 --- a/distant-net/src/common/authentication/methods/none.rs +++ b/distant-auth/src/methods/none.rs @@ -2,7 +2,8 @@ use std::io; use async_trait::async_trait; -use super::{AuthenticationMethod, Authenticator}; +use crate::authenticator::Authenticator; +use crate::methods::AuthenticationMethod; /// Authenticaton method for a static secret key #[derive(Clone, Debug)] diff --git a/distant-auth/src/methods/static_key.rs b/distant-auth/src/methods/static_key.rs new file mode 100644 index 0000000..56cd556 --- /dev/null +++ b/distant-auth/src/methods/static_key.rs @@ -0,0 +1,131 @@ +use std::io; +use std::str::FromStr; + +use async_trait::async_trait; + +use crate::authenticator::Authenticator; +use crate::methods::AuthenticationMethod; +use crate::msg::{Challenge, Error, Question}; + +/// Authenticaton method for a static secret key +#[derive(Clone, Debug)] +pub struct StaticKeyAuthenticationMethod { + key: T, +} + +impl StaticKeyAuthenticationMethod { + #[inline] + pub fn new(key: T) -> Self { + Self { key } + } +} + +#[async_trait] +impl AuthenticationMethod for StaticKeyAuthenticationMethod +where + T: FromStr + PartialEq + Send + Sync, +{ + fn id(&self) -> &'static str { + "static_key" + } + + async fn authenticate(&self, authenticator: &mut dyn Authenticator) -> io::Result<()> { + let response = authenticator + .challenge(Challenge { + questions: vec![Question { + label: "key".to_string(), + text: "Provide a key: ".to_string(), + options: Default::default(), + }], + options: Default::default(), + }) + .await?; + + if response.answers.is_empty() { + return Err(Error::non_fatal("missing answer").into_io_permission_denied()); + } + + match response.answers.into_iter().next().unwrap().parse::() { + Ok(key) if key == self.key => Ok(()), + _ => Err(Error::non_fatal("answer does not match key").into_io_permission_denied()), + } + } +} + +#[cfg(test)] +mod tests { + use test_log::test; + + use super::*; + use crate::authenticator::TestAuthenticator; + use crate::msg::*; + + #[test(tokio::test)] + async fn authenticate_should_fail_if_key_challenge_fails() { + let method = StaticKeyAuthenticationMethod::new(String::new()); + + let mut authenticator = TestAuthenticator { + challenge: Box::new(|_| Err(io::Error::new(io::ErrorKind::InvalidData, "test error"))), + ..Default::default() + }; + + let err = method.authenticate(&mut authenticator).await.unwrap_err(); + + assert_eq!(err.kind(), io::ErrorKind::InvalidData); + assert_eq!(err.to_string(), "test error"); + } + + #[test(tokio::test)] + async fn authenticate_should_fail_if_no_answer_included_in_challenge_response() { + let method = StaticKeyAuthenticationMethod::new(String::new()); + + let mut authenticator = TestAuthenticator { + challenge: Box::new(|_| { + Ok(ChallengeResponse { + answers: Vec::new(), + }) + }), + ..Default::default() + }; + + let err = method.authenticate(&mut authenticator).await.unwrap_err(); + + assert_eq!(err.kind(), io::ErrorKind::PermissionDenied); + assert_eq!(err.to_string(), "Error: missing answer"); + } + + #[test(tokio::test)] + async fn authenticate_should_fail_if_answer_does_not_match_key() { + let method = StaticKeyAuthenticationMethod::new(String::from("answer")); + + let mut authenticator = TestAuthenticator { + challenge: Box::new(|_| { + Ok(ChallengeResponse { + answers: vec![String::from("other")], + }) + }), + ..Default::default() + }; + + let err = method.authenticate(&mut authenticator).await.unwrap_err(); + + assert_eq!(err.kind(), io::ErrorKind::PermissionDenied); + assert_eq!(err.to_string(), "Error: answer does not match key"); + } + + #[test(tokio::test)] + async fn authenticate_should_succeed_if_answer_matches_key() { + let method = StaticKeyAuthenticationMethod::new(String::from("answer")); + + let mut authenticator = TestAuthenticator { + challenge: Box::new(|_| { + Ok(ChallengeResponse { + answers: vec![String::from("answer")], + }) + }), + ..Default::default() + }; + + method.authenticate(&mut authenticator).await.unwrap(); + } +} diff --git a/distant-net/src/common/authentication/msg.rs b/distant-auth/src/msg.rs similarity index 100% rename from distant-net/src/common/authentication/msg.rs rename to distant-auth/src/msg.rs diff --git a/distant-core/tests/stress/fixtures.rs b/distant-core/tests/stress/fixtures.rs index 25e52ea..05563b9 100644 --- a/distant-core/tests/stress/fixtures.rs +++ b/distant-core/tests/stress/fixtures.rs @@ -1,8 +1,8 @@ use std::net::SocketAddr; use std::time::Duration; +use distant_core::net::auth::{DummyAuthHandler, Verifier}; use distant_core::net::client::{Client, TcpConnector}; -use distant_core::net::common::authentication::{DummyAuthHandler, Verifier}; use distant_core::net::common::PortRange; use distant_core::net::server::Server; use distant_core::{DistantApiServerHandler, DistantClient, LocalDistantApi}; diff --git a/distant-net/Cargo.toml b/distant-net/Cargo.toml index 8a91341..ae19871 100644 --- a/distant-net/Cargo.toml +++ b/distant-net/Cargo.toml @@ -16,6 +16,7 @@ async-trait = "0.1.68" bytes = "1.4.0" chacha20poly1305 = "0.10.1" derive_more = { version = "0.99.17", default-features = false, features = ["as_mut", "as_ref", "deref", "deref_mut", "display", "from", "error", "into", "into_iterator", "is_variant", "try_into"] } +distant-auth = { version = "=0.20.0-alpha.7", path = "../distant-auth" } dyn-clone = "1.0.11" flate2 = "1.0.25" hex = "0.4.3" @@ -35,6 +36,7 @@ tokio = { version = "1.27.0", features = ["full"] } schemars = { version = "0.8.12", optional = true } [dev-dependencies] +distant-auth = { version = "=0.20.0-alpha.7", path = "../distant-auth", features = ["tests"] } env_logger = "0.10.0" serde_json = "1.0.95" tempfile = "3.5.0" diff --git a/distant-net/src/common/authentication/authenticator.rs b/distant-net/src/authentication.rs similarity index 58% rename from distant-net/src/common/authentication/authenticator.rs rename to distant-net/src/authentication.rs index 2cd451c..8ace4a3 100644 --- a/distant-net/src/common/authentication/authenticator.rs +++ b/distant-net/src/authentication.rs @@ -1,49 +1,10 @@ -use std::io; - +use crate::common::utils; +use crate::common::{FramedTransport, Transport}; use async_trait::async_trait; +use distant_auth::msg::*; +use distant_auth::{AuthHandler, Authenticate, Authenticator}; use log::*; - -use super::msg::*; -use super::AuthHandler; -use crate::common::{utils, FramedTransport, Transport}; - -/// Represents an interface for authenticating with a server. -#[async_trait] -pub trait Authenticate { - /// Performs authentication by leveraging the `handler` for any received challenge. - async fn authenticate(&mut self, mut handler: impl AuthHandler + Send) -> io::Result<()>; -} - -/// Represents an interface for submitting challenges for authentication. -#[async_trait] -pub trait Authenticator: Send { - /// Issues an initialization notice and returns the response indicating which authentication - /// methods to pursue - async fn initialize( - &mut self, - initialization: Initialization, - ) -> io::Result; - - /// Issues a challenge and returns the answers to the `questions` asked. - async fn challenge(&mut self, challenge: Challenge) -> io::Result; - - /// Requests verification of some `kind` and `text`, returning true if passed verification. - async fn verify(&mut self, verification: Verification) -> io::Result; - - /// Reports information with no response expected. - async fn info(&mut self, info: Info) -> io::Result<()>; - - /// Reports an error occurred during authentication, consuming the authenticator since no more - /// challenges should be issued. - async fn error(&mut self, error: Error) -> io::Result<()>; - - /// Reports that the authentication has started for a specific method. - async fn start_method(&mut self, start_method: StartMethod) -> io::Result<()>; - - /// Reports that the authentication has finished successfully, consuming the authenticator - /// since no more challenges should be issued. - async fn finished(&mut self) -> io::Result<()>; -} +use std::io; macro_rules! write_frame { ($transport:expr, $data:expr) => {{ @@ -203,161 +164,20 @@ where #[cfg(test)] mod tests { + use distant_auth::tests::TestAuthHandler; use test_log::test; use tokio::sync::mpsc; use super::*; - use crate::common::authentication::AuthMethodHandler; - - #[async_trait] - trait TestAuthHandler { - async fn on_initialization( - &mut self, - _: Initialization, - ) -> io::Result { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - async fn on_start_method(&mut self, _: StartMethod) -> io::Result<()> { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - async fn on_finished(&mut self) -> io::Result<()> { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - async fn on_challenge(&mut self, _: Challenge) -> io::Result { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - async fn on_verification(&mut self, _: Verification) -> io::Result { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - async fn on_info(&mut self, _: Info) -> io::Result<()> { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - async fn on_error(&mut self, _: Error) -> io::Result<()> { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - } - - #[async_trait] - impl AuthHandler for T { - async fn on_initialization( - &mut self, - x: Initialization, - ) -> io::Result { - TestAuthHandler::on_initialization(self, x).await - } - - async fn on_start_method(&mut self, x: StartMethod) -> io::Result<()> { - TestAuthHandler::on_start_method(self, x).await - } - - async fn on_finished(&mut self) -> io::Result<()> { - TestAuthHandler::on_finished(self).await - } - } - - #[async_trait] - impl AuthMethodHandler for T { - async fn on_challenge(&mut self, x: Challenge) -> io::Result { - TestAuthHandler::on_challenge(self, x).await - } - - async fn on_verification(&mut self, x: Verification) -> io::Result { - TestAuthHandler::on_verification(self, x).await - } - - async fn on_info(&mut self, x: Info) -> io::Result<()> { - TestAuthHandler::on_info(self, x).await - } - - async fn on_error(&mut self, x: Error) -> io::Result<()> { - TestAuthHandler::on_error(self, x).await - } - } - - macro_rules! auth_handler { - (@no_challenge @no_verification @tx($tx:ident, $ty:ty) $($methods:item)*) => { - auth_handler! { - @tx($tx, $ty) - - async fn on_challenge(&mut self, _: Challenge) -> io::Result { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - async fn on_verification( - &mut self, - _: Verification, - ) -> io::Result { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - $($methods)* - } - }; - (@no_challenge @tx($tx:ident, $ty:ty) $($methods:item)*) => { - auth_handler! { - @tx($tx, $ty) - - async fn on_challenge(&mut self, _: Challenge) -> io::Result { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - $($methods)* - } - }; - (@no_verification @tx($tx:ident, $ty:ty) $($methods:item)*) => { - auth_handler! { - @tx($tx, $ty) - - async fn on_verification( - &mut self, - _: Verification, - ) -> io::Result { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - - $($methods)* - } - }; - (@tx($tx:ident, $ty:ty) $($methods:item)*) => {{ - #[allow(dead_code)] - struct __InlineAuthHandler { - tx: mpsc::Sender<$ty>, - } - - #[async_trait] - impl TestAuthHandler for __InlineAuthHandler { - $($methods)* - } - - __InlineAuthHandler { tx: $tx } - }}; - } #[test(tokio::test)] async fn authenticator_initialization_should_be_able_to_successfully_complete_round_trip() { let (mut t1, mut t2) = FramedTransport::test_pair(100); - let (tx, _) = mpsc::channel(1); let task = tokio::spawn(async move { - t2.authenticate(auth_handler! { - @no_challenge - @no_verification - @tx(tx, ()) - - async fn on_initialization( - &mut self, - initialization: Initialization, - ) -> io::Result { - Ok(InitializationResponse { - methods: initialization.methods, - }) - } + t2.authenticate(TestAuthHandler { + on_initialization: Box::new(|x| Ok(InitializationResponse { methods: x.methods })), + ..Default::default() }) .await .unwrap() @@ -386,29 +206,34 @@ mod tests { #[test(tokio::test)] async fn authenticator_challenge_should_be_able_to_successfully_complete_round_trip() { let (mut t1, mut t2) = FramedTransport::test_pair(100); - let (tx, _) = mpsc::channel(1); let task = tokio::spawn(async move { - t2.authenticate(auth_handler! { - @no_verification - @tx(tx, ()) - - async fn on_challenge(&mut self, challenge: Challenge) -> io::Result { - assert_eq!(challenge.questions, vec![Question { - label: "label".to_string(), - text: "text".to_string(), - options: vec![("question_key".to_string(), "question_value".to_string())] + t2.authenticate(TestAuthHandler { + on_challenge: Box::new(|challenge| { + assert_eq!( + challenge.questions, + vec![Question { + label: "label".to_string(), + text: "text".to_string(), + options: vec![( + "question_key".to_string(), + "question_value".to_string() + )] .into_iter() .collect(), - }]); + }] + ); assert_eq!( challenge.options, - vec![("key".to_string(), "value".to_string())].into_iter().collect(), + vec![("key".to_string(), "value".to_string())] + .into_iter() + .collect(), ); Ok(ChallengeResponse { answers: vec!["some answer".to_string()].into_iter().collect(), }) - } + }), + ..Default::default() }) .await .unwrap() @@ -446,23 +271,15 @@ mod tests { #[test(tokio::test)] async fn authenticator_verification_should_be_able_to_successfully_complete_round_trip() { let (mut t1, mut t2) = FramedTransport::test_pair(100); - let (tx, _) = mpsc::channel(1); let task = tokio::spawn(async move { - t2.authenticate(auth_handler! { - @no_challenge - @tx(tx, ()) - - async fn on_verification( - &mut self, - verification: Verification, - ) -> io::Result { + t2.authenticate(TestAuthHandler { + on_verification: Box::new(|verification| { assert_eq!(verification.kind, VerificationKind::Host); assert_eq!(verification.text, "some text"); - Ok(VerificationResponse { - valid: true, - }) - } + Ok(VerificationResponse { valid: true }) + }), + ..Default::default() }) .await .unwrap() @@ -490,18 +307,12 @@ mod tests { let (tx, mut rx) = mpsc::channel(1); let task = tokio::spawn(async move { - t2.authenticate(auth_handler! { - @no_challenge - @no_verification - @tx(tx, Info) - - async fn on_info( - &mut self, - info: Info, - ) -> io::Result<()> { - self.tx.send(info).await.unwrap(); + t2.authenticate(TestAuthHandler { + on_info: Box::new(move |info| { + tx.try_send(info).unwrap(); Ok(()) - } + }), + ..Default::default() }) .await .unwrap() @@ -532,15 +343,12 @@ mod tests { let (tx, mut rx) = mpsc::channel(1); let task = tokio::spawn(async move { - t2.authenticate(auth_handler! { - @no_challenge - @no_verification - @tx(tx, Error) - - async fn on_error(&mut self, error: Error) -> io::Result<()> { - self.tx.send(error).await.unwrap(); + t2.authenticate(TestAuthHandler { + on_error: Box::new(move |error| { + tx.try_send(error).unwrap(); Ok(()) - } + }), + ..Default::default() }) .await .unwrap() @@ -573,15 +381,12 @@ mod tests { let (tx, mut rx) = mpsc::channel(1); let task = tokio::spawn(async move { - t2.authenticate(auth_handler! { - @no_challenge - @no_verification - @tx(tx, Error) - - async fn on_error(&mut self, error: Error) -> io::Result<()> { - self.tx.send(error).await.unwrap(); + t2.authenticate(TestAuthHandler { + on_error: Box::new(move |error| { + tx.try_send(error).unwrap(); Ok(()) - } + }), + ..Default::default() }) .await .unwrap() @@ -612,15 +417,12 @@ mod tests { let (tx, mut rx) = mpsc::channel(1); let task = tokio::spawn(async move { - t2.authenticate(auth_handler! { - @no_challenge - @no_verification - @tx(tx, StartMethod) - - async fn on_start_method(&mut self, start_method: StartMethod) -> io::Result<()> { - self.tx.send(start_method).await.unwrap(); + t2.authenticate(TestAuthHandler { + on_start_method: Box::new(move |start_method| { + tx.try_send(start_method).unwrap(); Ok(()) - } + }), + ..Default::default() }) .await .unwrap() @@ -651,15 +453,12 @@ mod tests { let (tx, mut rx) = mpsc::channel(1); let task = tokio::spawn(async move { - t2.authenticate(auth_handler! { - @no_challenge - @no_verification - @tx(tx, ()) - - async fn on_finished(&mut self) -> io::Result<()> { - self.tx.send(()).await.unwrap(); + t2.authenticate(TestAuthHandler { + on_finished: Box::new(move || { + tx.try_send(()).unwrap(); Ok(()) - } + }), + ..Default::default() }) .await .unwrap() diff --git a/distant-net/src/client/builder.rs b/distant-net/src/client/builder.rs index 46a6e08..10d64b1 100644 --- a/distant-net/src/client/builder.rs +++ b/distant-net/src/client/builder.rs @@ -14,12 +14,12 @@ use std::time::Duration; use std::{convert, io}; use async_trait::async_trait; +use distant_auth::AuthHandler; #[cfg(windows)] pub use windows::*; use super::ClientConfig; use crate::client::{Client, UntypedClient}; -use crate::common::authentication::AuthHandler; use crate::common::{Connection, Transport}; /// Interface that performs the connection to produce a [`Transport`] for use by the [`Client`]. diff --git a/distant-net/src/common.rs b/distant-net/src/common.rs index 7f9ba94..5f793c8 100644 --- a/distant-net/src/common.rs +++ b/distant-net/src/common.rs @@ -1,7 +1,8 @@ mod any; -pub mod authentication; mod connection; mod destination; +mod key; +mod keychain; mod listener; mod map; mod packet; @@ -13,6 +14,8 @@ pub use any::*; pub(crate) use connection::Connection; pub use connection::ConnectionId; pub use destination::*; +pub use key::*; +pub use keychain::*; pub use listener::*; pub use map::*; pub use packet::*; diff --git a/distant-net/src/common/authentication.rs b/distant-net/src/common/authentication.rs deleted file mode 100644 index 2a18ccd..0000000 --- a/distant-net/src/common/authentication.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod authenticator; -mod handler; -mod keychain; -mod methods; -pub mod msg; - -pub use authenticator::*; -pub use handler::*; -pub use keychain::*; -pub use methods::*; diff --git a/distant-net/src/common/authentication/methods/static_key.rs b/distant-net/src/common/authentication/methods/static_key.rs deleted file mode 100644 index f0d9338..0000000 --- a/distant-net/src/common/authentication/methods/static_key.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::io; - -use async_trait::async_trait; - -use super::{AuthenticationMethod, Authenticator, Challenge, Error, Question}; -use crate::common::HeapSecretKey; - -/// Authenticaton method for a static secret key -#[derive(Clone, Debug)] -pub struct StaticKeyAuthenticationMethod { - key: HeapSecretKey, -} - -impl StaticKeyAuthenticationMethod { - #[inline] - pub fn new(key: impl Into) -> Self { - Self { key: key.into() } - } -} - -#[async_trait] -impl AuthenticationMethod for StaticKeyAuthenticationMethod { - fn id(&self) -> &'static str { - "static_key" - } - - async fn authenticate(&self, authenticator: &mut dyn Authenticator) -> io::Result<()> { - let response = authenticator - .challenge(Challenge { - questions: vec![Question { - label: "key".to_string(), - text: "Provide a key: ".to_string(), - options: Default::default(), - }], - options: Default::default(), - }) - .await?; - - if response.answers.is_empty() { - return Err(Error::non_fatal("missing answer").into_io_permission_denied()); - } - - match response - .answers - .into_iter() - .next() - .unwrap() - .parse::() - { - Ok(key) if key == self.key => Ok(()), - _ => Err(Error::non_fatal("answer does not match key").into_io_permission_denied()), - } - } -} - -#[cfg(test)] -mod tests { - use test_log::test; - - use super::*; - use crate::common::authentication::msg::{AuthenticationResponse, ChallengeResponse}; - use crate::common::FramedTransport; - - #[test(tokio::test)] - async fn authenticate_should_fail_if_key_challenge_fails() { - let method = StaticKeyAuthenticationMethod::new(b"".to_vec()); - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up an invalid frame for our challenge to ensure it fails - t2.write_frame(b"invalid initialization response") - .await - .unwrap(); - - assert_eq!( - method.authenticate(&mut t1).await.unwrap_err().kind(), - io::ErrorKind::InvalidData - ); - } - - #[test(tokio::test)] - async fn authenticate_should_fail_if_no_answer_included_in_challenge_response() { - let method = StaticKeyAuthenticationMethod::new(b"".to_vec()); - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Challenge(ChallengeResponse { - answers: Vec::new(), - })) - .await - .unwrap(); - - assert_eq!( - method.authenticate(&mut t1).await.unwrap_err().kind(), - io::ErrorKind::PermissionDenied - ); - } - - #[test(tokio::test)] - async fn authenticate_should_fail_if_answer_does_not_match_key() { - let method = StaticKeyAuthenticationMethod::new(b"answer".to_vec()); - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Challenge(ChallengeResponse { - answers: vec![HeapSecretKey::from(b"some key".to_vec()).to_string()], - })) - .await - .unwrap(); - - assert_eq!( - method.authenticate(&mut t1).await.unwrap_err().kind(), - io::ErrorKind::PermissionDenied - ); - } - - #[test(tokio::test)] - async fn authenticate_should_succeed_if_answer_matches_key() { - let method = StaticKeyAuthenticationMethod::new(b"answer".to_vec()); - let (mut t1, mut t2) = FramedTransport::test_pair(100); - - // Queue up a response to the initialization request - t2.write_frame_for(&AuthenticationResponse::Challenge(ChallengeResponse { - answers: vec![HeapSecretKey::from(b"answer".to_vec()).to_string()], - })) - .await - .unwrap(); - - method.authenticate(&mut t1).await.unwrap(); - } -} diff --git a/distant-net/src/common/connection.rs b/distant-net/src/common/connection.rs index 8d7ba6d..acb434b 100644 --- a/distant-net/src/common/connection.rs +++ b/distant-net/src/common/connection.rs @@ -2,14 +2,16 @@ use std::io; use std::ops::{Deref, DerefMut}; use async_trait::async_trait; +use distant_auth::{AuthHandler, Authenticate, Verifier}; use log::*; use serde::{Deserialize, Serialize}; use tokio::sync::oneshot; -use super::authentication::{AuthHandler, Authenticate, Keychain, KeychainResult, Verifier}; #[cfg(test)] -use super::InmemoryTransport; -use super::{Backup, FramedTransport, HeapSecretKey, Reconnectable, Transport}; +use crate::common::InmemoryTransport; +use crate::common::{ + Backup, FramedTransport, HeapSecretKey, Keychain, KeychainResult, Reconnectable, Transport, +}; /// Id of the connection pub type ConnectionId = u32; @@ -455,11 +457,11 @@ impl Connection { mod tests { use std::sync::Arc; + use distant_auth::msg::Challenge; + use distant_auth::{Authenticator, DummyAuthHandler}; use test_log::test; use super::*; - use crate::common::authentication::msg::Challenge; - use crate::common::authentication::{Authenticator, DummyAuthHandler}; use crate::common::Frame; #[test(tokio::test)] diff --git a/distant-net/src/common/transport/framed/codec/encryption/key.rs b/distant-net/src/common/key.rs similarity index 100% rename from distant-net/src/common/transport/framed/codec/encryption/key.rs rename to distant-net/src/common/key.rs diff --git a/distant-net/src/common/authentication/keychain.rs b/distant-net/src/common/keychain.rs similarity index 100% rename from distant-net/src/common/authentication/keychain.rs rename to distant-net/src/common/keychain.rs diff --git a/distant-net/src/common/transport/framed.rs b/distant-net/src/common/transport/framed.rs index 39330d4..da0bf8b 100644 --- a/distant-net/src/common/transport/framed.rs +++ b/distant-net/src/common/transport/framed.rs @@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize}; use super::{InmemoryTransport, Interest, Ready, Reconnectable, Transport}; use crate::common::utils; +use crate::common::SecretKey32; mod backup; mod codec; diff --git a/distant-net/src/common/transport/framed/codec/encryption.rs b/distant-net/src/common/transport/framed/codec/encryption.rs index 9ac553a..f0f6632 100644 --- a/distant-net/src/common/transport/framed/codec/encryption.rs +++ b/distant-net/src/common/transport/framed/codec/encryption.rs @@ -3,9 +3,7 @@ use std::{fmt, io}; use derive_more::Display; use super::{Codec, Frame}; - -mod key; -pub use key::*; +use crate::common::{SecretKey, SecretKey32}; /// Represents the type of encryption for a [`EncryptionCodec`] #[derive( diff --git a/distant-net/src/common/transport/framed/exchange.rs b/distant-net/src/common/transport/framed/exchange.rs index 30dad35..3545495 100644 --- a/distant-net/src/common/transport/framed/exchange.rs +++ b/distant-net/src/common/transport/framed/exchange.rs @@ -6,7 +6,7 @@ use p256::PublicKey; use rand::rngs::OsRng; use sha2::Sha256; -use super::SecretKey32; +use crate::common::SecretKey32; mod pkb; pub use pkb::PublicKeyBytes; diff --git a/distant-net/src/lib.rs b/distant-net/src/lib.rs index f153f79..8356caf 100644 --- a/distant-net/src/lib.rs +++ b/distant-net/src/lib.rs @@ -1,3 +1,4 @@ +mod authentication; pub mod client; pub mod common; pub mod manager; @@ -6,3 +7,6 @@ pub mod server; pub use client::{Client, ReconnectStrategy}; pub use server::Server; pub use {log, paste}; + +/// Authentication functionality tied to network operations. +pub use distant_auth as auth; diff --git a/distant-net/src/manager/client.rs b/distant-net/src/manager/client.rs index f1cde90..fe3d038 100644 --- a/distant-net/src/manager/client.rs +++ b/distant-net/src/manager/client.rs @@ -1,10 +1,10 @@ use std::io; +use distant_auth::msg::{Authentication, AuthenticationResponse}; +use distant_auth::AuthHandler; use log::*; use crate::client::Client; -use crate::common::authentication::msg::{Authentication, AuthenticationResponse}; -use crate::common::authentication::AuthHandler; use crate::common::{ConnectionId, Destination, Map, Request}; use crate::manager::data::{ ConnectionInfo, ConnectionList, ManagerCapabilities, ManagerRequest, ManagerResponse, @@ -298,9 +298,10 @@ impl ManagerClient { #[cfg(test)] mod tests { + use distant_auth::DummyAuthHandler; + use super::*; use crate::client::UntypedClient; - use crate::common::authentication::DummyAuthHandler; use crate::common::{Connection, InmemoryTransport, Request, Response}; fn setup() -> (ManagerClient, Connection) { diff --git a/distant-net/src/manager/data/request.rs b/distant-net/src/manager/data/request.rs index 74ab8fd..938b2f1 100644 --- a/distant-net/src/manager/data/request.rs +++ b/distant-net/src/manager/data/request.rs @@ -1,9 +1,9 @@ use derive_more::IsVariant; +use distant_auth::msg::AuthenticationResponse; use serde::{Deserialize, Serialize}; use strum::{AsRefStr, EnumDiscriminants, EnumIter, EnumMessage, EnumString}; use super::{ManagerAuthenticationId, ManagerChannelId}; -use crate::common::authentication::msg::AuthenticationResponse; use crate::common::{ConnectionId, Destination, Map, UntypedRequest}; #[allow(clippy::large_enum_variant)] diff --git a/distant-net/src/manager/data/response.rs b/distant-net/src/manager/data/response.rs index 5fd566a..3ee84b1 100644 --- a/distant-net/src/manager/data/response.rs +++ b/distant-net/src/manager/data/response.rs @@ -1,9 +1,9 @@ +use distant_auth::msg::Authentication; use serde::{Deserialize, Serialize}; use super::{ ConnectionInfo, ConnectionList, ManagerAuthenticationId, ManagerCapabilities, ManagerChannelId, }; -use crate::common::authentication::msg::Authentication; use crate::common::{ConnectionId, Destination, UntypedResponse}; #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/distant-net/src/manager/server.rs b/distant-net/src/manager/server.rs index a05f821..d7cb6db 100644 --- a/distant-net/src/manager/server.rs +++ b/distant-net/src/manager/server.rs @@ -3,10 +3,10 @@ use std::io; use std::sync::Arc; use async_trait::async_trait; +use distant_auth::msg::AuthenticationResponse; use log::*; use tokio::sync::{oneshot, RwLock}; -use crate::common::authentication::msg::AuthenticationResponse; use crate::common::{ConnectionId, Destination, Map}; use crate::manager::{ ConnectionInfo, ConnectionList, ManagerAuthenticationId, ManagerCapabilities, ManagerChannelId, diff --git a/distant-net/src/manager/server/authentication.rs b/distant-net/src/manager/server/authentication.rs index 135c31b..74ae48a 100644 --- a/distant-net/src/manager/server/authentication.rs +++ b/distant-net/src/manager/server/authentication.rs @@ -3,10 +3,10 @@ use std::io; use std::sync::Arc; use async_trait::async_trait; +use distant_auth::msg::*; +use distant_auth::Authenticator; use tokio::sync::{oneshot, RwLock}; -use crate::common::authentication::msg::*; -use crate::common::authentication::Authenticator; use crate::manager::data::{ManagerAuthenticationId, ManagerResponse}; use crate::server::ServerReply; diff --git a/distant-net/src/manager/server/handler.rs b/distant-net/src/manager/server/handler.rs index 4a76a1d..ee86f53 100644 --- a/distant-net/src/manager/server/handler.rs +++ b/distant-net/src/manager/server/handler.rs @@ -2,9 +2,9 @@ use std::future::Future; use std::io; use async_trait::async_trait; +use distant_auth::Authenticator; use crate::client::UntypedClient; -use crate::common::authentication::Authenticator; use crate::common::{Destination, Map}; pub type BoxedLaunchHandler = Box; @@ -67,19 +67,15 @@ macro_rules! boxed_launch_handler { let x: $crate::manager::BoxedLaunchHandler = Box::new( |$destination: &$crate::common::Destination, $options: &$crate::common::Map, - $authenticator: &mut dyn $crate::common::authentication::Authenticator| async { - $body - }, + $authenticator: &mut dyn $crate::auth::Authenticator| async { $body }, ); x }}; (move |$destination:ident, $options:ident, $authenticator:ident| $(async)? $body:block) => {{ let x: $crate::manager::BoxedLaunchHandler = Box::new( move |$destination: &$crate::common::Destination, - $options: &$crate::common::Map, - $authenticator: &mut dyn $crate::common::authentication::Authenticator| async move { - $body - }, + $options: &$crate::common::Map, + $authenticator: &mut dyn $crate::auth::Authenticator| async move { $body }, ); x }}; @@ -141,19 +137,15 @@ macro_rules! boxed_connect_handler { let x: $crate::manager::BoxedConnectHandler = Box::new( |$destination: &$crate::common::Destination, $options: &$crate::common::Map, - $authenticator: &mut dyn $crate::common::authentication::Authenticator| async { - $body - }, + $authenticator: &mut dyn $crate::auth::Authenticator| async { $body }, ); x }}; (move |$destination:ident, $options:ident, $authenticator:ident| $(async)? $body:block) => {{ let x: $crate::manager::BoxedConnectHandler = Box::new( move |$destination: &$crate::common::Destination, - $options: &$crate::common::Map, - $authenticator: &mut dyn $crate::common::authentication::Authenticator| async move { - $body - }, + $options: &$crate::common::Map, + $authenticator: &mut dyn $crate::auth::Authenticator| async move { $body }, ); x }}; diff --git a/distant-net/src/server.rs b/distant-net/src/server.rs index c2a6ed4..248a176 100644 --- a/distant-net/src/server.rs +++ b/distant-net/src/server.rs @@ -3,12 +3,12 @@ use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; +use distant_auth::Verifier; use log::*; use serde::de::DeserializeOwned; use serde::Serialize; use tokio::sync::{broadcast, RwLock}; -use crate::common::authentication::Verifier; use crate::common::{Listener, Response, Transport}; mod builder; @@ -246,13 +246,11 @@ mod tests { use std::time::Duration; use async_trait::async_trait; + use distant_auth::{AuthenticationMethod, DummyAuthHandler, NoneAuthenticationMethod}; use test_log::test; use tokio::sync::mpsc; use super::*; - use crate::common::authentication::{ - AuthenticationMethod, DummyAuthHandler, NoneAuthenticationMethod, - }; use crate::common::{Connection, InmemoryTransport, MpscListener, Request, Response}; pub struct TestServerHandler; diff --git a/distant-net/src/server/builder/tcp.rs b/distant-net/src/server/builder/tcp.rs index 7a94420..2abf3a7 100644 --- a/distant-net/src/server/builder/tcp.rs +++ b/distant-net/src/server/builder/tcp.rs @@ -1,10 +1,10 @@ use std::io; use std::net::IpAddr; +use distant_auth::Verifier; use serde::de::DeserializeOwned; use serde::Serialize; -use crate::common::authentication::Verifier; use crate::common::{PortRange, TcpListener}; use crate::server::{Server, ServerConfig, ServerHandler, TcpServerRef}; @@ -60,11 +60,11 @@ mod tests { use std::net::{Ipv6Addr, SocketAddr}; use async_trait::async_trait; + use distant_auth::DummyAuthHandler; use test_log::test; use super::*; use crate::client::Client; - use crate::common::authentication::DummyAuthHandler; use crate::common::Request; use crate::server::ServerCtx; diff --git a/distant-net/src/server/builder/unix.rs b/distant-net/src/server/builder/unix.rs index a934544..e6b77c7 100644 --- a/distant-net/src/server/builder/unix.rs +++ b/distant-net/src/server/builder/unix.rs @@ -1,10 +1,10 @@ use std::io; use std::path::Path; +use distant_auth::Verifier; use serde::de::DeserializeOwned; use serde::Serialize; -use crate::common::authentication::Verifier; use crate::common::UnixSocketListener; use crate::server::{Server, ServerConfig, ServerHandler, UnixSocketServerRef}; @@ -59,12 +59,12 @@ where #[cfg(test)] mod tests { use async_trait::async_trait; + use distant_auth::DummyAuthHandler; use tempfile::NamedTempFile; use test_log::test; use super::*; use crate::client::Client; - use crate::common::authentication::DummyAuthHandler; use crate::common::Request; use crate::server::ServerCtx; diff --git a/distant-net/src/server/connection.rs b/distant-net/src/server/connection.rs index 1f63519..ce79116 100644 --- a/distant-net/src/server/connection.rs +++ b/distant-net/src/server/connection.rs @@ -5,6 +5,7 @@ use std::sync::{Arc, Weak}; use std::task::{Context, Poll}; use std::time::{Duration, Instant}; +use distant_auth::Verifier; use log::*; use serde::de::DeserializeOwned; use serde::Serialize; @@ -15,8 +16,9 @@ use super::{ ConnectionCtx, ConnectionState, ServerCtx, ServerHandler, ServerReply, ServerState, ShutdownTimer, }; -use crate::common::authentication::{Keychain, Verifier}; -use crate::common::{Backup, Connection, Frame, Interest, Response, Transport, UntypedRequest}; +use crate::common::{ + Backup, Connection, Frame, Interest, Keychain, Response, Transport, UntypedRequest, +}; pub type ServerKeychain = Keychain>; @@ -591,10 +593,10 @@ mod tests { use std::sync::atomic::{AtomicBool, Ordering}; use async_trait::async_trait; + use distant_auth::DummyAuthHandler; use test_log::test; use super::*; - use crate::common::authentication::DummyAuthHandler; use crate::common::{ HeapSecretKey, InmemoryTransport, Ready, Reconnectable, Request, Response, }; diff --git a/distant-net/src/server/state.rs b/distant-net/src/server/state.rs index c937f6c..935f945 100644 --- a/distant-net/src/server/state.rs +++ b/distant-net/src/server/state.rs @@ -3,8 +3,7 @@ use std::collections::HashMap; use tokio::sync::{mpsc, oneshot, RwLock}; use tokio::task::JoinHandle; -use crate::common::authentication::Keychain; -use crate::common::{Backup, ConnectionId}; +use crate::common::{Backup, ConnectionId, Keychain}; /// Contains all top-level state for the server pub struct ServerState { diff --git a/distant-net/tests/manager_tests.rs b/distant-net/tests/manager_tests.rs index e32b180..eed4c36 100644 --- a/distant-net/tests/manager_tests.rs +++ b/distant-net/tests/manager_tests.rs @@ -1,9 +1,9 @@ use std::io; use async_trait::async_trait; +use distant_net::auth::{DummyAuthHandler, Verifier}; use distant_net::boxed_connect_handler; use distant_net::client::Client; -use distant_net::common::authentication::{DummyAuthHandler, Verifier}; use distant_net::common::{Destination, InmemoryTransport, Map, OneshotListener}; use distant_net::manager::{Config, ManagerClient, ManagerServer}; use distant_net::server::{Server, ServerCtx, ServerHandler}; diff --git a/distant-net/tests/typed_tests.rs b/distant-net/tests/typed_tests.rs index 650b936..be19b11 100644 --- a/distant-net/tests/typed_tests.rs +++ b/distant-net/tests/typed_tests.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; +use distant_auth::{DummyAuthHandler, Verifier}; use distant_net::client::Client; -use distant_net::common::authentication::{DummyAuthHandler, Verifier}; use distant_net::common::{InmemoryTransport, OneshotListener}; use distant_net::server::{Server, ServerCtx, ServerHandler}; use log::*; diff --git a/distant-net/tests/untyped_tests.rs b/distant-net/tests/untyped_tests.rs index be5cb47..af43d02 100644 --- a/distant-net/tests/untyped_tests.rs +++ b/distant-net/tests/untyped_tests.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; +use distant_auth::{DummyAuthHandler, Verifier}; use distant_net::client::Client; -use distant_net::common::authentication::{DummyAuthHandler, Verifier}; use distant_net::common::{InmemoryTransport, OneshotListener, Request}; use distant_net::server::{Server, ServerCtx, ServerHandler}; use log::*; diff --git a/distant-ssh2/src/lib.rs b/distant-ssh2/src/lib.rs index 0e4b006..b50c5f6 100644 --- a/distant-ssh2/src/lib.rs +++ b/distant-ssh2/src/lib.rs @@ -12,8 +12,8 @@ use std::time::Duration; use async_compat::CompatExt; use async_once_cell::OnceCell; use async_trait::async_trait; +use distant_core::net::auth::{AuthHandlerMap, DummyAuthHandler, Verifier}; use distant_core::net::client::{Client, ClientConfig}; -use distant_core::net::common::authentication::{AuthHandlerMap, DummyAuthHandler, Verifier}; use distant_core::net::common::{Host, InmemoryTransport, OneshotListener}; use distant_core::net::server::{Server, ServerRef}; use distant_core::{DistantApiServerHandler, DistantClient, DistantSingleKeyCredentials}; diff --git a/src/cli/commands/manager/handlers.rs b/src/cli/commands/manager/handlers.rs index d425dfd..9179166 100644 --- a/src/cli/commands/manager/handlers.rs +++ b/src/cli/commands/manager/handlers.rs @@ -5,12 +5,12 @@ use std::process::Stdio; use std::time::Duration; use async_trait::async_trait; -use distant_core::net::client::{Client, ClientConfig, ReconnectStrategy, UntypedClient}; -use distant_core::net::common::authentication::msg::*; -use distant_core::net::common::authentication::{ +use distant_core::net::auth::msg::*; +use distant_core::net::auth::{ AuthHandler, Authenticator, DynAuthHandler, ProxyAuthHandler, SingleAuthHandler, StaticKeyAuthMethodHandler, }; +use distant_core::net::client::{Client, ClientConfig, ReconnectStrategy, UntypedClient}; use distant_core::net::common::{Destination, Map, SecretKey32}; use distant_core::net::manager::{ConnectHandler, LaunchHandler}; use log::*; diff --git a/src/cli/commands/server.rs b/src/cli/commands/server.rs index aa41aaf..1e06efc 100644 --- a/src/cli/commands/server.rs +++ b/src/cli/commands/server.rs @@ -1,7 +1,7 @@ use std::io::{self, Read, Write}; use anyhow::Context; -use distant_core::net::common::authentication::Verifier; +use distant_core::net::auth::Verifier; use distant_core::net::common::{Host, SecretKey32}; use distant_core::net::server::{Server, ServerConfig as NetServerConfig, ServerRef}; use distant_core::{DistantApiServerHandler, DistantSingleKeyCredentials}; diff --git a/src/cli/common/client.rs b/src/cli/common/client.rs index b8af4e5..73dd481 100644 --- a/src/cli/common/client.rs +++ b/src/cli/common/client.rs @@ -2,11 +2,11 @@ use std::io; use std::time::Duration; use async_trait::async_trait; -use distant_core::net::client::{Client as NetClient, ClientConfig, ReconnectStrategy}; -use distant_core::net::common::authentication::msg::*; -use distant_core::net::common::authentication::{ +use distant_core::net::auth::msg::*; +use distant_core::net::auth::{ AuthHandler, AuthMethodHandler, PromptAuthMethodHandler, SingleAuthHandler, }; +use distant_core::net::client::{Client as NetClient, ClientConfig, ReconnectStrategy}; use distant_core::net::manager::ManagerClient; use log::*; diff --git a/src/cli/common/manager.rs b/src/cli/common/manager.rs index 4f9653d..3060214 100644 --- a/src/cli/common/manager.rs +++ b/src/cli/common/manager.rs @@ -1,5 +1,5 @@ use anyhow::Context; -use distant_core::net::common::authentication::Verifier; +use distant_core::net::auth::Verifier; use distant_core::net::manager::{Config as ManagerConfig, ManagerServer}; use distant_core::net::server::ServerRef; use log::*;