You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
distant/distant-net/src/manager/server/authentication.rs

103 lines
3.5 KiB
Rust

use std::collections::HashMap;
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::manager::data::{ManagerAuthenticationId, ManagerResponse};
use crate::server::ServerReply;
/// Implementation of [`Authenticator`] used by a manger to perform authentication with
/// remote servers it is managing.
#[derive(Clone)]
pub struct ManagerAuthenticator {
/// Used to communicate authentication requests
pub(super) reply: ServerReply<ManagerResponse>,
/// Used to store one-way response senders that are used to return callbacks
pub(super) registry:
Arc<RwLock<HashMap<ManagerAuthenticationId, oneshot::Sender<AuthenticationResponse>>>>,
}
impl ManagerAuthenticator {
/// Sends an [`Authentication`] `msg` that expects a reply, storing a callback.
async fn send(&self, msg: Authentication) -> io::Result<AuthenticationResponse> {
let (tx, rx) = oneshot::channel();
let id = rand::random();
self.registry.write().await.insert(id, tx);
self.reply.send(ManagerResponse::Authenticate { id, msg })?;
rx.await
.map_err(|x| io::Error::new(io::ErrorKind::Other, x))
}
/// Sends an [`Authentication`] `msg` without expecting a reply. No callback is stored.
fn fire(&self, msg: Authentication) -> io::Result<()> {
let id = rand::random();
self.reply.send(ManagerResponse::Authenticate { id, msg })?;
Ok(())
}
}
/// Represents an interface for submitting challenges for authentication.
#[async_trait]
impl Authenticator for ManagerAuthenticator {
async fn initialize(
&mut self,
initialization: Initialization,
) -> io::Result<InitializationResponse> {
match self
.send(Authentication::Initialization(initialization))
.await
{
Ok(AuthenticationResponse::Initialization(x)) => Ok(x),
Ok(x) => Err(io::Error::new(
io::ErrorKind::Other,
format!("Unexpected response: {x:?}"),
)),
Err(x) => Err(x),
}
}
async fn challenge(&mut self, challenge: Challenge) -> io::Result<ChallengeResponse> {
match self.send(Authentication::Challenge(challenge)).await {
Ok(AuthenticationResponse::Challenge(x)) => Ok(x),
Ok(x) => Err(io::Error::new(
io::ErrorKind::Other,
format!("Unexpected response: {x:?}"),
)),
Err(x) => Err(x),
}
}
async fn verify(&mut self, verification: Verification) -> io::Result<VerificationResponse> {
match self.send(Authentication::Verification(verification)).await {
Ok(AuthenticationResponse::Verification(x)) => Ok(x),
Ok(x) => Err(io::Error::new(
io::ErrorKind::Other,
format!("Unexpected response: {x:?}"),
)),
Err(x) => Err(x),
}
}
async fn info(&mut self, info: Info) -> io::Result<()> {
self.fire(Authentication::Info(info))
}
async fn error(&mut self, error: Error) -> io::Result<()> {
self.fire(Authentication::Error(error))
}
async fn start_method(&mut self, start_method: StartMethod) -> io::Result<()> {
self.fire(Authentication::StartMethod(start_method))
}
async fn finished(&mut self) -> io::Result<()> {
self.fire(Authentication::Finished)
}
}