Use error structs for errors instead of plain strings.
This commit is contained in:
parent
09745829f1
commit
7fd6923464
10 changed files with 357 additions and 99 deletions
|
|
@ -1,6 +1,6 @@
|
|||
//! Provides the SASL "ANONYMOUS" mechanism.
|
||||
|
||||
use crate::client::Mechanism;
|
||||
use crate::client::{Mechanism, MechanismError};
|
||||
use crate::common::{Credentials, Secret};
|
||||
|
||||
/// A struct for the SASL ANONYMOUS mechanism.
|
||||
|
|
@ -21,11 +21,11 @@ impl Mechanism for Anonymous {
|
|||
"ANONYMOUS"
|
||||
}
|
||||
|
||||
fn from_credentials(credentials: Credentials) -> Result<Anonymous, String> {
|
||||
fn from_credentials(credentials: Credentials) -> Result<Anonymous, MechanismError> {
|
||||
if let Secret::None = credentials.secret {
|
||||
Ok(Anonymous)
|
||||
} else {
|
||||
Err("the anonymous sasl mechanism requires no credentials".to_owned())
|
||||
Err(MechanismError::AnonymousRequiresNoCredentials)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Provides the SASL "PLAIN" mechanism.
|
||||
|
||||
use crate::client::Mechanism;
|
||||
use crate::client::{Mechanism, MechanismError};
|
||||
use crate::common::{Credentials, Identity, Password, Secret};
|
||||
|
||||
/// A struct for the SASL PLAIN mechanism.
|
||||
|
|
@ -27,15 +27,15 @@ impl Mechanism for Plain {
|
|||
"PLAIN"
|
||||
}
|
||||
|
||||
fn from_credentials(credentials: Credentials) -> Result<Plain, String> {
|
||||
fn from_credentials(credentials: Credentials) -> Result<Plain, MechanismError> {
|
||||
if let Secret::Password(Password::Plain(password)) = credentials.secret {
|
||||
if let Identity::Username(username) = credentials.identity {
|
||||
Ok(Plain::new(username, password))
|
||||
} else {
|
||||
Err("PLAIN requires a username".to_owned())
|
||||
Err(MechanismError::PlainRequiresUsername)
|
||||
}
|
||||
} else {
|
||||
Err("PLAIN requires a plaintext password".to_owned())
|
||||
Err(MechanismError::PlainRequiresPlaintextPassword)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use base64;
|
||||
|
||||
use crate::client::Mechanism;
|
||||
use crate::client::{Mechanism, MechanismError};
|
||||
use crate::common::scram::{generate_nonce, ScramProvider};
|
||||
use crate::common::{parse_frame, xor, ChannelBinding, Credentials, Identity, Password, Secret};
|
||||
|
||||
|
|
@ -80,16 +80,16 @@ impl<S: ScramProvider> Mechanism for Scram<S> {
|
|||
&self.name
|
||||
}
|
||||
|
||||
fn from_credentials(credentials: Credentials) -> Result<Scram<S>, String> {
|
||||
fn from_credentials(credentials: Credentials) -> Result<Scram<S>, MechanismError> {
|
||||
if let Secret::Password(password) = credentials.secret {
|
||||
if let Identity::Username(username) = credentials.identity {
|
||||
Scram::new(username, password, credentials.channel_binding)
|
||||
.map_err(|_| "can't generate nonce".to_owned())
|
||||
.map_err(|_| MechanismError::CannotGenerateNonce)
|
||||
} else {
|
||||
Err("SCRAM requires a username".to_owned())
|
||||
Err(MechanismError::ScramRequiresUsername)
|
||||
}
|
||||
} else {
|
||||
Err("SCRAM requires a password".to_owned())
|
||||
Err(MechanismError::ScramRequiresPassword)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ impl<S: ScramProvider> Mechanism for Scram<S> {
|
|||
data
|
||||
}
|
||||
|
||||
fn response(&mut self, challenge: &[u8]) -> Result<Vec<u8>, String> {
|
||||
fn response(&mut self, challenge: &[u8]) -> Result<Vec<u8>, MechanismError> {
|
||||
let next_state;
|
||||
let ret;
|
||||
match self.state {
|
||||
|
|
@ -120,13 +120,13 @@ impl<S: ScramProvider> Mechanism for Scram<S> {
|
|||
ref gs2_header,
|
||||
} => {
|
||||
let frame =
|
||||
parse_frame(challenge).map_err(|_| "can't decode challenge".to_owned())?;
|
||||
parse_frame(challenge).map_err(|_| MechanismError::CannotDecodeChallenge)?;
|
||||
let server_nonce = frame.get("r");
|
||||
let salt = frame.get("s").and_then(|v| base64::decode(v).ok());
|
||||
let iterations = frame.get("i").and_then(|v| v.parse().ok());
|
||||
let server_nonce = server_nonce.ok_or_else(|| "no server nonce".to_owned())?;
|
||||
let salt = salt.ok_or_else(|| "no server salt".to_owned())?;
|
||||
let iterations = iterations.ok_or_else(|| "no server iterations".to_owned())?;
|
||||
let server_nonce = server_nonce.ok_or_else(|| MechanismError::NoServerNonce)?;
|
||||
let salt = salt.ok_or_else(|| MechanismError::NoServerSalt)?;
|
||||
let iterations = iterations.ok_or_else(|| MechanismError::NoServerIterations)?;
|
||||
// TODO: SASLprep
|
||||
let mut client_final_message_bare = Vec::new();
|
||||
client_final_message_bare.extend(b"c=");
|
||||
|
|
@ -159,15 +159,15 @@ impl<S: ScramProvider> Mechanism for Scram<S> {
|
|||
ret = client_final_message;
|
||||
}
|
||||
_ => {
|
||||
return Err("not in the right state to receive this response".to_owned());
|
||||
return Err(MechanismError::InvalidState);
|
||||
}
|
||||
}
|
||||
self.state = next_state;
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn success(&mut self, data: &[u8]) -> Result<(), String> {
|
||||
let frame = parse_frame(data).map_err(|_| "can't decode success response".to_owned())?;
|
||||
fn success(&mut self, data: &[u8]) -> Result<(), MechanismError> {
|
||||
let frame = parse_frame(data).map_err(|_| MechanismError::CannotDecodeSuccessResponse)?;
|
||||
match self.state {
|
||||
ScramState::GotServerData {
|
||||
ref server_signature,
|
||||
|
|
@ -176,13 +176,13 @@ impl<S: ScramProvider> Mechanism for Scram<S> {
|
|||
if sig == *server_signature {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("invalid signature in success response".to_owned())
|
||||
Err(MechanismError::InvalidSignatureInSuccessResponse)
|
||||
}
|
||||
} else {
|
||||
Err("no signature in success response".to_owned())
|
||||
Err(MechanismError::NoSignatureInSuccessResponse)
|
||||
}
|
||||
}
|
||||
_ => Err("not in the right state to get a success response".to_owned()),
|
||||
_ => Err(MechanismError::InvalidState),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,80 @@
|
|||
use crate::common::scram::DeriveError;
|
||||
use crate::common::Credentials;
|
||||
use hmac::crypto_mac::InvalidKeyLength;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MechanismError {
|
||||
AnonymousRequiresNoCredentials,
|
||||
|
||||
PlainRequiresUsername,
|
||||
PlainRequiresPlaintextPassword,
|
||||
|
||||
CannotGenerateNonce,
|
||||
ScramRequiresUsername,
|
||||
ScramRequiresPassword,
|
||||
|
||||
CannotDecodeChallenge,
|
||||
NoServerNonce,
|
||||
NoServerSalt,
|
||||
NoServerIterations,
|
||||
DeriveError(DeriveError),
|
||||
InvalidKeyLength(InvalidKeyLength),
|
||||
InvalidState,
|
||||
|
||||
CannotDecodeSuccessResponse,
|
||||
InvalidSignatureInSuccessResponse,
|
||||
NoSignatureInSuccessResponse,
|
||||
}
|
||||
|
||||
impl From<DeriveError> for MechanismError {
|
||||
fn from(err: DeriveError) -> MechanismError {
|
||||
MechanismError::DeriveError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InvalidKeyLength> for MechanismError {
|
||||
fn from(err: InvalidKeyLength) -> MechanismError {
|
||||
MechanismError::InvalidKeyLength(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MechanismError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
fmt,
|
||||
"{}",
|
||||
match self {
|
||||
MechanismError::AnonymousRequiresNoCredentials =>
|
||||
"ANONYMOUS mechanism requires no credentials",
|
||||
|
||||
MechanismError::PlainRequiresUsername => "PLAIN requires a username",
|
||||
MechanismError::PlainRequiresPlaintextPassword =>
|
||||
"PLAIN requires a plaintext password",
|
||||
|
||||
MechanismError::CannotGenerateNonce => "can't generate nonce",
|
||||
MechanismError::ScramRequiresUsername => "SCRAM requires a username",
|
||||
MechanismError::ScramRequiresPassword => "SCRAM requires a password",
|
||||
|
||||
MechanismError::CannotDecodeChallenge => "can't decode challenge",
|
||||
MechanismError::NoServerNonce => "no server nonce",
|
||||
MechanismError::NoServerSalt => "no server salt",
|
||||
MechanismError::NoServerIterations => "no server iterations",
|
||||
MechanismError::DeriveError(err) => return write!(fmt, "derive error: {}", err),
|
||||
MechanismError::InvalidKeyLength(err) =>
|
||||
return write!(fmt, "invalid key length: {}", err),
|
||||
MechanismError::InvalidState => "not in the right state to receive this response",
|
||||
|
||||
MechanismError::CannotDecodeSuccessResponse => "can't decode success response",
|
||||
MechanismError::InvalidSignatureInSuccessResponse =>
|
||||
"invalid signature in success response",
|
||||
MechanismError::NoSignatureInSuccessResponse => "no signature in success response",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MechanismError {}
|
||||
|
||||
/// A trait which defines SASL mechanisms.
|
||||
pub trait Mechanism {
|
||||
|
|
@ -6,7 +82,7 @@ pub trait Mechanism {
|
|||
fn name(&self) -> &str;
|
||||
|
||||
/// Creates this mechanism from `Credentials`.
|
||||
fn from_credentials(credentials: Credentials) -> Result<Self, String>
|
||||
fn from_credentials(credentials: Credentials) -> Result<Self, MechanismError>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
|
|
@ -16,12 +92,12 @@ pub trait Mechanism {
|
|||
}
|
||||
|
||||
/// Creates a response to the SASL challenge.
|
||||
fn response(&mut self, _challenge: &[u8]) -> Result<Vec<u8>, String> {
|
||||
fn response(&mut self, _challenge: &[u8]) -> Result<Vec<u8>, MechanismError> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
/// Verifies the server success response, if there is one.
|
||||
fn success(&mut self, _data: &[u8]) -> Result<(), String> {
|
||||
fn success(&mut self, _data: &[u8]) -> Result<(), MechanismError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue