Skip to content

Commit 25d39c1

Browse files
ByteBakeralamb
andauthored
feat: further TLS options on ClientOptions: #5034 (#6148)
* feat: further TLS options on ClientOptions: #5034 * Rename to Certificate and with_root_certificate, add docs --------- Co-authored-by: Andrew Lamb <[email protected]>
1 parent d7ad4fe commit 25d39c1

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

object_store/src/client/mod.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,60 @@ impl FromStr for ClientConfigKey {
167167
}
168168
}
169169

170+
/// Represents a CA certificate provided by the user.
171+
///
172+
/// This is used to configure the client to trust a specific certificate. See
173+
/// [Self::from_pem] for an example
174+
#[derive(Debug, Clone)]
175+
pub struct Certificate(reqwest::tls::Certificate);
176+
177+
impl Certificate {
178+
/// Create a `Certificate` from a PEM encoded certificate.
179+
///
180+
/// # Example from a PEM file
181+
///
182+
/// ```no_run
183+
/// # use object_store::Certificate;
184+
/// # use std::fs::File;
185+
/// # use std::io::Read;
186+
/// let mut buf = Vec::new();
187+
/// File::open("my_cert.pem").unwrap()
188+
/// .read_to_end(&mut buf).unwrap();
189+
/// let cert = Certificate::from_pem(&buf).unwrap();
190+
///
191+
/// ```
192+
pub fn from_pem(pem: &[u8]) -> Result<Self> {
193+
Ok(Self(
194+
reqwest::tls::Certificate::from_pem(pem).map_err(map_client_error)?,
195+
))
196+
}
197+
198+
/// Create a collection of `Certificate` from a PEM encoded certificate
199+
/// bundle.
200+
///
201+
/// Files that contain such collections have extensions such as `.crt`,
202+
/// `.cer` and `.pem` files.
203+
pub fn from_pem_bundle(pem_bundle: &[u8]) -> Result<Vec<Self>> {
204+
Ok(reqwest::tls::Certificate::from_pem_bundle(pem_bundle)
205+
.map_err(map_client_error)?
206+
.into_iter()
207+
.map(Self)
208+
.collect())
209+
}
210+
211+
/// Create a `Certificate` from a binary DER encoded certificate.
212+
pub fn from_der(der: &[u8]) -> Result<Self> {
213+
Ok(Self(
214+
reqwest::tls::Certificate::from_der(der).map_err(map_client_error)?,
215+
))
216+
}
217+
}
218+
170219
/// HTTP client configuration for remote object stores
171220
#[derive(Debug, Clone)]
172221
pub struct ClientOptions {
173222
user_agent: Option<ConfigValue<HeaderValue>>,
223+
root_certificates: Vec<Certificate>,
174224
content_type_map: HashMap<String, String>,
175225
default_content_type: Option<String>,
176226
default_headers: Option<HeaderMap>,
@@ -201,6 +251,7 @@ impl Default for ClientOptions {
201251
// we opt for a slightly higher default timeout of 30 seconds
202252
Self {
203253
user_agent: None,
254+
root_certificates: Default::default(),
204255
content_type_map: Default::default(),
205256
default_content_type: None,
206257
default_headers: None,
@@ -310,6 +361,15 @@ impl ClientOptions {
310361
self
311362
}
312363

364+
/// Add a custom root certificate.
365+
///
366+
/// This can be used to connect to a server that has a self-signed
367+
/// certificate for example.
368+
pub fn with_root_certificate(mut self, certificate: Certificate) -> Self {
369+
self.root_certificates.push(certificate);
370+
self
371+
}
372+
313373
/// Set the default CONTENT_TYPE for uploads
314374
pub fn with_default_content_type(mut self, mime: impl Into<String>) -> Self {
315375
self.default_content_type = Some(mime.into());
@@ -541,6 +601,10 @@ impl ClientOptions {
541601
builder = builder.proxy(proxy);
542602
}
543603

604+
for certificate in &self.root_certificates {
605+
builder = builder.add_root_certificate(certificate.0.clone());
606+
}
607+
544608
if let Some(timeout) = &self.timeout {
545609
builder = builder.timeout(timeout.get()?)
546610
}

object_store/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,8 @@ mod client;
526526

527527
#[cfg(feature = "cloud")]
528528
pub use client::{
529-
backoff::BackoffConfig, retry::RetryConfig, ClientConfigKey, ClientOptions, CredentialProvider,
530-
StaticCredentialProvider,
529+
backoff::BackoffConfig, retry::RetryConfig, Certificate, ClientConfigKey, ClientOptions,
530+
CredentialProvider, StaticCredentialProvider,
531531
};
532532

533533
#[cfg(feature = "cloud")]

0 commit comments

Comments
 (0)