Implement SASL ANONYMOUS on the server side

Emmanuel Gil Peyrot created

Fixes #11.

Change summary

sasl/src/server/mechanisms/anonymous.rs | 28 +++++++++++++++++++++++++++
sasl/src/server/mechanisms/mod.rs       |  2 +
sasl/src/server/mod.rs                  | 10 +++++++++
3 files changed, 40 insertions(+)

Detailed changes

sasl/src/server/mechanisms/anonymous.rs πŸ”—

@@ -0,0 +1,28 @@
+use crate::common::Identity;
+use crate::server::{Mechanism, MechanismError, Response};
+use getrandom::getrandom;
+
+pub struct Anonymous;
+
+impl Anonymous {
+    pub fn new() -> Anonymous {
+        Anonymous
+    }
+}
+
+impl Mechanism for Anonymous {
+    fn name(&self) -> &str {
+        "ANONYMOUS"
+    }
+
+    fn respond(&mut self, payload: &[u8]) -> Result<Response, MechanismError> {
+        if !payload.is_empty() {
+            return Err(MechanismError::FailedToDecodeMessage);
+        }
+        let mut rand = [0u8; 16];
+        getrandom(&mut rand)?;
+        let username = format!("{:02x?}", rand);
+        let ident = Identity::Username(username);
+        Ok(Response::Success(ident, Vec::new()))
+    }
+}

sasl/src/server/mechanisms/mod.rs πŸ”—

@@ -1,7 +1,9 @@
+mod anonymous;
 mod plain;
 #[cfg(feature = "scram")]
 mod scram;
 
+pub use self::anonymous::Anonymous;
 pub use self::plain::Plain;
 #[cfg(feature = "scram")]
 pub use self::scram::Scram;

sasl/src/server/mod.rs πŸ”—

@@ -62,6 +62,7 @@ pub enum MechanismError {
 
     CannotDecodeResponse,
     InvalidKeyLength(hmac::digest::InvalidLength),
+    RandomFailure(getrandom::Error),
     NoProof,
     CannotDecodeProof,
     AuthenticationFailed,
@@ -98,6 +99,12 @@ impl From<hmac::digest::InvalidLength> for MechanismError {
     }
 }
 
+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")
@@ -139,6 +146,9 @@ impl fmt::Display for MechanismError {
 
             MechanismError::CannotDecodeResponse => write!(fmt, "can’t decode response"),
             MechanismError::InvalidKeyLength(err) => write!(fmt, "invalid key length: {}", err),
+            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"),