Create new configuration option for redirect preserving authorization header in Agent. Handle new option in Unit

This commit is contained in:
llde
2021-12-10 17:56:44 +01:00
committed by Martin Algesten
parent 38ad90307d
commit 653f791638
2 changed files with 36 additions and 18 deletions

View File

@@ -16,6 +16,16 @@ use {
cookie_store::CookieStore, cookie_store::CookieStore,
}; };
/// Specify the strategy for propagation of authorization headers during Redirects
///
/// Never is the default strategy and never send authorization headers in Redirects
/// SameHost send the authorization header in Redirects only if the host of the Redirect is the same of the previous request, and both use the Https scheme
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RedirectAuthHeaders {
Never,
SameHost,
}
/// Accumulates options towards building an [Agent]. /// Accumulates options towards building an [Agent].
#[derive(Debug)] #[derive(Debug)]
pub struct AgentBuilder { pub struct AgentBuilder {
@@ -38,6 +48,7 @@ pub(crate) struct AgentConfig {
pub timeout_write: Option<Duration>, pub timeout_write: Option<Duration>,
pub timeout: Option<Duration>, pub timeout: Option<Duration>,
pub redirects: u32, pub redirects: u32,
pub redirect_auth_headers: RedirectAuthHeaders,
pub user_agent: String, pub user_agent: String,
pub tls_config: Arc<dyn TlsConnector>, pub tls_config: Arc<dyn TlsConnector>,
} }
@@ -221,6 +232,7 @@ impl AgentBuilder {
timeout_write: None, timeout_write: None,
timeout: None, timeout: None,
redirects: 5, redirects: 5,
redirect_auth_headers: RedirectAuthHeaders::Never,
user_agent: format!("ureq/{}", env!("CARGO_PKG_VERSION")), user_agent: format!("ureq/{}", env!("CARGO_PKG_VERSION")),
tls_config: crate::default_tls_config(), tls_config: crate::default_tls_config(),
}, },
@@ -445,6 +457,15 @@ impl AgentBuilder {
self self
} }
/// Set the strategy for propagation of authorization headers in redirects.
///
/// Defaults to RedirectAuthHeaders::Never.
///
pub fn set_redirect_auth_headers(mut self, v: RedirectAuthHeaders) -> Self {
self.config.redirect_auth_headers = v;
self
}
/// The user-agent header to associate with all requests from this agent by default. /// The user-agent header to associate with all requests from this agent by default.
/// ///
/// Defaults to `ureq/[VERSION]`. You can override the user-agent on an individual request by /// Defaults to `ureq/[VERSION]`. You can override the user-agent on an individual request by

View File

@@ -9,6 +9,7 @@ use url::Url;
#[cfg(feature = "cookies")] #[cfg(feature = "cookies")]
use cookie::Cookie; use cookie::Cookie;
use crate::agent::RedirectAuthHeaders;
use crate::body::{self, BodySize, Payload, SizedReader}; use crate::body::{self, BodySize, Payload, SizedReader};
use crate::error::{Error, ErrorKind}; use crate::error::{Error, ErrorKind};
use crate::header; use crate::header;
@@ -353,6 +354,17 @@ fn connect_socket(unit: &Unit, hostname: &str, use_pooled: bool) -> Result<(Stre
Ok((stream?, false)) Ok((stream?, false))
} }
fn can_propagate_authorization_on_redirect(unit: &Unit, previous: &[String]) -> bool {
if let RedirectAuthHeaders::SameHost = unit.agent.config.redirect_auth_headers {
let host_s = unit.url.host_str().unwrap();
let prev_url = Url::parse(&previous[0]).unwrap();
let prev_host = prev_url.host_str().unwrap();
host_s == prev_host && prev_url.scheme() == "https" && unit.url.scheme() == "https"
} else {
false
}
}
/// Send request line + headers (all up until the body). /// Send request line + headers (all up until the body).
#[allow(clippy::write_with_newline)] #[allow(clippy::write_with_newline)]
fn send_prelude(unit: &Unit, stream: &mut Stream, previous: &[String]) -> io::Result<()> { fn send_prelude(unit: &Unit, stream: &mut Stream, previous: &[String]) -> io::Result<()> {
@@ -393,28 +405,13 @@ fn send_prelude(unit: &Unit, stream: &mut Stream, previous: &[String]) -> io::Re
if !header::has_header(&unit.headers, "accept") { if !header::has_header(&unit.headers, "accept") {
prelude.write_header("Accept", "*/*")?; prelude.write_header("Accept", "*/*")?;
} }
//Preserve Authorization in Same Host redirections
let host_s = unit.url.host_str().unwrap();
let preserve_auth = if !previous.is_empty() { let preserve_auth = if !previous.is_empty() {
let prev_url = Url::parse(&previous[0]).unwrap(); can_propagate_authorization_on_redirect(unit, previous)
if let Some(prev_host) = prev_url.host_str() {
if host_s == prev_host {
if prev_url.scheme() == unit.url.scheme() {
let port = unit.url.port().unwrap_or(scheme_default);
let prev_port = prev_url.port().unwrap_or(scheme_default);
port == prev_port
} else {
false
}
} else {
false
}
} else {
false
}
} else { } else {
true //Not in redirection true //Not in redirection
}; };
// other headers // other headers
for header in &unit.headers { for header in &unit.headers {
if preserve_auth || !header.is_name("Authorization") { if preserve_auth || !header.is_name("Authorization") {