Skip to content

Commit b344d87

Browse files
authored
Allow cloning the transport with different credentials (#260)
* Allow cloning the transport with different credentials * Allow using an arbitrary value for the Authorization header
1 parent 336cd06 commit b344d87

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

elasticsearch/src/auth.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ pub enum Credentials {
3535
ApiKey(String, String),
3636
/// An API key as a base64-encoded id and secret
3737
EncodedApiKey(String),
38+
/// An arbitrary value for the Authorization header
39+
AuthorizationHeader(String),
3840
}
3941

4042
#[cfg(any(feature = "native-tls", feature = "rustls-tls"))]

elasticsearch/src/http/transport.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,9 @@ impl Transport {
543543
header_value.set_sensitive(true);
544544
request_builder.header(AUTHORIZATION, header_value)
545545
}
546+
Credentials::AuthorizationHeader(header) => {
547+
request_builder.header(AUTHORIZATION, header.clone())
548+
}
546549
}
547550
}
548551
drop(creds_guard);
@@ -711,6 +714,20 @@ impl Transport {
711714
pub fn set_auth(&self, credentials: Credentials) {
712715
*self.credentials.write() = Some(credentials);
713716
}
717+
718+
/// Creates a new `Transport` that is a clone of this one, except for authentication
719+
/// credentials. This is the opposite of [`Transport::set_auth()`]. Typically used
720+
/// when working in multi-tenant environments where credentials can vary with every
721+
/// request.
722+
pub fn clone_with_auth(&self, credentials: Option<Credentials>) -> Self {
723+
Self {
724+
client: self.client.clone(),
725+
credentials: Arc::new(RwLock::new(credentials)),
726+
conn_pool: self.conn_pool.clone(),
727+
request_body_compression: self.request_body_compression,
728+
send_meta: self.send_meta,
729+
}
730+
}
714731
}
715732

716733
impl Default for Transport {
@@ -1298,4 +1315,28 @@ pub mod tests {
12981315

12991316
Ok(())
13001317
}
1318+
1319+
#[test]
1320+
fn clone_with_credentials() -> anyhow::Result<()> {
1321+
let t1: Transport = TransportBuilder::new(SingleNodeConnectionPool::default())
1322+
.auth(Credentials::Basic("foo".to_string(), "bar".to_string()))
1323+
.build()?;
1324+
1325+
let t2 = t1.clone_with_auth(Some(Credentials::Bearer("The bear".to_string())));
1326+
1327+
if let Some(Credentials::Basic(login, password)) = t1.credentials.read().as_ref() {
1328+
assert_eq!(login, "foo");
1329+
assert_eq!(password, "bar");
1330+
} else {
1331+
panic!("Expected Basic credentials");
1332+
}
1333+
1334+
if let Some(Credentials::Bearer(token)) = t2.credentials.read().as_ref() {
1335+
assert_eq!(token, "The bear");
1336+
} else {
1337+
panic!("Expected Bearer credentials");
1338+
}
1339+
1340+
Ok(())
1341+
}
13011342
}

elasticsearch/tests/auth.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,22 @@ async fn bearer_header() -> anyhow::Result<()> {
116116
Ok(())
117117
}
118118

119+
#[tokio::test]
120+
async fn arbitrary_auth_header() -> anyhow::Result<()> {
121+
let server = server::http(move |req| async move {
122+
assert_eq!(req.headers()["authorization"], "Foo bar baz");
123+
http::Response::default()
124+
});
125+
126+
let builder = client::create_builder(format!("http://{}", server.addr()).as_ref())
127+
.auth(Credentials::AuthorizationHeader("Foo bar baz".into()));
128+
129+
let client = client::create(builder);
130+
let _response = client.ping().send().await?;
131+
132+
Ok(())
133+
}
134+
119135
// TODO: test PKI authentication. Could configure a HttpsConnector, maybe using https://github.com/sfackler/hyper-openssl?, or send to PKI configured Elasticsearch.
120136
//#[tokio::test]
121137
//async fn client_certificate() -> anyhow::Result<()> {

0 commit comments

Comments
 (0)