1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
use http0::header::{AUTHORIZATION, USER_AGENT};
use std::borrow::Cow;
use std::time::Duration;
const HEADER_NAME_X_RAY_TRACE_ID: &str = "x-amzn-trace-id";
/// HTTP-specific signing settings
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub struct SigningSettings {
/// Specifies how to encode the request URL when signing. Some services do not decode
/// the path prior to checking the signature, requiring clients to actually _double-encode_
/// the URI in creating the canonical request in order to pass a signature check.
pub percent_encoding_mode: PercentEncodingMode,
/// Add an additional checksum header
pub payload_checksum_kind: PayloadChecksumKind,
/// Where to put the signature
pub signature_location: SignatureLocation,
/// For presigned requests, how long the presigned request is valid for
pub expires_in: Option<Duration>,
/// Headers that should be excluded from the signing process
pub excluded_headers: Option<Vec<Cow<'static, str>>>,
/// Specifies whether the absolute path component of the URI should be normalized during signing.
pub uri_path_normalization_mode: UriPathNormalizationMode,
/// Some services require X-Amz-Security-Token to be included in the
/// canonical request. Other services require only it to be added after
/// calculating the signature.
pub session_token_mode: SessionTokenMode,
/// Some services require an alternative session token header or query param instead of
/// `x-amz-security-token` or `X-Amz-Security-Token`.
pub session_token_name_override: Option<&'static str>,
}
/// HTTP payload checksum type
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq)]
pub enum PayloadChecksumKind {
/// Add x-amz-checksum-sha256 to the canonical request
///
/// This setting is required for S3
XAmzSha256,
/// Do not add an additional header when creating the canonical request
///
/// This is "normal mode" and will work for services other than S3
NoHeader,
}
/// Config value to specify how to encode the request URL when signing.
///
/// We assume the URI will be encoded _once_ prior to transmission. Some services
/// do not decode the path prior to checking the signature, requiring clients to actually
/// _double-encode_ the URI in creating the canonical request in order to pass a signature check.
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq)]
pub enum PercentEncodingMode {
/// Re-encode the resulting URL (e.g. %30 becomes `%2530)
Double,
/// Take the resulting URL as-is
Single,
}
/// Config value to specify whether the canonical request's URI path should be normalized.
/// <https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html>
///
/// URI path normalization is performed based on <https://www.rfc-editor.org/rfc/rfc3986>.
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq)]
pub enum UriPathNormalizationMode {
/// Normalize the URI path according to RFC3986
Enabled,
/// Don't normalize the URI path (S3, for example, rejects normalized paths in some instances)
Disabled,
}
impl From<bool> for UriPathNormalizationMode {
fn from(value: bool) -> Self {
if value {
UriPathNormalizationMode::Enabled
} else {
UriPathNormalizationMode::Disabled
}
}
}
/// Config value to specify whether X-Amz-Security-Token should be part of the canonical request.
/// <http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html#temporary-security-credentials>
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq)]
pub enum SessionTokenMode {
/// Include in the canonical request before calculating the signature.
Include,
/// Exclude in the canonical request.
Exclude,
}
impl Default for SigningSettings {
fn default() -> Self {
// Headers that are potentially altered by proxies or as a part of standard service operations.
// Reference:
// Go SDK: <https://github.com/aws/aws-sdk-go/blob/v1.44.289/aws/signer/v4/v4.go#L92>
// Java SDK: <https://github.com/aws/aws-sdk-java-v2/blob/master/core/auth/src/main/java/software/amazon/awssdk/auth/signer/internal/AbstractAws4Signer.java#L70>
// JS SDK: <https://github.com/aws/aws-sdk-js/blob/master/lib/signers/v4.js#L191>
// There is no single source of truth for these available, so this uses the minimum common set of the excluded options.
// Instantiate this every time, because SigningSettings takes a Vec (which cannot be const);
let excluded_headers = Some(
[
// This header is calculated as part of the signing process, so if it's present, discard it
Cow::Borrowed(AUTHORIZATION.as_str()),
// Changes when sent by proxy
Cow::Borrowed(USER_AGENT.as_str()),
// Changes based on the request from the client
Cow::Borrowed(HEADER_NAME_X_RAY_TRACE_ID),
]
.to_vec(),
);
Self {
percent_encoding_mode: PercentEncodingMode::Double,
payload_checksum_kind: PayloadChecksumKind::NoHeader,
signature_location: SignatureLocation::Headers,
expires_in: None,
excluded_headers,
uri_path_normalization_mode: UriPathNormalizationMode::Enabled,
session_token_mode: SessionTokenMode::Include,
session_token_name_override: None,
}
}
}
/// Where to place signing values in the HTTP request
#[non_exhaustive]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SignatureLocation {
/// Place the signature in the request headers
Headers,
/// Place the signature in the request query parameters
QueryParams,
}