[backport-735-v0.8.x] backport changes to custom_requester.rs

This commit is contained in:
Alex Auvolat 2024-03-01 12:40:13 +01:00
parent 610af71e36
commit 430d0be48c
No known key found for this signature in database
GPG key ID: 0E496D15096376BE

View file

@ -1,11 +1,14 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::{TryFrom, TryInto};
use chrono::{offset::Utc, DateTime}; use chrono::{offset::Utc, DateTime};
use hmac::{Hmac, Mac}; use hmac::{Hmac, Mac};
use hyper::client::HttpConnector; use hyper::client::HttpConnector;
use hyper::header::{
HeaderMap, HeaderName, HeaderValue, AUTHORIZATION, CONTENT_ENCODING, CONTENT_LENGTH, HOST,
};
use hyper::{Body, Client, Method, Request, Response, Uri}; use hyper::{Body, Client, Method, Request, Response, Uri};
use super::garage::{Instance, Key}; use super::garage::{Instance, Key};
@ -168,54 +171,85 @@ impl<'a> RequestBuilder<'a> {
.unwrap(); .unwrap();
let streaming_signer = signer.clone(); let streaming_signer = signer.clone();
let mut all_headers = self.signed_headers.clone(); let mut all_headers = self
.signed_headers
.iter()
.map(|(k, v)| {
(
HeaderName::try_from(k).expect("invalid header name"),
HeaderValue::try_from(v).expect("invalid header value"),
)
})
.collect::<HeaderMap>();
let date = now.format(signature::LONG_DATETIME).to_string(); let date = now.format(signature::LONG_DATETIME).to_string();
all_headers.insert("x-amz-date".to_owned(), date); all_headers.insert(
all_headers.insert("host".to_owned(), host); signature::payload::X_AMZ_DATE,
HeaderValue::from_str(&date).unwrap(),
);
all_headers.insert(HOST, HeaderValue::from_str(&host).unwrap());
let body_sha = match self.body_signature { let body_sha = match self.body_signature {
BodySignature::Unsigned => "UNSIGNED-PAYLOAD".to_owned(), BodySignature::Unsigned => "UNSIGNED-PAYLOAD".to_owned(),
BodySignature::Classic => hex::encode(garage_util::data::sha256sum(&self.body)), BodySignature::Classic => hex::encode(garage_util::data::sha256sum(&self.body)),
BodySignature::Streaming(size) => { BodySignature::Streaming(size) => {
all_headers.insert("content-encoding".to_owned(), "aws-chunked".to_owned());
all_headers.insert( all_headers.insert(
"x-amz-decoded-content-length".to_owned(), CONTENT_ENCODING,
self.body.len().to_string(), HeaderValue::from_str("aws-chunked").unwrap(),
);
all_headers.insert(
HeaderName::from_static("x-amz-decoded-content-length"),
HeaderValue::from_str(&self.body.len().to_string()).unwrap(),
); );
// Get lenght of body by doing the conversion to a streaming body with an // Get lenght of body by doing the conversion to a streaming body with an
// invalid signature (we don't know the seed) just to get its length. This // invalid signature (we don't know the seed) just to get its length. This
// is a pretty lazy and inefficient way to do it, but it's enought for test // is a pretty lazy and inefficient way to do it, but it's enought for test
// code. // code.
all_headers.insert( all_headers.insert(
"content-length".to_owned(), CONTENT_LENGTH,
to_streaming_body(&self.body, size, String::new(), signer.clone(), now, "") to_streaming_body(&self.body, size, String::new(), signer.clone(), now, "")
.len() .len()
.to_string(), .to_string()
.try_into()
.unwrap(),
); );
"STREAMING-AWS4-HMAC-SHA256-PAYLOAD".to_owned() "STREAMING-AWS4-HMAC-SHA256-PAYLOAD".to_owned()
} }
}; };
all_headers.insert("x-amz-content-sha256".to_owned(), body_sha.clone()); all_headers.insert(
signature::payload::X_AMZ_CONTENT_SH256,
HeaderValue::from_str(&body_sha).unwrap(),
);
let mut signed_headers = all_headers let mut signed_headers = all_headers.keys().cloned().collect::<Vec<_>>();
signed_headers.sort_by(|h1, h2| h1.as_str().cmp(h2.as_str()));
let signed_headers_str = signed_headers
.iter() .iter()
.map(|(k, _)| k.as_ref()) .map(ToString::to_string)
.collect::<Vec<&str>>(); .collect::<Vec<_>>()
signed_headers.sort(); .join(";");
let signed_headers = signed_headers.join(";");
all_headers.extend(self.unsigned_headers.clone()); all_headers.extend(self.unsigned_headers.iter().map(|(k, v)| {
(
HeaderName::try_from(k).expect("invalid header name"),
HeaderValue::try_from(v).expect("invalid header value"),
)
}));
let uri = Uri::try_from(&uri).unwrap();
let query = signature::payload::parse_query_map(&uri).unwrap();
let canonical_request = signature::payload::canonical_request( let canonical_request = signature::payload::canonical_request(
self.service, self.service,
&self.method, &self.method,
&Uri::try_from(&uri).unwrap(), uri.path(),
&query,
&all_headers, &all_headers,
&signed_headers, &signed_headers,
&body_sha, &body_sha,
); )
.unwrap();
let string_to_sign = signature::payload::string_to_sign(&now, &scope, &canonical_request); let string_to_sign = signature::payload::string_to_sign(&now, &scope, &canonical_request);
@ -223,14 +257,15 @@ impl<'a> RequestBuilder<'a> {
let signature = hex::encode(signer.finalize().into_bytes()); let signature = hex::encode(signer.finalize().into_bytes());
let authorization = format!( let authorization = format!(
"AWS4-HMAC-SHA256 Credential={}/{},SignedHeaders={},Signature={}", "AWS4-HMAC-SHA256 Credential={}/{},SignedHeaders={},Signature={}",
self.requester.key.id, scope, signed_headers, signature self.requester.key.id, scope, signed_headers_str, signature
);
all_headers.insert(
AUTHORIZATION,
HeaderValue::from_str(&authorization).unwrap(),
); );
all_headers.insert("authorization".to_owned(), authorization);
let mut request = Request::builder(); let mut request = Request::builder();
for (k, v) in all_headers { *request.headers_mut().unwrap() = all_headers;
request = request.header(k, v);
}
let body = if let BodySignature::Streaming(size) = self.body_signature { let body = if let BodySignature::Streaming(size) = self.body_signature {
to_streaming_body(&self.body, size, signature, streaming_signer, now, &scope) to_streaming_body(&self.body, size, signature, streaming_signer, now, &scope)