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