Error management for authentication

This commit is contained in:
Alexis Mousset
2015-07-14 11:18:49 +02:00
parent 75de338409
commit e6b46faa06
5 changed files with 26 additions and 14 deletions

View File

@@ -1,7 +1,7 @@
[package]
name = "smtp"
version = "0.0.13"
version = "0.0.15"
description = "Simple SMTP client"
readme = "README.md"
documentation = "http://amousset.github.io/rust-smtp/smtp/"

View File

@@ -16,6 +16,7 @@ use crypto::md5::Md5;
use crypto::mac::Mac;
use NUL;
use error::Error;
/// Returns a PLAIN mecanism response
pub fn plain(username: &str, password: &str) -> String {
@@ -23,14 +24,16 @@ pub fn plain(username: &str, password: &str) -> String {
}
/// Returns a CRAM-MD5 mecanism response
pub fn cram_md5(username: &str, password: &str, encoded_challenge: &str) -> String {
// TODO manage errors
let challenge = encoded_challenge.from_base64().unwrap();
pub fn cram_md5(username: &str, password: &str, encoded_challenge: &str) -> Result<String, Error> {
let challenge = match encoded_challenge.from_base64() {
Ok(challenge) => challenge,
Err(error) => return Err(Error::ChallengeParsingError(error)),
};
let mut hmac = Hmac::new(Md5::new(), password.as_bytes());
hmac.input(&challenge);
format!("{} {}", username, hmac.result().code().to_hex()).as_bytes().to_base64(base64::STANDARD)
Ok(format!("{} {}", username, hmac.result().code().to_hex()).as_bytes().to_base64(base64::STANDARD))
}
#[cfg(test)]
@@ -45,7 +48,7 @@ mod test {
#[test]
fn test_cram_md5() {
assert_eq!(cram_md5("alice", "wonderland",
"PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg=="),
"PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg==").unwrap(),
"YWxpY2UgNjRiMmE0M2MxZjZlZDY4MDZhOTgwOTE0ZTIzZTc1ZjA=");
}
}

View File

@@ -16,7 +16,7 @@ use std::io::{BufRead, Read, Write};
use bufstream::BufStream;
use response::ResponseParser;
use error::SmtpResult;
use error::{Error, SmtpResult};
use client::net::{Connector, SmtpStream};
use client::authentication::{plain, cram_md5};
use {CRLF, MESSAGE_ENDING};
@@ -175,8 +175,14 @@ impl<S: Connector + Write + Read = SmtpStream> Client<S> {
/// Sends an AUTH command with CRAM-MD5 mecanism
pub fn auth_cram_md5(&mut self, username: &str, password: &str) -> SmtpResult {
let encoded_challenge = try!(self.command("AUTH CRAM-MD5")).first_word().expect("No challenge");
self.command(&format!("AUTH CRAM-MD5 {}", cram_md5(username, password, &encoded_challenge)))
let encoded_challenge = match try!(self.command("AUTH CRAM-MD5")).first_word() {
Some(challenge) => challenge,
None => return Err(Error::ResponseParsingError("Could not read CRAM challenge")),
};
let cram_response = try!(cram_md5(username, password, &encoded_challenge));
self.command(&format!("AUTH CRAM-MD5 {}", cram_response))
}
/// Sends the message content

View File

@@ -103,11 +103,10 @@ impl EmailBuilder {
message_id: current_message,
};
email.message.headers.insert(
Header::new_with_value("Message-ID".to_string(),
format!("<{}@rust-smtp>", current_message)
).unwrap()
);
match Header::new_with_value("Message-ID".to_string(), format!("<{}@rust-smtp>", current_message)) {
Ok(header) => email.message.headers.insert(header),
Err(_) => (),
}
EmailBuilder {
content: email,

View File

@@ -15,6 +15,7 @@ use std::fmt::{Display, Formatter};
use std::fmt;
use response::{Severity, Response};
use serialize::base64::FromBase64Error;
use self::Error::*;
/// An enum of all error kinds.
@@ -30,6 +31,8 @@ pub enum Error {
PermanentError(Response),
/// Error parsing a response
ResponseParsingError(&'static str),
/// Error parsing a base64 string in response
ChallengeParsingError(FromBase64Error),
/// Internal client error
ClientError(&'static str),
/// DNS resolution error
@@ -50,6 +53,7 @@ impl StdError for Error {
TransientError(_) => "a transient error occured during the SMTP transaction",
PermanentError(_) => "a permanent error occured during the SMTP transaction",
ResponseParsingError(_) => "an error occured while parsing an SMTP response",
ChallengeParsingError(_) => "an error occured while parsing a CRAM-MD5 challenge",
ResolutionError => "Could no resolve hostname",
ClientError(_) => "an unknown error occured",
IoError(_) => "an I/O error occured",