Authentication support.

main
Mauro D 2022-06-14 06:46:08 +00:00
parent f33ab4fbd3
commit 951a8ea8c3
2 changed files with 50 additions and 3 deletions

View File

@ -19,9 +19,16 @@ use crate::{
const DEFAULT_TIMEOUT_MS: u64 = 10 * 1000; const DEFAULT_TIMEOUT_MS: u64 = 10 * 1000;
static USER_AGENT: &str = concat!("stalwart-jmap/", env!("CARGO_PKG_VERSION")); static USER_AGENT: &str = concat!("stalwart-jmap/", env!("CARGO_PKG_VERSION"));
pub enum Credentials {
Basic(String),
Bearer(String),
}
pub struct Client { pub struct Client {
session: Session, session: Session,
session_url: String, session_url: String,
#[cfg(feature = "websockets")]
pub(crate) authorization: String,
upload_url: Vec<URLPart<blob::URLParameter>>, upload_url: Vec<URLPart<blob::URLParameter>>,
download_url: Vec<URLPart<blob::URLParameter>>, download_url: Vec<URLPart<blob::URLParameter>>,
event_source_url: Vec<URLPart<event_source::URLParameter>>, event_source_url: Vec<URLPart<event_source::URLParameter>>,
@ -33,7 +40,11 @@ pub struct Client {
} }
impl Client { impl Client {
pub async fn connect(url: &str) -> crate::Result<Self> { pub async fn connect(url: &str, credentials: impl Into<Credentials>) -> crate::Result<Self> {
let authorization = match credentials.into() {
Credentials::Basic(s) => format!("Basic {}", s),
Credentials::Bearer(s) => format!("Bearer {}", s),
};
let mut headers = header::HeaderMap::new(); let mut headers = header::HeaderMap::new();
headers.insert( headers.insert(
header::USER_AGENT, header::USER_AGENT,
@ -41,7 +52,7 @@ impl Client {
); );
headers.insert( headers.insert(
header::AUTHORIZATION, header::AUTHORIZATION,
header::HeaderValue::from_static("Basic test"), header::HeaderValue::from_str(&authorization).unwrap(),
); );
let session: Session = serde_json::from_slice( let session: Session = serde_json::from_slice(
@ -76,6 +87,8 @@ impl Client {
event_source_url: URLPart::parse(session.event_source_url())?, event_source_url: URLPart::parse(session.event_source_url())?,
session, session,
session_url: url.to_string(), session_url: url.to_string(),
#[cfg(feature = "websockets")]
authorization,
timeout: DEFAULT_TIMEOUT_MS, timeout: DEFAULT_TIMEOUT_MS,
headers, headers,
default_account_id, default_account_id,
@ -200,6 +213,40 @@ impl Client {
} }
} }
impl Credentials {
pub fn basic(username: &str, password: &str) -> Self {
Credentials::Basic(base64::encode(format!("{}:{}", username, password)))
}
pub fn bearer(token: impl Into<String>) -> Self {
Credentials::Bearer(token.into())
}
}
impl From<&str> for Credentials {
fn from(s: &str) -> Self {
Credentials::bearer(s.to_string())
}
}
impl From<String> for Credentials {
fn from(s: String) -> Self {
Credentials::bearer(s)
}
}
impl From<(&str, &str)> for Credentials {
fn from((username, password): (&str, &str)) -> Self {
Credentials::basic(username, password)
}
}
impl From<(String, String)> for Credentials {
fn from((username, password): (String, String)) -> Self {
Credentials::basic(&username, &password)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::core::response::{Response, TaggedMethodResponse}; use crate::core::response::{Response, TaggedMethodResponse};

View File

@ -163,7 +163,7 @@ impl Client {
let mut request = capabilities.url().into_client_request()?; let mut request = capabilities.url().into_client_request()?;
request request
.headers_mut() .headers_mut()
.insert("Authorization", "Bearer 123".parse().unwrap()); //TODO implement .insert("Authorization", self.authorization.parse().unwrap());
let (stream, _) = tokio_tungstenite::connect_async(request).await?; let (stream, _) = tokio_tungstenite::connect_async(request).await?;
let (tx, mut rx) = stream.split(); let (tx, mut rx) = stream.split();