lib.rs

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