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;