feat(transport): Remove support for CRAM-MD5
It is obsolete and may give a false sense of security. We may add a better mechanism later.
This commit is contained in:
@@ -24,10 +24,7 @@ nom = { version = "^3.2", optional = true }
|
||||
bufstream = { version = "^0.1", optional = true }
|
||||
native-tls = { version = "^0.1", optional = true }
|
||||
base64 = { version = "^0.9", optional = true }
|
||||
hex = { version = "^0.3", optional = true }
|
||||
hostname = { version = "^0.1", optional = true }
|
||||
md-5 = { version = "^0.7", optional = true }
|
||||
hmac = { version = "^0.6", optional = true }
|
||||
serde = { version = "^1.0", optional = true }
|
||||
serde_json = { version = "^1.0", optional = true }
|
||||
serde_derive = { version = "^1.0", optional = true }
|
||||
@@ -41,7 +38,6 @@ default = ["file-transport", "smtp-transport", "sendmail-transport"]
|
||||
unstable = []
|
||||
serde-impls = ["serde", "serde_derive"]
|
||||
file-transport = ["serde-impls", "serde_json"]
|
||||
crammd5-auth = ["md-5", "hmac", "hex"]
|
||||
smtp-transport = ["bufstream", "native-tls", "base64", "nom", "hostname"]
|
||||
sendmail-transport = []
|
||||
|
||||
|
||||
@@ -10,16 +10,10 @@
|
||||
extern crate base64;
|
||||
#[cfg(feature = "smtp-transport")]
|
||||
extern crate bufstream;
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
extern crate hex;
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
extern crate hmac;
|
||||
#[cfg(feature = "smtp-transport")]
|
||||
extern crate hostname;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
extern crate md5;
|
||||
#[cfg(feature = "smtp-transport")]
|
||||
extern crate native_tls;
|
||||
#[cfg(feature = "smtp-transport")]
|
||||
|
||||
@@ -1,31 +1,14 @@
|
||||
//! Provides authentication mechanisms
|
||||
//! Provides limited SASL authentication mechanisms
|
||||
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
use md5::Md5;
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
use hmac::{Hmac, Mac};
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
use hex;
|
||||
use smtp::NUL;
|
||||
use smtp::error::Error;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
/// Accepted authentication mechanisms on an encrypted connection
|
||||
/// Trying LOGIN last as it is deprecated.
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
pub const DEFAULT_ENCRYPTED_MECHANISMS: &[Mechanism] =
|
||||
&[Mechanism::Plain, Mechanism::CramMd5, Mechanism::Login];
|
||||
/// Accepted authentication mechanisms on an encrypted connection
|
||||
/// Trying LOGIN last as it is deprecated.
|
||||
#[cfg(not(feature = "crammd5-auth"))]
|
||||
pub const DEFAULT_ENCRYPTED_MECHANISMS: &[Mechanism] = &[Mechanism::Plain, Mechanism::Login];
|
||||
|
||||
/// Accepted authentication mechanisms on an unencrypted connection
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
pub const DEFAULT_UNENCRYPTED_MECHANISMS: &[Mechanism] = &[Mechanism::CramMd5];
|
||||
/// Accepted authentication mechanisms on an unencrypted connection
|
||||
/// When CRAMMD5 support is not enabled, no mechanisms are allowed.
|
||||
#[cfg(not(feature = "crammd5-auth"))]
|
||||
pub const DEFAULT_UNENCRYPTED_MECHANISMS: &[Mechanism] = &[];
|
||||
|
||||
/// Convertable to user credentials
|
||||
@@ -51,14 +34,14 @@ impl<S: Into<String>, T: Into<String>> IntoCredentials for (S, T) {
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
|
||||
pub struct Credentials {
|
||||
username: String,
|
||||
password: String,
|
||||
authentication_identity: String,
|
||||
secret: String,
|
||||
}
|
||||
|
||||
impl Credentials {
|
||||
/// Create a `Credentials` struct from username and password
|
||||
pub fn new(username: String, password: String) -> Credentials {
|
||||
Credentials { username, password }
|
||||
Credentials { authentication_identity: username, secret: password }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,10 +56,6 @@ pub enum Mechanism {
|
||||
/// Obsolete but needed for some providers (like office365)
|
||||
/// https://www.ietf.org/archive/id/draft-murchison-sasl-login-00.txt
|
||||
Login,
|
||||
/// CRAM-MD5 authentication mechanism
|
||||
/// RFC 2195: https://tools.ietf.org/html/rfc2195
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
CramMd5,
|
||||
}
|
||||
|
||||
impl Display for Mechanism {
|
||||
@@ -87,8 +66,6 @@ impl Display for Mechanism {
|
||||
match *self {
|
||||
Mechanism::Plain => "PLAIN",
|
||||
Mechanism::Login => "LOGIN",
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
Mechanism::CramMd5 => "CRAM-MD5",
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -101,8 +78,6 @@ impl Mechanism {
|
||||
match *self {
|
||||
Mechanism::Plain => true,
|
||||
Mechanism::Login => false,
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
Mechanism::CramMd5 => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +93,7 @@ impl Mechanism {
|
||||
Some(_) => Err(Error::Client("This mechanism does not expect a challenge")),
|
||||
None => Ok(format!(
|
||||
"{}{}{}{}",
|
||||
NUL, credentials.username, NUL, credentials.password
|
||||
NUL, credentials.authentication_identity, NUL, credentials.secret
|
||||
)),
|
||||
},
|
||||
Mechanism::Login => {
|
||||
@@ -128,32 +103,15 @@ impl Mechanism {
|
||||
};
|
||||
|
||||
if vec!["User Name", "Username:", "Username"].contains(&decoded_challenge) {
|
||||
return Ok(credentials.username.to_string());
|
||||
return Ok(credentials.authentication_identity.to_string());
|
||||
}
|
||||
|
||||
if vec!["Password", "Password:"].contains(&decoded_challenge) {
|
||||
return Ok(credentials.password.to_string());
|
||||
return Ok(credentials.secret.to_string());
|
||||
}
|
||||
|
||||
Err(Error::Client("Unrecognized challenge"))
|
||||
}
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
Mechanism::CramMd5 => {
|
||||
let decoded_challenge = match challenge {
|
||||
Some(challenge) => challenge,
|
||||
None => return Err(Error::Client("This mechanism does expect a challenge")),
|
||||
};
|
||||
|
||||
let mut hmac: Hmac<Md5> = Hmac::new_varkey(credentials.password.as_bytes())
|
||||
.expect("md5 should support variable key size");
|
||||
hmac.input(decoded_challenge.as_bytes());
|
||||
|
||||
Ok(format!(
|
||||
"{} {}",
|
||||
credentials.username,
|
||||
hex::encode(hmac.result().code())
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,23 +149,4 @@ mod test {
|
||||
);
|
||||
assert!(mechanism.response(&credentials, None).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
fn test_cram_md5() {
|
||||
let mechanism = Mechanism::CramMd5;
|
||||
|
||||
let credentials = Credentials::new("alice".to_string(), "wonderland".to_string());
|
||||
|
||||
assert_eq!(
|
||||
mechanism
|
||||
.response(
|
||||
&credentials,
|
||||
Some("PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg==")
|
||||
)
|
||||
.unwrap(),
|
||||
"alice a540ebe4ef2304070bbc3c456c1f64c0"
|
||||
);
|
||||
assert!(mechanism.response(&credentials, None).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,8 +313,6 @@ impl AuthCommand {
|
||||
mod test {
|
||||
use super::*;
|
||||
use smtp::extension::MailBodyParameter;
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
use smtp::response::{Category, Code, Detail, Severity};
|
||||
|
||||
#[test]
|
||||
fn test_display() {
|
||||
@@ -391,18 +389,6 @@ mod test {
|
||||
),
|
||||
"AUTH PLAIN AHVzZXIAcGFzc3dvcmQ=\r\n"
|
||||
);
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
AuthCommand::new(
|
||||
Mechanism::CramMd5,
|
||||
credentials.clone(),
|
||||
Some("test".to_string()),
|
||||
).unwrap()
|
||||
),
|
||||
"dXNlciAzMTYxY2NmZDdmMjNlMzJiYmMzZTQ4NjdmYzk0YjE4Nw==\r\n"
|
||||
);
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
@@ -410,24 +396,5 @@ mod test {
|
||||
),
|
||||
"AUTH LOGIN\r\n"
|
||||
);
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
AuthCommand::new_from_response(
|
||||
Mechanism::CramMd5,
|
||||
credentials.clone(),
|
||||
&Response::new(
|
||||
Code::new(
|
||||
Severity::PositiveIntermediate,
|
||||
Category::Unspecified3,
|
||||
Detail::Four,
|
||||
),
|
||||
vec!["dGVzdAo=".to_string()],
|
||||
),
|
||||
).unwrap()
|
||||
),
|
||||
"dXNlciA1NTIzNThiMzExOWFjOWNkYzM2YWRiN2MxNWRmMWJkNw==\r\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,10 +145,6 @@ impl ServerInfo {
|
||||
"LOGIN" => {
|
||||
features.insert(Extension::Authentication(Mechanism::Login));
|
||||
}
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
"CRAM-MD5" => {
|
||||
features.insert(Extension::Authentication(Mechanism::CramMd5));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
@@ -357,8 +353,6 @@ mod test {
|
||||
|
||||
assert!(server_info.supports_feature(Extension::EightBitMime));
|
||||
assert!(!server_info.supports_feature(Extension::StartTls));
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
assert!(!server_info.supports_auth_mechanism(Mechanism::CramMd5));
|
||||
|
||||
let response2 = Response::new(
|
||||
Code::new(
|
||||
@@ -377,8 +371,6 @@ mod test {
|
||||
let mut features2 = HashSet::new();
|
||||
assert!(features2.insert(Extension::EightBitMime));
|
||||
assert!(features2.insert(Extension::Authentication(Mechanism::Plain),));
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
assert!(features2.insert(Extension::Authentication(Mechanism::CramMd5),));
|
||||
|
||||
let server_info2 = ServerInfo {
|
||||
name: "me".to_string(),
|
||||
@@ -389,8 +381,6 @@ mod test {
|
||||
|
||||
assert!(server_info2.supports_feature(Extension::EightBitMime));
|
||||
assert!(server_info2.supports_auth_mechanism(Mechanism::Plain));
|
||||
#[cfg(feature = "crammd5-auth")]
|
||||
assert!(server_info2.supports_auth_mechanism(Mechanism::CramMd5));
|
||||
assert!(!server_info2.supports_feature(Extension::StartTls));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
//! It implements the following extensions:
|
||||
//!
|
||||
//! * 8BITMIME ([RFC 6152](https://tools.ietf.org/html/rfc6152))
|
||||
//! * AUTH ([RFC 4954](http://tools.ietf.org/html/rfc4954)) with PLAIN, LOGIN and
|
||||
//! CRAM-MD5 mechanisms
|
||||
//! * AUTH ([RFC 4954](http://tools.ietf.org/html/rfc4954)) with PLAIN, LOGIN mechanisms
|
||||
//! * STARTTLS ([RFC 2487](http://tools.ietf.org/html/rfc2487))
|
||||
//! * SMTPUTF8 ([RFC 6531](http://tools.ietf.org/html/rfc6531))
|
||||
//!
|
||||
|
||||
Reference in New Issue
Block a user