lib.rs

  1//#![deny(missing_docs)]
  2
  3//! This crate provides a framework for SASL authentication and a few authentication mechanisms.
  4//!
  5//! # Examples
  6//!
  7//! ## Simple client-sided usage
  8//!
  9//! ```rust
 10//! use sasl::client::Mechanism;
 11//! use sasl::common::Credentials;
 12//! use sasl::client::mechanisms::Plain;
 13//!
 14//! let creds = Credentials::default()
 15//!                         .with_username("user")
 16//!                         .with_password("pencil");
 17//!
 18//! let mut mechanism = Plain::from_credentials(creds).unwrap();
 19//!
 20//! let initial_data = mechanism.initial();
 21//!
 22//! assert_eq!(initial_data, b"\0user\0pencil");
 23//! ```
 24//!
 25//! ## More complex usage
 26//!
 27//! ```rust,ignore
 28//! #[macro_use] extern crate sasl;
 29//!
 30//! use sasl::server::{Validator, Provider, Mechanism as ServerMechanism, Response};
 31//! use sasl::server::{ValidatorError, ProviderError, MechanismError as ServerMechanismError};
 32//! use sasl::server::mechanisms::{Plain as ServerPlain, Scram as ServerScram};
 33//! use sasl::client::{Mechanism as ClientMechanism, MechanismError as ClientMechanismError};
 34//! use sasl::client::mechanisms::{Plain as ClientPlain, Scram as ClientScram};
 35//! use sasl::common::{Identity, Credentials, Password, ChannelBinding};
 36//! use sasl::common::scram::{ScramProvider, Sha1, Sha256};
 37//! use sasl::secret;
 38//!
 39//! const USERNAME: &'static str = "user";
 40//! const PASSWORD: &'static str = "pencil";
 41//! const SALT: [u8; 8] = [35, 71, 92, 105, 212, 219, 114, 93];
 42//! const ITERATIONS: u32 = 4096;
 43//!
 44//! struct MyValidator;
 45//!
 46//! impl Validator<secret::Plain> for MyValidator {
 47//!     fn validate(&self, identity: &Identity, value: &secret::Plain) -> Result<(), ValidatorError> {
 48//!         let &secret::Plain(ref password) = value;
 49//!         if identity != &Identity::Username(USERNAME.to_owned()) {
 50//!             Err(ValidatorError::AuthenticationFailed)
 51//!         }
 52//!         else if password != PASSWORD {
 53//!             Err(ValidatorError::AuthenticationFailed)
 54//!         }
 55//!         else {
 56//!             Ok(())
 57//!         }
 58//!     }
 59//! }
 60//!
 61//! impl Provider<secret::Pbkdf2Sha1> for MyValidator {
 62//!     fn provide(&self, identity: &Identity) -> Result<secret::Pbkdf2Sha1, ProviderError> {
 63//!         if identity != &Identity::Username(USERNAME.to_owned()) {
 64//!             Err(ProviderError::AuthenticationFailed)
 65//!         }
 66//!         else {
 67//!             let digest = sasl::common::scram::Sha1::derive
 68//!                 ( &Password::Plain((PASSWORD.to_owned()))
 69//!                 , &SALT[..]
 70//!                 , ITERATIONS )?;
 71//!             Ok(secret::Pbkdf2Sha1 {
 72//!                 salt: SALT.to_vec(),
 73//!                 iterations: ITERATIONS,
 74//!                 digest: digest,
 75//!             })
 76//!         }
 77//!     }
 78//! }
 79//!
 80//! impl_validator_using_provider!(MyValidator, secret::Pbkdf2Sha1);
 81//!
 82//! impl Provider<secret::Pbkdf2Sha256> for MyValidator {
 83//!     fn provide(&self, identity: &Identity) -> Result<secret::Pbkdf2Sha256, ProviderError> {
 84//!         if identity != &Identity::Username(USERNAME.to_owned()) {
 85//!             Err(ProviderError::AuthenticationFailed)
 86//!         }
 87//!         else {
 88//!             let digest = sasl::common::scram::Sha256::derive
 89//!                 ( &Password::Plain((PASSWORD.to_owned()))
 90//!                 , &SALT[..]
 91//!                 , ITERATIONS )?;
 92//!             Ok(secret::Pbkdf2Sha256 {
 93//!                 salt: SALT.to_vec(),
 94//!                 iterations: ITERATIONS,
 95//!                 digest: digest,
 96//!             })
 97//!         }
 98//!     }
 99//! }
100//!
101//! impl_validator_using_provider!(MyValidator, secret::Pbkdf2Sha256);
102//!
103//! #[derive(Debug, PartialEq)]
104//! enum MechanismError {
105//!     Client(ClientMechanismError),
106//!     Server(ServerMechanismError),
107//! }
108//!
109//! impl From<ClientMechanismError> for MechanismError {
110//!     fn from(err: ClientMechanismError) -> MechanismError {
111//!         MechanismError::Client(err)
112//!     }
113//! }
114//!
115//! impl From<ServerMechanismError> for MechanismError {
116//!     fn from(err: ServerMechanismError) -> MechanismError {
117//!         MechanismError::Server(err)
118//!     }
119//! }
120//!
121//! fn finish<CM, SM>(cm: &mut CM, sm: &mut SM) -> Result<Identity, MechanismError>
122//!     where CM: ClientMechanism,
123//!           SM: ServerMechanism {
124//!     let init = cm.initial();
125//!     println!("C: {}", String::from_utf8_lossy(&init));
126//!     let mut resp = sm.respond(&init)?;
127//!     loop {
128//!         let msg;
129//!         match resp {
130//!             Response::Proceed(ref data) => {
131//!                 println!("S: {}", String::from_utf8_lossy(&data));
132//!                 msg = cm.response(data)?;
133//!                 println!("C: {}", String::from_utf8_lossy(&msg));
134//!             },
135//!             _ => break,
136//!         }
137//!         resp = sm.respond(&msg)?;
138//!     }
139//!     if let Response::Success(ret, fin) = resp {
140//!         println!("S: {}", String::from_utf8_lossy(&fin));
141//!         cm.success(&fin)?;
142//!         Ok(ret)
143//!     }
144//!     else {
145//!         unreachable!();
146//!     }
147//! }
148//!
149//! fn main() {
150//!     let mut mech = ServerPlain::new(MyValidator);
151//!     let expected_response = Response::Success(Identity::Username("user".to_owned()), Vec::new());
152//!     assert_eq!(mech.respond(b"\0user\0pencil"), Ok(expected_response));
153//!
154//!     let mut mech = ServerPlain::new(MyValidator);
155//!     assert_eq!(mech.respond(b"\0user\0marker"), Err(ServerMechanismError::ValidatorError(ValidatorError::AuthenticationFailed)));
156//!
157//!     let creds = Credentials::default()
158//!                             .with_username(USERNAME)
159//!                             .with_password(PASSWORD);
160//!     let mut client_mech = ClientPlain::from_credentials(creds.clone()).unwrap();
161//!     let mut server_mech = ServerPlain::new(MyValidator);
162//!
163//!     assert_eq!(finish(&mut client_mech, &mut server_mech), Ok(Identity::Username(USERNAME.to_owned())));
164//!
165//!     let mut client_mech = ClientScram::<Sha1>::from_credentials(creds.clone()).unwrap();
166//!     let mut server_mech = ServerScram::<Sha1, _>::new(MyValidator, ChannelBinding::Unsupported);
167//!
168//!     assert_eq!(finish(&mut client_mech, &mut server_mech), Ok(Identity::Username(USERNAME.to_owned())));
169//!
170//!     let mut client_mech = ClientScram::<Sha256>::from_credentials(creds.clone()).unwrap();
171//!     let mut server_mech = ServerScram::<Sha256, _>::new(MyValidator, ChannelBinding::Unsupported);
172//!
173//!     assert_eq!(finish(&mut client_mech, &mut server_mech), Ok(Identity::Username(USERNAME.to_owned())));
174//! }
175//! ```
176//!
177//! # Usage
178//!
179//! You can use this in your crate by adding this under `dependencies` in your `Cargo.toml`:
180//!
181//! ```toml,ignore
182//! sasl = "*"
183//! ```
184
185mod error;
186
187pub mod client;
188#[macro_use]
189pub mod server;
190pub mod common;
191pub mod secret;
192
193pub use crate::error::Error;