From ab7d0d830812904b63508442d3890c840a29a6e8 Mon Sep 17 00:00:00 2001 From: lumi Date: Tue, 28 Feb 2017 13:05:17 +0100 Subject: [PATCH] #![deny(missing_docs)] and lots of documentation --- sasl/src/error.rs | 3 +++ sasl/src/lib.rs | 43 +++++++++++++++++++++++++++++--- sasl/src/mechanisms/anonymous.rs | 5 ++++ sasl/src/mechanisms/mod.rs | 2 +- sasl/src/mechanisms/plain.rs | 5 ++++ sasl/src/mechanisms/scram.rs | 28 +++++++++++++++++++++ 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/sasl/src/error.rs b/sasl/src/error.rs index 4192300..284406b 100644 --- a/sasl/src/error.rs +++ b/sasl/src/error.rs @@ -1,8 +1,11 @@ use openssl::error::ErrorStack; +/// A wrapper enum for things that could go wrong in this crate. #[derive(Debug)] pub enum Error { + /// An error in OpenSSL. OpenSslErrorStack(ErrorStack), + /// An error in a SASL mechanism. SaslError(String), } diff --git a/sasl/src/lib.rs b/sasl/src/lib.rs index 07082a6..4566ad6 100644 --- a/sasl/src/lib.rs +++ b/sasl/src/lib.rs @@ -1,14 +1,50 @@ -//! Provides the `SaslMechanism` trait and some implementations. +#![deny(missing_docs)] + +//! This crate provides a framework for SASL authentication and a few authentication mechanisms. +//! +//! # Examples +//! +//! ```rust +//! use sasl::{SaslCredentials, SaslSecret, SaslMechanism, Error}; +//! use sasl::mechanisms::Plain; +//! +//! let creds = SaslCredentials { +//! username: "user".to_owned(), +//! secret: SaslSecret::Password("pencil".to_owned()), +//! channel_binding: None, +//! }; +//! +//! let mut mechanism = Plain::from_credentials(creds).unwrap(); +//! +//! let initial_data = mechanism.initial().unwrap(); +//! +//! assert_eq!(initial_data, b"\0user\0pencil"); +//! ``` +//! +//! You may look at the tests of `mechanisms/scram.rs` for examples of more advanced usage. +//! +//! # Usage +//! +//! You can use this in your crate by adding this under `dependencies` in your `Cargo.toml`: +//! +//! ```toml,ignore +//! sasl = "*" +//! ``` extern crate openssl; extern crate base64; -pub mod error; +mod error; + +pub use error::Error; /// A struct containing SASL credentials. pub struct SaslCredentials { - pub username: String, + /// The requested username. + pub username: String, // TODO: change this since some mechanisms do not use it + /// The secret used to authenticate. pub secret: SaslSecret, + /// Optionally, channel binding data, for *-PLUS mechanisms. pub channel_binding: Option>, } @@ -20,6 +56,7 @@ pub enum SaslSecret { Password(String), } +/// A trait which defines SASL mechanisms. pub trait SaslMechanism { /// The name of the mechanism. fn name(&self) -> &str; diff --git a/sasl/src/mechanisms/anonymous.rs b/sasl/src/mechanisms/anonymous.rs index 9d595e7..299886b 100644 --- a/sasl/src/mechanisms/anonymous.rs +++ b/sasl/src/mechanisms/anonymous.rs @@ -4,9 +4,14 @@ use SaslMechanism; use SaslCredentials; use SaslSecret; +/// A struct for the SASL ANONYMOUS mechanism. pub struct Anonymous; impl Anonymous { + /// Constructs a new struct for authenticating using the SASL ANONYMOUS mechanism. + /// + /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the + /// requested mechanism using `from_credentials`. pub fn new() -> Anonymous { Anonymous } diff --git a/sasl/src/mechanisms/mod.rs b/sasl/src/mechanisms/mod.rs index 59463ac..2b81947 100644 --- a/sasl/src/mechanisms/mod.rs +++ b/sasl/src/mechanisms/mod.rs @@ -1,4 +1,4 @@ -///! Provides a few SASL mechanisms. +//! Provides a few SASL mechanisms. mod anonymous; mod plain; diff --git a/sasl/src/mechanisms/plain.rs b/sasl/src/mechanisms/plain.rs index 58600ce..dc1460e 100644 --- a/sasl/src/mechanisms/plain.rs +++ b/sasl/src/mechanisms/plain.rs @@ -4,12 +4,17 @@ use SaslMechanism; use SaslCredentials; use SaslSecret; +/// A struct for the SASL PLAIN mechanism. pub struct Plain { username: String, password: String, } impl Plain { + /// Constructs a new struct for authenticating using the SASL PLAIN mechanism. + /// + /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the + /// requested mechanism using `from_credentials`. pub fn new, P: Into>(username: N, password: P) -> Plain { Plain { username: username.into(), diff --git a/sasl/src/mechanisms/scram.rs b/sasl/src/mechanisms/scram.rs index efa2f5d..433b1b5 100644 --- a/sasl/src/mechanisms/scram.rs +++ b/sasl/src/mechanisms/scram.rs @@ -62,13 +62,22 @@ fn generate_nonce() -> Result { Ok(base64::encode(&data)) } +/// A trait which defines the needed methods for SCRAM. pub trait ScramProvider { + /// The name of the hash function. fn name() -> &'static str; + + /// A function which hashes the data using the hash function. fn hash(data: &[u8]) -> Vec; + + /// A function which performs an HMAC using the hash function. fn hmac(data: &[u8], key: &[u8]) -> Vec; + + /// A function which does PBKDF2 key derivation using the hash function. fn derive(data: &[u8], salt: &[u8], iterations: usize) -> Vec; } +/// A `ScramProvider` which provides SCRAM-SHA-1 and SCRAM-SHA-1-PLUS pub struct Sha1; impl ScramProvider for Sha1 { // TODO: look at all these unwraps @@ -92,6 +101,7 @@ impl ScramProvider for Sha1 { // TODO: look at all these unwraps } } +/// A `ScramProvider` which provides SCRAM-SHA-256 and SCRAM-SHA-256-PLUS pub struct Sha256; impl ScramProvider for Sha256 { // TODO: look at all these unwraps @@ -121,6 +131,7 @@ enum ScramState { GotServerData { server_signature: Vec }, } +/// A struct for the SASL SCRAM-* and SCRAM-*-PLUS mechanisms. pub struct Scram { name: String, username: String, @@ -132,6 +143,10 @@ pub struct Scram { } impl Scram { + /// Constructs a new struct for authenticating using the SASL SCRAM-* mechanism. + /// + /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the + /// requested mechanism using `from_credentials`. pub fn new, P: Into>(username: N, password: P) -> Result, Error> { Ok(Scram { name: format!("SCRAM-{}", S::name()), @@ -144,6 +159,12 @@ impl Scram { }) } + /// Constructs a new struct for authenticating using the SASL SCRAM-* mechanism. + /// + /// This one takes a nonce instead of generating it. + /// + /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the + /// requested mechanism using `from_credentials`. pub fn new_with_nonce, P: Into>(username: N, password: P, nonce: String) -> Scram { Scram { name: format!("SCRAM-{}", S::name()), @@ -156,7 +177,14 @@ impl Scram { } } + /// Constructs a new struct for authenticating using the SASL SCRAM-*-PLUS mechanism. + /// + /// This means that this function will also take the channel binding data. + /// + /// It is recommended that instead you use a `SaslCredentials` struct and turn it into the + /// requested mechanism using `from_credentials`. pub fn new_with_channel_binding, P: Into>(username: N, password: P, channel_binding: Vec) -> Result, Error> { + // TODO: channel binding modes other than tls-unique Ok(Scram { name: format!("SCRAM-{}-PLUS", S::name()), username: username.into(),