From 64005f12834b2b73b1e4fcaab3dac4237d7a6511 Mon Sep 17 00:00:00 2001 From: LIAUD Corentin Date: Sat, 4 Dec 2021 11:50:47 +0100 Subject: [PATCH] Adds basic_auth() & bearer_auth() on ClientBuilder --- src/async_impl/client.rs | 59 +++++++++++++++++++++++++++++++++++++++- src/blocking/client.rs | 30 ++++++++++++++++++++ tests/client.rs | 48 ++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) diff --git a/src/async_impl/client.rs b/src/async_impl/client.rs index 1735a1bb1..0b30aa600 100644 --- a/src/async_impl/client.rs +++ b/src/async_impl/client.rs @@ -6,10 +6,11 @@ use std::time::Duration; use std::{collections::HashMap, convert::TryInto, net::SocketAddr}; use std::{fmt, str}; +use base64::encode; use bytes::Bytes; use http::header::{ Entry, HeaderMap, HeaderValue, ACCEPT, ACCEPT_ENCODING, CONTENT_ENCODING, CONTENT_LENGTH, - CONTENT_TYPE, LOCATION, PROXY_AUTHORIZATION, RANGE, REFERER, TRANSFER_ENCODING, USER_AGENT, + CONTENT_TYPE, LOCATION, PROXY_AUTHORIZATION, RANGE, REFERER, TRANSFER_ENCODING, USER_AGENT, AUTHORIZATION, }; use http::uri::Scheme; use http::Uri; @@ -881,6 +882,62 @@ impl ClientBuilder { self } + /// Enable HTTP basic authentication. + /// + /// ```rust + /// # use reqwest::Error; + /// # async fn run() -> Result<(), Error> { + /// let client = reqwest::ClientBuilder::new() + /// .basic_auth("admin", Some("good password")) + /// .build()?; + /// let resp = client.delete("http://httpbin.org/delete") + /// .send() + /// .await?; + /// # Ok(()) + /// # } + /// ``` + pub fn basic_auth(mut self, username: U, password: Option

) -> ClientBuilder + where + U: fmt::Display, + P: fmt::Display, + { + let auth = match password { + Some(password) => format!("{}:{}", username, password), + None => format!("{}:", username), + }; + let header_value = format!("Basic {}", encode(&auth)); + + match header_value.try_into() { + Ok(header_value) => { + self.config.headers.insert(AUTHORIZATION, header_value); + } + Err(e) => { + self.config.error = Some(crate::error::builder::(e.into())); + } + }; + + self + } + + /// Enable HTTP bearer authentication. + pub fn bearer_auth(mut self, token: T) -> ClientBuilder + where + T: fmt::Display, + { + let header_value = format!("Bearer {}", token); + + match header_value.try_into() { + Ok(header_value) => { + self.config.headers.insert(AUTHORIZATION, header_value); + } + Err(e) => { + self.config.error = Some(crate::error::builder::(e.into())); + } + }; + + self + } + /// Enable a persistent cookie store for the client. /// /// Cookies received in responses will be preserved and included in diff --git a/src/blocking/client.rs b/src/blocking/client.rs index a8c5319b4..5fe2b5c12 100644 --- a/src/blocking/client.rs +++ b/src/blocking/client.rs @@ -164,6 +164,36 @@ impl ClientBuilder { self.with_inner(move |inner| inner.default_headers(headers)) } + /// Enable HTTP basic authentication. + /// + /// ```rust + /// # use reqwest::Error; + /// # async fn run() -> Result<(), Error> { + /// let client = reqwest::blocking::ClientBuilder::new() + /// .basic_auth("admin", Some("good password")) + /// .build()?; + /// let resp = client.delete("http://httpbin.org/delete") + /// .send() + /// .await?; + /// # Ok(()) + /// # } + /// ``` + pub fn basic_auth(self, username: U, password: Option

) -> ClientBuilder + where + U: fmt::Display, + P: fmt::Display, + { + self.with_inner(move |inner| inner.basic_auth(username, password)) + } + + /// Enable HTTP bearer authentication. + pub fn bearer_auth(self, token: T) -> ClientBuilder + where + T: fmt::Display, + { + self.with_inner(move |inner| inner.bearer_auth(token)) + } + /// Enable a persistent cookie store for the client. /// /// Cookies received in responses will be preserved and included in diff --git a/tests/client.rs b/tests/client.rs index 51fb9dfa0..0c285e2f3 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -133,6 +133,54 @@ async fn user_agent() { assert_eq!(res.status(), reqwest::StatusCode::OK); } +#[tokio::test] +async fn basic_auth() { + let server = server::http(move |req| async move { + assert_eq!( + req.headers()["authorization"], + "Basic YWRtaW46Z29vZCBwYXNzd29yZA==" + ); + http::Response::default() + }); + + let url = format!("http://{}/basic", server.addr()); + let res = reqwest::Client::builder() + .basic_auth("admin", Some("good password")) + .build() + .expect("client builder") + .get(&url) + .send() + .await + .expect("request"); + + assert_eq!(res.status(), reqwest::StatusCode::OK); +} + +#[tokio::test] +async fn bearer_auth() { + let bearer_token = "iwefOJASndcsde645f"; + + let server = server::http(move |req| async move { + assert_eq!( + req.headers()["authorization"], + format!("Bearer {}", bearer_token) + ); + http::Response::default() + }); + + let url = format!("http://{}/basic", server.addr()); + let res = reqwest::Client::builder() + .bearer_auth(bearer_token) + .build() + .expect("client builder") + .get(&url) + .send() + .await + .expect("request"); + + assert_eq!(res.status(), reqwest::StatusCode::OK); +} + #[tokio::test] async fn response_text() { let _ = env_logger::try_init();