forked from Deuxfleurs/garage
[fix-presigned] add back anonymous request code path + refactoring
This commit is contained in:
parent
2efa9c5a1a
commit
4c1d42cc5f
2 changed files with 40 additions and 30 deletions
|
@ -40,17 +40,26 @@ pub async fn check_payload_signature(
|
||||||
) -> Result<(Option<Key>, Option<Hash>), Error> {
|
) -> Result<(Option<Key>, Option<Hash>), Error> {
|
||||||
let query = parse_query_map(request.uri())?;
|
let query = parse_query_map(request.uri())?;
|
||||||
|
|
||||||
let res = if query.contains_key(X_AMZ_ALGORITHM.as_str()) {
|
if query.contains_key(X_AMZ_ALGORITHM.as_str()) {
|
||||||
check_presigned_signature(garage, service, request, query).await
|
check_presigned_signature(garage, service, request, query).await
|
||||||
} else {
|
} else if request.headers().contains_key(AUTHORIZATION) {
|
||||||
check_standard_signature(garage, service, request, query).await
|
check_standard_signature(garage, service, request, query).await
|
||||||
};
|
} else {
|
||||||
|
// Unsigned (anonymous) request
|
||||||
if let Err(e) = &res {
|
let content_sha256 = request
|
||||||
error!("ERROR IN SIGNATURE\n{:?}\n{}", request, e);
|
.headers()
|
||||||
|
.get("x-amz-content-sha256")
|
||||||
|
.filter(|c| c.as_bytes() != UNSIGNED_PAYLOAD.as_bytes());
|
||||||
|
if let Some(content_sha256) = content_sha256 {
|
||||||
|
let sha256 = hex::decode(content_sha256)
|
||||||
|
.ok()
|
||||||
|
.and_then(|bytes| Hash::try_from(&bytes))
|
||||||
|
.ok_or_bad_request("Invalid content sha256 hash")?;
|
||||||
|
Ok((None, Some(sha256)))
|
||||||
|
} else {
|
||||||
|
Ok((None, None))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_standard_signature(
|
async fn check_standard_signature(
|
||||||
|
@ -63,8 +72,11 @@ async fn check_standard_signature(
|
||||||
|
|
||||||
// Verify that all necessary request headers are signed
|
// Verify that all necessary request headers are signed
|
||||||
let signed_headers = split_signed_headers(&authorization)?;
|
let signed_headers = split_signed_headers(&authorization)?;
|
||||||
|
if !signed_headers.contains(&HOST) {
|
||||||
|
return Err(Error::bad_request("Header `Host` should be signed"));
|
||||||
|
}
|
||||||
for (name, _) in request.headers().iter() {
|
for (name, _) in request.headers().iter() {
|
||||||
if name.as_str().starts_with("x-amz-") || name == CONTENT_TYPE {
|
if name == CONTENT_TYPE || name.as_str().starts_with("x-amz-") {
|
||||||
if !signed_headers.contains(name) {
|
if !signed_headers.contains(name) {
|
||||||
return Err(Error::bad_request(format!(
|
return Err(Error::bad_request(format!(
|
||||||
"Header `{}` should be signed",
|
"Header `{}` should be signed",
|
||||||
|
@ -73,9 +85,6 @@ async fn check_standard_signature(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !signed_headers.contains(&HOST) {
|
|
||||||
return Err(Error::bad_request("Header `Host` should be signed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let canonical_request = canonical_request(
|
let canonical_request = canonical_request(
|
||||||
service,
|
service,
|
||||||
|
@ -122,6 +131,9 @@ async fn check_presigned_signature(
|
||||||
|
|
||||||
// Check that all mandatory signed headers are included
|
// Check that all mandatory signed headers are included
|
||||||
let signed_headers = split_signed_headers(&authorization)?;
|
let signed_headers = split_signed_headers(&authorization)?;
|
||||||
|
if !signed_headers.contains(&HOST) {
|
||||||
|
return Err(Error::bad_request("Header `Host` should be signed"));
|
||||||
|
}
|
||||||
for (name, _) in request.headers().iter() {
|
for (name, _) in request.headers().iter() {
|
||||||
if name.as_str().starts_with("x-amz-") {
|
if name.as_str().starts_with("x-amz-") {
|
||||||
if !signed_headers.contains(name) {
|
if !signed_headers.contains(name) {
|
||||||
|
@ -132,9 +144,6 @@ async fn check_presigned_signature(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !signed_headers.contains(&HOST) {
|
|
||||||
return Err(Error::bad_request("Header `Host` should be signed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
query.remove(X_AMZ_SIGNATURE.as_str());
|
query.remove(X_AMZ_SIGNATURE.as_str());
|
||||||
let canonical_request = canonical_request(
|
let canonical_request = canonical_request(
|
||||||
|
@ -254,21 +263,17 @@ pub fn canonical_request(
|
||||||
|
|
||||||
// Canonical header string calculated from signed headers
|
// Canonical header string calculated from signed headers
|
||||||
signed_headers.sort_by(|h1, h2| h1.as_str().cmp(h2.as_str()));
|
signed_headers.sort_by(|h1, h2| h1.as_str().cmp(h2.as_str()));
|
||||||
let canonical_header_string = {
|
let canonical_header_string = signed_headers
|
||||||
let mut items = Vec::with_capacity(signed_headers.len());
|
.iter()
|
||||||
for name in signed_headers.iter() {
|
.map(|name| {
|
||||||
let value = headers
|
let value = headers
|
||||||
.get(name)
|
.get(name)
|
||||||
.ok_or_bad_request(format!("signed header `{}` is not present", name))?
|
.ok_or_bad_request(format!("signed header `{}` is not present", name))?
|
||||||
.to_str()?;
|
.to_str()?;
|
||||||
items.push((name, value));
|
Ok(format!("{}:{}", name.as_str(), value.trim()))
|
||||||
}
|
})
|
||||||
items
|
.collect::<Result<Vec<String>, Error>>()?
|
||||||
.iter()
|
.join("\n");
|
||||||
.map(|(key, value)| format!("{}:{}", key.as_str(), value.trim()))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n")
|
|
||||||
};
|
|
||||||
let signed_headers = signed_headers.join(";");
|
let signed_headers = signed_headers.join(";");
|
||||||
|
|
||||||
let list = [
|
let list = [
|
||||||
|
|
|
@ -15,6 +15,11 @@ use super::{compute_scope, sha256sum, HmacSha256, LONG_DATETIME};
|
||||||
|
|
||||||
use crate::helpers::*;
|
use crate::helpers::*;
|
||||||
use crate::signature::error::*;
|
use crate::signature::error::*;
|
||||||
|
use crate::signature::payload::{
|
||||||
|
STREAMING_AWS4_HMAC_SHA256_PAYLOAD, X_AMZ_CONTENT_SH256, X_AMZ_DATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const AWS4_HMAC_SHA256_PAYLOAD: &str = "AWS4-HMAC-SHA256-PAYLOAD";
|
||||||
|
|
||||||
pub type ReqBody = BoxBody<Error>;
|
pub type ReqBody = BoxBody<Error>;
|
||||||
|
|
||||||
|
@ -25,8 +30,8 @@ pub fn parse_streaming_body(
|
||||||
region: &str,
|
region: &str,
|
||||||
service: &str,
|
service: &str,
|
||||||
) -> Result<Request<ReqBody>, Error> {
|
) -> Result<Request<ReqBody>, Error> {
|
||||||
match req.headers().get("x-amz-content-sha256") {
|
match req.headers().get(X_AMZ_CONTENT_SH256) {
|
||||||
Some(header) if header == "STREAMING-AWS4-HMAC-SHA256-PAYLOAD" => {
|
Some(header) if header == STREAMING_AWS4_HMAC_SHA256_PAYLOAD => {
|
||||||
let signature = content_sha256
|
let signature = content_sha256
|
||||||
.take()
|
.take()
|
||||||
.ok_or_bad_request("No signature provided")?;
|
.ok_or_bad_request("No signature provided")?;
|
||||||
|
@ -39,7 +44,7 @@ pub fn parse_streaming_body(
|
||||||
|
|
||||||
let date = req
|
let date = req
|
||||||
.headers()
|
.headers()
|
||||||
.get("x-amz-date")
|
.get(X_AMZ_DATE)
|
||||||
.ok_or_bad_request("Missing X-Amz-Date field")?
|
.ok_or_bad_request("Missing X-Amz-Date field")?
|
||||||
.to_str()?;
|
.to_str()?;
|
||||||
let date: NaiveDateTime = NaiveDateTime::parse_from_str(date, LONG_DATETIME)
|
let date: NaiveDateTime = NaiveDateTime::parse_from_str(date, LONG_DATETIME)
|
||||||
|
@ -75,7 +80,7 @@ fn compute_streaming_payload_signature(
|
||||||
content_sha256: Hash,
|
content_sha256: Hash,
|
||||||
) -> Result<Hash, Error> {
|
) -> Result<Hash, Error> {
|
||||||
let string_to_sign = [
|
let string_to_sign = [
|
||||||
"AWS4-HMAC-SHA256-PAYLOAD",
|
AWS4_HMAC_SHA256_PAYLOAD,
|
||||||
&date.format(LONG_DATETIME).to_string(),
|
&date.format(LONG_DATETIME).to_string(),
|
||||||
scope,
|
scope,
|
||||||
&hex::encode(previous_signature),
|
&hex::encode(previous_signature),
|
||||||
|
|
Loading…
Reference in a new issue