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