1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
use async_trait::async_trait;
use bytes::{BufMut, BytesMut};
/// Type to represent an authentication error message.
pub type AuthError = String;
/// Trait used to represent a user-defined custom authentication.
#[async_trait]
pub trait AuthenticatorSession: Send + Sync {
/// To handle an authentication challenge initiated by the server.
/// The information contained in the token parameter is authentication protocol specific.
/// It may be NULL or empty.
async fn evaluate_challenge(
&mut self,
token: Option<&[u8]>,
) -> Result<Option<Vec<u8>>, AuthError>;
/// To handle the success phase of exchange.
/// The token parameters contain information that may be used to finalize the request.
async fn success(&mut self, token: Option<&[u8]>) -> Result<(), AuthError>;
}
/// Trait used to represent a factory of [`AuthenticatorSession`] instances.
/// A new [`AuthenticatorSession`] instance will be created for each session.
///
/// The custom authenticator can be set using SessionBuilder::authenticator_provider method.
///
/// Default: [`PlainTextAuthenticator`] is the default authenticator which requires username and
/// password. It can be set by using SessionBuilder::user(\"user\", \"pass\") method.
#[async_trait]
pub trait AuthenticatorProvider: Sync + Send {
/// A pair of initial response and boxed [`AuthenticatorSession`]
/// should be returned if authentication is required by the server.
async fn start_authentication_session(
&self,
authenticator_name: &str,
) -> Result<(Option<Vec<u8>>, Box<dyn AuthenticatorSession>), AuthError>;
}
struct PlainTextAuthenticatorSession;
#[async_trait]
impl AuthenticatorSession for PlainTextAuthenticatorSession {
async fn evaluate_challenge(
&mut self,
_token: Option<&[u8]>,
) -> Result<Option<Vec<u8>>, AuthError> {
Err("Challenges are not expected during PlainTextAuthentication".to_string())
}
async fn success(&mut self, _token: Option<&[u8]>) -> Result<(), AuthError> {
Ok(())
}
}
/// Default authenticator provider that requires username and password if authentication is required.
pub struct PlainTextAuthenticator {
username: String,
password: String,
}
impl PlainTextAuthenticator {
/// Creates new [`PlainTextAuthenticator`] instance with provided username and password.
pub fn new(username: String, password: String) -> Self {
PlainTextAuthenticator { username, password }
}
}
#[async_trait]
impl AuthenticatorProvider for PlainTextAuthenticator {
async fn start_authentication_session(
&self,
_authenticator_name: &str,
) -> Result<(Option<Vec<u8>>, Box<dyn AuthenticatorSession>), AuthError> {
let mut response = BytesMut::new();
let username_as_bytes = self.username.as_bytes();
let password_as_bytes = self.password.as_bytes();
response.put_u8(0);
response.put_slice(username_as_bytes);
response.put_u8(0);
response.put_slice(password_as_bytes);
Ok((
Some(response.to_vec()),
Box::new(PlainTextAuthenticatorSession),
))
}
}