We mostly had to import from alloc some structs that are part of the std prelude, such as Vec and String.
199 lines
6.3 KiB
Rust
199 lines
6.3 KiB
Rust
use crate::common::Identity;
|
||
use crate::secret::Secret;
|
||
use alloc::vec::Vec;
|
||
use core::error::Error;
|
||
use core::fmt;
|
||
|
||
#[cfg(feature = "scram")]
|
||
use crate::common::scram::DeriveError;
|
||
|
||
#[macro_export]
|
||
macro_rules! impl_validator_using_provider {
|
||
( $validator:ty, $secret:ty ) => {
|
||
impl $crate::server::Validator<$secret> for $validator {
|
||
fn validate(
|
||
&self,
|
||
identity: &$crate::common::Identity,
|
||
value: &$secret,
|
||
) -> Result<(), $crate::server::ValidatorError> {
|
||
if $crate::server::Provider::<$secret>::provide(self, identity).is_ok() {
|
||
Ok(())
|
||
} else {
|
||
Err($crate::server::ValidatorError::AuthenticationFailed)
|
||
}
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
pub trait Provider<S: Secret>: Validator<S> {
|
||
fn provide(&self, identity: &Identity) -> Result<S, ProviderError>;
|
||
}
|
||
|
||
pub trait Validator<S: Secret> {
|
||
fn validate(&self, identity: &Identity, value: &S) -> Result<(), ValidatorError>;
|
||
}
|
||
|
||
#[derive(Debug, PartialEq)]
|
||
pub enum ProviderError {
|
||
AuthenticationFailed,
|
||
#[cfg(feature = "scram")]
|
||
DeriveError(DeriveError),
|
||
}
|
||
|
||
#[derive(Debug, PartialEq)]
|
||
pub enum ValidatorError {
|
||
AuthenticationFailed,
|
||
ProviderError(ProviderError),
|
||
}
|
||
|
||
#[derive(Debug, PartialEq)]
|
||
pub enum MechanismError {
|
||
NoUsernameSpecified,
|
||
ErrorDecodingUsername,
|
||
NoPasswordSpecified,
|
||
ErrorDecodingPassword,
|
||
ValidatorError(ValidatorError),
|
||
|
||
FailedToDecodeMessage,
|
||
ChannelBindingNotSupported,
|
||
ChannelBindingIsSupported,
|
||
ChannelBindingMechanismIncorrect,
|
||
CannotDecodeInitialMessage,
|
||
NoUsername,
|
||
NoNonce,
|
||
FailedToGenerateNonce,
|
||
ProviderError(ProviderError),
|
||
|
||
CannotDecodeResponse,
|
||
#[cfg(feature = "scram")]
|
||
InvalidKeyLength(hmac::digest::InvalidLength),
|
||
#[cfg(any(feature = "scram", feature = "anonymous"))]
|
||
RandomFailure(getrandom::Error),
|
||
NoProof,
|
||
CannotDecodeProof,
|
||
AuthenticationFailed,
|
||
SaslSessionAlreadyOver,
|
||
}
|
||
|
||
#[cfg(feature = "scram")]
|
||
impl From<DeriveError> for ProviderError {
|
||
fn from(err: DeriveError) -> ProviderError {
|
||
ProviderError::DeriveError(err)
|
||
}
|
||
}
|
||
|
||
impl From<ProviderError> for ValidatorError {
|
||
fn from(err: ProviderError) -> ValidatorError {
|
||
ValidatorError::ProviderError(err)
|
||
}
|
||
}
|
||
|
||
impl From<ProviderError> for MechanismError {
|
||
fn from(err: ProviderError) -> MechanismError {
|
||
MechanismError::ProviderError(err)
|
||
}
|
||
}
|
||
|
||
impl From<ValidatorError> for MechanismError {
|
||
fn from(err: ValidatorError) -> MechanismError {
|
||
MechanismError::ValidatorError(err)
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "scram")]
|
||
impl From<hmac::digest::InvalidLength> for MechanismError {
|
||
fn from(err: hmac::digest::InvalidLength) -> MechanismError {
|
||
MechanismError::InvalidKeyLength(err)
|
||
}
|
||
}
|
||
|
||
#[cfg(any(feature = "scram", feature = "anonymous"))]
|
||
impl From<getrandom::Error> for MechanismError {
|
||
fn from(err: getrandom::Error) -> MechanismError {
|
||
MechanismError::RandomFailure(err)
|
||
}
|
||
}
|
||
|
||
impl fmt::Display for ProviderError {
|
||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||
write!(fmt, "provider error")
|
||
}
|
||
}
|
||
|
||
impl fmt::Display for ValidatorError {
|
||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||
write!(fmt, "validator error")
|
||
}
|
||
}
|
||
|
||
impl fmt::Display for MechanismError {
|
||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||
match self {
|
||
MechanismError::NoUsernameSpecified => write!(fmt, "no username specified"),
|
||
MechanismError::ErrorDecodingUsername => write!(fmt, "error decoding username"),
|
||
MechanismError::NoPasswordSpecified => write!(fmt, "no password specified"),
|
||
MechanismError::ErrorDecodingPassword => write!(fmt, "error decoding password"),
|
||
MechanismError::ValidatorError(err) => write!(fmt, "validator error: {}", err),
|
||
|
||
MechanismError::FailedToDecodeMessage => write!(fmt, "failed to decode message"),
|
||
MechanismError::ChannelBindingNotSupported => {
|
||
write!(fmt, "channel binding not supported")
|
||
}
|
||
MechanismError::ChannelBindingIsSupported => {
|
||
write!(fmt, "channel binding is supported")
|
||
}
|
||
MechanismError::ChannelBindingMechanismIncorrect => {
|
||
write!(fmt, "channel binding mechanism is incorrect")
|
||
}
|
||
MechanismError::CannotDecodeInitialMessage => {
|
||
write!(fmt, "can’t decode initial message")
|
||
}
|
||
MechanismError::NoUsername => write!(fmt, "no username"),
|
||
MechanismError::NoNonce => write!(fmt, "no nonce"),
|
||
MechanismError::FailedToGenerateNonce => write!(fmt, "failed to generate nonce"),
|
||
MechanismError::ProviderError(err) => write!(fmt, "provider error: {}", err),
|
||
|
||
MechanismError::CannotDecodeResponse => write!(fmt, "can’t decode response"),
|
||
#[cfg(feature = "scram")]
|
||
MechanismError::InvalidKeyLength(err) => write!(fmt, "invalid key length: {}", err),
|
||
#[cfg(any(feature = "scram", feature = "anonymous"))]
|
||
MechanismError::RandomFailure(err) => {
|
||
write!(fmt, "failure to get random data: {}", err)
|
||
}
|
||
MechanismError::NoProof => write!(fmt, "no proof"),
|
||
MechanismError::CannotDecodeProof => write!(fmt, "can’t decode proof"),
|
||
MechanismError::AuthenticationFailed => write!(fmt, "authentication failed"),
|
||
MechanismError::SaslSessionAlreadyOver => write!(fmt, "SASL session already over"),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl Error for ProviderError {}
|
||
|
||
impl Error for ValidatorError {}
|
||
|
||
impl Error for MechanismError {
|
||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||
match self {
|
||
MechanismError::ValidatorError(err) => Some(err),
|
||
MechanismError::ProviderError(err) => Some(err),
|
||
// TODO: figure out how to enable the std feature on this crate.
|
||
//MechanismError::InvalidKeyLength(err) => Some(err),
|
||
_ => None,
|
||
}
|
||
}
|
||
}
|
||
|
||
pub trait Mechanism {
|
||
fn name(&self) -> &str;
|
||
fn respond(&mut self, payload: &[u8]) -> Result<Response, MechanismError>;
|
||
}
|
||
|
||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||
pub enum Response {
|
||
Success(Identity, Vec<u8>),
|
||
Proceed(Vec<u8>),
|
||
}
|
||
|
||
pub mod mechanisms;
|