1#![deny(missing_docs)]
2
3//! This crate provides a framework for SASL authentication and a few authentication mechanisms.
4//!
5//! # Examples
6//!
7//! ```rust
8//! use sasl::{SaslCredentials, SaslMechanism, Error};
9//! use sasl::mechanisms::Plain;
10//!
11//! let creds = SaslCredentials::default()
12//! .with_username("user")
13//! .with_password("pencil");
14//!
15//! let mut mechanism = Plain::from_credentials(creds).unwrap();
16//!
17//! let initial_data = mechanism.initial().unwrap();
18//!
19//! assert_eq!(initial_data, b"\0user\0pencil");
20//! ```
21//!
22//! You may look at the tests of `mechanisms/scram.rs` for examples of more advanced usage.
23//!
24//! # Usage
25//!
26//! You can use this in your crate by adding this under `dependencies` in your `Cargo.toml`:
27//!
28//! ```toml,ignore
29//! sasl = "*"
30//! ```
31
32extern crate base64;
33extern crate openssl;
34
35mod error;
36
37pub use error::Error;
38
39/// A struct containing SASL credentials.
40#[derive(Clone, Debug)]
41pub struct SaslCredentials {
42 /// The requested username.
43 pub username: Option<String>,
44 /// The secret used to authenticate.
45 pub secret: SaslSecret,
46 /// Channel binding data, for *-PLUS mechanisms.
47 pub channel_binding: ChannelBinding,
48}
49
50impl Default for SaslCredentials {
51 fn default() -> SaslCredentials {
52 SaslCredentials {
53 username: None,
54 secret: SaslSecret::None,
55 channel_binding: ChannelBinding::None,
56 }
57 }
58}
59
60impl SaslCredentials {
61 /// Creates a new SaslCredentials with the specified username.
62 pub fn with_username<N: Into<String>>(mut self, username: N) -> SaslCredentials {
63 self.username = Some(username.into());
64 self
65 }
66
67 /// Creates a new SaslCredentials with the specified password.
68 pub fn with_password<P: Into<String>>(mut self, password: P) -> SaslCredentials {
69 self.secret = SaslSecret::Password(password.into());
70 self
71 }
72
73 /// Creates a new SaslCredentials with the specified chanel binding.
74 pub fn with_channel_binding(mut self, channel_binding: ChannelBinding) -> SaslCredentials {
75 self.channel_binding = channel_binding;
76 self
77 }
78}
79
80/// Channel binding configuration.
81#[derive(Clone, Debug, PartialEq, Eq)]
82pub enum ChannelBinding {
83 /// No channel binding data.
84 None,
85 /// p=tls-unique channel binding data.
86 TlsUnique(Vec<u8>),
87}
88
89impl ChannelBinding {
90 /// Return the gs2 header for this channel binding mechanism.
91 pub fn header(&self) -> &[u8] {
92 match *self {
93 ChannelBinding::None => b"n,,",
94 ChannelBinding::TlsUnique(_) => b"p=tls-unique,,",
95 }
96 }
97
98 /// Return the channel binding data for this channel binding mechanism.
99 pub fn data(&self) -> &[u8] {
100 match *self {
101 ChannelBinding::None => &[],
102 ChannelBinding::TlsUnique(ref data) => data,
103 }
104 }
105}
106
107/// Represents a SASL secret, like a password.
108#[derive(Clone, Debug, PartialEq, Eq)]
109pub enum SaslSecret {
110 /// No extra data needed.
111 None,
112 /// Password required.
113 Password(String),
114}
115
116/// A trait which defines SASL mechanisms.
117pub trait SaslMechanism {
118 /// The name of the mechanism.
119 fn name(&self) -> &str;
120
121 /// Creates this mechanism from `SaslCredentials`.
122 fn from_credentials(credentials: SaslCredentials) -> Result<Self, String>
123 where
124 Self: Sized;
125
126 /// Provides initial payload of the SASL mechanism.
127 fn initial(&mut self) -> Result<Vec<u8>, String> {
128 Ok(Vec::new())
129 }
130
131 /// Creates a response to the SASL challenge.
132 fn response(&mut self, _challenge: &[u8]) -> Result<Vec<u8>, String> {
133 Ok(Vec::new())
134 }
135
136 /// Verifies the server success response, if there is one.
137 fn success(&mut self, _data: &[u8]) -> Result<(), String> {
138 Ok(())
139 }
140}
141
142pub mod mechanisms;