-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
229 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
//! SCRAM-SHA-256 client. | ||
use super::Error; | ||
|
||
use scram::{ | ||
client::{ClientFinal, ServerFinal, ServerFirst}, | ||
ScramClient, | ||
}; | ||
|
||
enum State<'a> { | ||
Initial(ScramClient<'a>), | ||
First(ServerFirst<'a>), | ||
Final(ClientFinal), | ||
ServerFinal(ServerFinal), | ||
} | ||
|
||
/// SASL SCRAM client. | ||
pub struct Client<'a> { | ||
state: Option<State<'a>>, | ||
} | ||
|
||
impl<'a> Client<'a> { | ||
/// Create new SCRAM client. | ||
pub fn new(user: &'a str, password: &'a str) -> Self { | ||
Self { | ||
state: Some(State::Initial(ScramClient::new(user, password, None))), | ||
} | ||
} | ||
|
||
/// Client first message. | ||
pub fn first(&mut self) -> Result<String, Error> { | ||
let (scram, client_first) = match self.state.take() { | ||
Some(State::Initial(scram)) => scram.client_first(), | ||
_ => return Err(Error::OutOfOrder), | ||
}; | ||
self.state = Some(State::First(scram)); | ||
Ok(client_first) | ||
} | ||
|
||
/// Handle server first message. | ||
pub fn server_first(&mut self, message: &str) -> Result<(), Error> { | ||
let scram = match self.state.take() { | ||
Some(State::First(scram)) => scram.handle_server_first(message)?, | ||
_ => return Err(Error::OutOfOrder), | ||
}; | ||
self.state = Some(State::Final(scram)); | ||
Ok(()) | ||
} | ||
|
||
/// Client last message. | ||
pub fn last(&mut self) -> Result<String, Error> { | ||
let (scram, client_final) = match self.state.take() { | ||
Some(State::Final(scram)) => scram.client_final(), | ||
_ => return Err(Error::OutOfOrder), | ||
}; | ||
self.state = Some(State::ServerFinal(scram)); | ||
Ok(client_final) | ||
} | ||
|
||
/// Verify server last message. | ||
pub fn server_last(&mut self, message: &str) -> Result<(), Error> { | ||
match self.state.take() { | ||
Some(State::ServerFinal(scram)) => scram.handle_server_final(message)?, | ||
_ => return Err(Error::OutOfOrder), | ||
}; | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
//! SCRAM errors. | ||
use thiserror::Error; | ||
|
||
#[derive(Debug, Error)] | ||
pub enum Error { | ||
#[error("out of order auth")] | ||
OutOfOrder, | ||
|
||
#[error("invalid server first message")] | ||
InvalidServerFirst(#[from] scram::Error), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,7 @@ | ||
//! SCRAM-SHA-256 authentication. | ||
pub mod client; | ||
pub mod error; | ||
pub mod state; | ||
|
||
pub use client::Client; | ||
pub use error::Error; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
//! SCRAM-SHA-256 state. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
//! Password messages. | ||
use crate::net::c_string_buf; | ||
|
||
use super::super::code; | ||
use super::super::prelude::*; | ||
|
||
/// Password message. | ||
#[derive(Debug)] | ||
pub enum Password { | ||
/// SASLInitialResponse (F) | ||
SASLInitialResponse { name: String, response: String }, | ||
/// SASLResponse (F) | ||
SASLResponse { response: String }, | ||
} | ||
|
||
impl Password { | ||
/// Create new SASL initial response. | ||
pub fn sasl_initial(response: &str) -> Self { | ||
Self::SASLInitialResponse { | ||
name: "SCRAM-SHA-256".to_string(), | ||
response: response.to_owned(), | ||
} | ||
} | ||
} | ||
|
||
impl FromBytes for Password { | ||
fn from_bytes(mut bytes: Bytes) -> Result<Self, Error> { | ||
code!(bytes, 'p'); | ||
let _len = bytes.get_i32(); | ||
let content = c_string_buf(&mut bytes); | ||
|
||
if bytes.has_remaining() { | ||
let len = bytes.get_i32(); | ||
let response = if len >= 0 { | ||
c_string_buf(&mut bytes) | ||
} else { | ||
String::new() | ||
}; | ||
|
||
Ok(Self::SASLInitialResponse { | ||
name: content, | ||
response, | ||
}) | ||
} else { | ||
Ok(Password::SASLResponse { response: content }) | ||
} | ||
} | ||
} | ||
|
||
impl ToBytes for Password { | ||
fn to_bytes(&self) -> Result<Bytes, Error> { | ||
let mut payload = Payload::named(self.code()); | ||
match self { | ||
Password::SASLInitialResponse { name, response } => { | ||
payload.put_string(name); | ||
payload.put_i32(response.len() as i32); | ||
payload.put(Bytes::copy_from_slice(response.as_bytes())); | ||
} | ||
|
||
Password::SASLResponse { response } => { | ||
payload.put(Bytes::copy_from_slice(response.as_bytes())); | ||
} | ||
} | ||
|
||
Ok(payload.freeze()) | ||
} | ||
} | ||
|
||
impl Protocol for Password { | ||
fn code(&self) -> char { | ||
'p' | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1de68b9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@levkk: Good job!
Linked to: