1use std::fmt;
2
3use crate::common::Credentials;
4
5#[cfg(feature = "scram")]
6use crate::common::scram::DeriveError;
7#[cfg(feature = "scram")]
8use hmac::digest::InvalidLength;
9
10#[derive(Debug, PartialEq)]
11pub enum MechanismError {
12 AnonymousRequiresNoCredentials,
13
14 PlainRequiresUsername,
15 PlainRequiresPlaintextPassword,
16
17 CannotGenerateNonce,
18 ScramRequiresUsername,
19 ScramRequiresPassword,
20
21 CannotDecodeChallenge,
22 NoServerNonce,
23 NoServerSalt,
24 NoServerIterations,
25 #[cfg(feature = "scram")]
26 DeriveError(DeriveError),
27 #[cfg(feature = "scram")]
28 InvalidKeyLength(InvalidLength),
29 InvalidState,
30
31 CannotDecodeSuccessResponse,
32 InvalidSignatureInSuccessResponse,
33 NoSignatureInSuccessResponse,
34}
35
36#[cfg(feature = "scram")]
37#[cfg_attr(docsrs, doc(cfg(feature = "scram")))]
38impl From<DeriveError> for MechanismError {
39 fn from(err: DeriveError) -> MechanismError {
40 MechanismError::DeriveError(err)
41 }
42}
43
44#[cfg(feature = "scram")]
45#[cfg_attr(docsrs, doc(cfg(feature = "scram")))]
46impl From<InvalidLength> for MechanismError {
47 fn from(err: InvalidLength) -> MechanismError {
48 MechanismError::InvalidKeyLength(err)
49 }
50}
51
52impl fmt::Display for MechanismError {
53 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
54 write!(
55 fmt,
56 "{}",
57 match self {
58 MechanismError::AnonymousRequiresNoCredentials =>
59 "ANONYMOUS mechanism requires no credentials",
60
61 MechanismError::PlainRequiresUsername => "PLAIN requires a username",
62 MechanismError::PlainRequiresPlaintextPassword =>
63 "PLAIN requires a plaintext password",
64
65 MechanismError::CannotGenerateNonce => "can't generate nonce",
66 MechanismError::ScramRequiresUsername => "SCRAM requires a username",
67 MechanismError::ScramRequiresPassword => "SCRAM requires a password",
68
69 MechanismError::CannotDecodeChallenge => "can't decode challenge",
70 MechanismError::NoServerNonce => "no server nonce",
71 MechanismError::NoServerSalt => "no server salt",
72 MechanismError::NoServerIterations => "no server iterations",
73 #[cfg(feature = "scram")]
74 MechanismError::DeriveError(err) => return write!(fmt, "derive error: {}", err),
75 #[cfg(feature = "scram")]
76 MechanismError::InvalidKeyLength(err) =>
77 return write!(fmt, "invalid key length: {}", err),
78 MechanismError::InvalidState => "not in the right state to receive this response",
79
80 MechanismError::CannotDecodeSuccessResponse => "can't decode success response",
81 MechanismError::InvalidSignatureInSuccessResponse =>
82 "invalid signature in success response",
83 MechanismError::NoSignatureInSuccessResponse => "no signature in success response",
84 }
85 )
86 }
87}
88
89impl std::error::Error for MechanismError {}
90
91/// A trait which defines SASL mechanisms.
92pub trait Mechanism {
93 /// The name of the mechanism.
94 fn name(&self) -> &str;
95
96 /// Creates this mechanism from `Credentials`.
97 fn from_credentials(credentials: Credentials) -> Result<Self, MechanismError>
98 where
99 Self: Sized;
100
101 /// Provides initial payload of the SASL mechanism.
102 fn initial(&mut self) -> Vec<u8> {
103 Vec::new()
104 }
105
106 /// Creates a response to the SASL challenge.
107 fn response(&mut self, _challenge: &[u8]) -> Result<Vec<u8>, MechanismError> {
108 Ok(Vec::new())
109 }
110
111 /// Verifies the server success response, if there is one.
112 fn success(&mut self, _data: &[u8]) -> Result<(), MechanismError> {
113 Ok(())
114 }
115}
116
117pub mod mechanisms;