From 269bf70a7f5ed0044e20c239caa05a81ba6a19ed Mon Sep 17 00:00:00 2001 From: Alexis Mousset Date: Fri, 13 Mar 2015 22:45:59 +0100 Subject: [PATCH] Test authentication functions --- src/client/authentication.rs | 51 ++++++++++++++++++++++++++++++++++++ src/client/mod.rs | 23 ++++------------ 2 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 src/client/authentication.rs diff --git a/src/client/authentication.rs b/src/client/authentication.rs new file mode 100644 index 0000000..ce96e5e --- /dev/null +++ b/src/client/authentication.rs @@ -0,0 +1,51 @@ +// Copyright 2014 Alexis Mousset. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Provides authentications functions + +use serialize::base64::{self, ToBase64, FromBase64}; +use serialize::hex::ToHex; +use crypto::hmac::Hmac; +use crypto::md5::Md5; +use crypto::mac::Mac; + +use tools::NUL; + +/// Returns a PLAIN mecanism response +pub fn plain(username: &str, password: &str) -> String { + format!("{}{}{}{}", NUL, username, NUL, password).as_bytes().to_base64(base64::STANDARD) +} + +/// 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(); + + let mut hmac = Hmac::new(Md5::new(), password.as_bytes()); + hmac.input(challenge.as_slice()); + + format!("{} {}", username, hmac.result().code().to_hex()).as_bytes().to_base64(base64::STANDARD) +} + +#[cfg(test)] +mod test { + use super::{plain, cram_md5}; + + #[test] + fn test_plain() { + assert_eq!(plain("username", "password").as_slice(), "AHVzZXJuYW1lAHBhc3N3b3Jk"); + } + + #[test] + fn test_cram_md5() { + assert_eq!(cram_md5("alice", "wonderland", + "PDE3ODkzLjEzMjA2NzkxMjNAdGVzc2VyYWN0LnN1c2FtLmluPg==").as_slice(), + "YWxpY2UgNjRiMmE0M2MxZjZlZDY4MDZhOTgwOTE0ZTIzZTc1ZjA="); + } +} diff --git a/src/client/mod.rs b/src/client/mod.rs index bd6e998..d5869cf 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -15,19 +15,15 @@ use std::net::TcpStream; use std::net::{SocketAddr, ToSocketAddrs}; use std::io::{BufRead, BufStream, Read, Write}; -use serialize::base64::{self, ToBase64, FromBase64}; -use serialize::hex::ToHex; -use crypto::hmac::Hmac; -use crypto::md5::Md5; -use crypto::mac::Mac; - -use tools::{NUL, CRLF, MESSAGE_ENDING}; +use tools::{CRLF, MESSAGE_ENDING}; use tools::{escape_dot, escape_crlf}; use response::{Response, Severity, Category}; use error::SmtpResult; use client::connecter::Connecter; +use client::authentication::{plain, cram_md5}; pub mod connecter; +mod authentication; /// Structure that implements the SMTP client pub struct Client { @@ -172,22 +168,13 @@ impl Client { /// Sends an AUTH command with PLAIN mecanism pub fn auth_plain(&mut self, username: &str, password: &str) -> SmtpResult { - let auth_string = format!("{}{}{}{}", NUL, username, NUL, password); - self.command(format!("AUTH PLAIN {}", auth_string.as_bytes().to_base64(base64::STANDARD)).as_slice()) + self.command(format!("AUTH PLAIN {}", plain(username, password)).as_slice()) } /// Sends an AUTH command with CRAM-MD5 mecanism pub fn auth_cram_md5(&mut self, username: &str, password: &str) -> SmtpResult { let encoded_challenge = try_smtp!(self.command("AUTH CRAM-MD5"), self).first_word().expect("No challenge"); - // TODO manage errors - let challenge = encoded_challenge.from_base64().unwrap(); - - let mut hmac = Hmac::new(Md5::new(), password.as_bytes()); - hmac.input(challenge.as_slice()); - - let auth_string = format!("{} {}", username, hmac.result().code().to_hex()); - - self.command(format!("AUTH CRAM-MD5 {}", auth_string.as_bytes().to_base64(base64::STANDARD)).as_slice()) + self.command(format!("AUTH CRAM-MD5 {}", cram_md5(username, password, encoded_challenge.as_slice())).as_slice()) } /// Sends the message content and close