#![deny(missing_docs)] and lots of documentation

This commit is contained in:
lumi 2017-02-28 13:05:17 +01:00
parent 329870b886
commit ab7d0d8308
6 changed files with 82 additions and 4 deletions

View file

@ -1,8 +1,11 @@
use openssl::error::ErrorStack; use openssl::error::ErrorStack;
/// A wrapper enum for things that could go wrong in this crate.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// An error in OpenSSL.
OpenSslErrorStack(ErrorStack), OpenSslErrorStack(ErrorStack),
/// An error in a SASL mechanism.
SaslError(String), SaslError(String),
} }

View file

@ -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 openssl;
extern crate base64; extern crate base64;
pub mod error; mod error;
pub use error::Error;
/// A struct containing SASL credentials. /// A struct containing SASL credentials.
pub struct SaslCredentials { 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, pub secret: SaslSecret,
/// Optionally, channel binding data, for *-PLUS mechanisms.
pub channel_binding: Option<Vec<u8>>, pub channel_binding: Option<Vec<u8>>,
} }
@ -20,6 +56,7 @@ pub enum SaslSecret {
Password(String), Password(String),
} }
/// A trait which defines SASL mechanisms.
pub trait SaslMechanism { pub trait SaslMechanism {
/// The name of the mechanism. /// The name of the mechanism.
fn name(&self) -> &str; fn name(&self) -> &str;

View file

@ -4,9 +4,14 @@ use SaslMechanism;
use SaslCredentials; use SaslCredentials;
use SaslSecret; use SaslSecret;
/// A struct for the SASL ANONYMOUS mechanism.
pub struct Anonymous; pub struct Anonymous;
impl 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 { pub fn new() -> Anonymous {
Anonymous Anonymous
} }

View file

@ -1,4 +1,4 @@
///! Provides a few SASL mechanisms. //! Provides a few SASL mechanisms.
mod anonymous; mod anonymous;
mod plain; mod plain;

View file

@ -4,12 +4,17 @@ use SaslMechanism;
use SaslCredentials; use SaslCredentials;
use SaslSecret; use SaslSecret;
/// A struct for the SASL PLAIN mechanism.
pub struct Plain { pub struct Plain {
username: String, username: String,
password: String, password: String,
} }
impl Plain { 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<N: Into<String>, P: Into<String>>(username: N, password: P) -> Plain { pub fn new<N: Into<String>, P: Into<String>>(username: N, password: P) -> Plain {
Plain { Plain {
username: username.into(), username: username.into(),

View file

@ -62,13 +62,22 @@ fn generate_nonce() -> Result<String, ErrorStack> {
Ok(base64::encode(&data)) Ok(base64::encode(&data))
} }
/// A trait which defines the needed methods for SCRAM.
pub trait ScramProvider { pub trait ScramProvider {
/// The name of the hash function.
fn name() -> &'static str; fn name() -> &'static str;
/// A function which hashes the data using the hash function.
fn hash(data: &[u8]) -> Vec<u8>; fn hash(data: &[u8]) -> Vec<u8>;
/// A function which performs an HMAC using the hash function.
fn hmac(data: &[u8], key: &[u8]) -> Vec<u8>; fn hmac(data: &[u8], key: &[u8]) -> Vec<u8>;
/// A function which does PBKDF2 key derivation using the hash function.
fn derive(data: &[u8], salt: &[u8], iterations: usize) -> Vec<u8>; fn derive(data: &[u8], salt: &[u8], iterations: usize) -> Vec<u8>;
} }
/// A `ScramProvider` which provides SCRAM-SHA-1 and SCRAM-SHA-1-PLUS
pub struct Sha1; pub struct Sha1;
impl ScramProvider for Sha1 { // TODO: look at all these unwraps 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; pub struct Sha256;
impl ScramProvider for Sha256 { // TODO: look at all these unwraps impl ScramProvider for Sha256 { // TODO: look at all these unwraps
@ -121,6 +131,7 @@ enum ScramState {
GotServerData { server_signature: Vec<u8> }, GotServerData { server_signature: Vec<u8> },
} }
/// A struct for the SASL SCRAM-* and SCRAM-*-PLUS mechanisms.
pub struct Scram<S: ScramProvider> { pub struct Scram<S: ScramProvider> {
name: String, name: String,
username: String, username: String,
@ -132,6 +143,10 @@ pub struct Scram<S: ScramProvider> {
} }
impl<S: ScramProvider> Scram<S> { impl<S: ScramProvider> Scram<S> {
/// 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<N: Into<String>, P: Into<String>>(username: N, password: P) -> Result<Scram<S>, Error> { pub fn new<N: Into<String>, P: Into<String>>(username: N, password: P) -> Result<Scram<S>, Error> {
Ok(Scram { Ok(Scram {
name: format!("SCRAM-{}", S::name()), name: format!("SCRAM-{}", S::name()),
@ -144,6 +159,12 @@ impl<S: ScramProvider> Scram<S> {
}) })
} }
/// 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<N: Into<String>, P: Into<String>>(username: N, password: P, nonce: String) -> Scram<S> { pub fn new_with_nonce<N: Into<String>, P: Into<String>>(username: N, password: P, nonce: String) -> Scram<S> {
Scram { Scram {
name: format!("SCRAM-{}", S::name()), name: format!("SCRAM-{}", S::name()),
@ -156,7 +177,14 @@ impl<S: ScramProvider> Scram<S> {
} }
} }
/// 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<N: Into<String>, P: Into<String>>(username: N, password: P, channel_binding: Vec<u8>) -> Result<Scram<S>, Error> { pub fn new_with_channel_binding<N: Into<String>, P: Into<String>>(username: N, password: P, channel_binding: Vec<u8>) -> Result<Scram<S>, Error> {
// TODO: channel binding modes other than tls-unique
Ok(Scram { Ok(Scram {
name: format!("SCRAM-{}-PLUS", S::name()), name: format!("SCRAM-{}-PLUS", S::name()),
username: username.into(), username: username.into(),