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