Skip to main content

aws_sigv4/
http_request.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Utilities to sign HTTP requests.
7//!
8//! # Example: Signing an HTTP request
9//!
10//! **Note**: This requires the `http1` feature (enabled by default). To sign a pre-1.x
11//! `http` 0.2.x request with [`SigningInstructions::apply_to_request_http0x`], enable the
12//! `http0-compat` feature instead.
13//!
14//! [`SigningInstructions::apply_to_request_http0x`]: crate::http_request::SigningInstructions::apply_to_request_http0x
15//!
16//! ```rust
17//! # use aws_credential_types::Credentials;
18//! use aws_smithy_runtime_api::client::identity::Identity;
19//! # use aws_sigv4::http_request::SignableBody;
20//! #[cfg(feature = "http1")]
21//! fn test() -> Result<(), aws_sigv4::http_request::SigningError> {
22//! use aws_sigv4::http_request::{sign, SigningSettings, SigningParams, SignableRequest};
23//! use aws_sigv4::sign::v4;
24//! use std::time::SystemTime;
25//!
26//! // Set up information and settings for the signing
27//! // You can obtain credentials from `SdkConfig`.
28//! let identity = Credentials::new(
29//!     "AKIDEXAMPLE",
30//!     "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
31//!     None,
32//!     None,
33//!     "hardcoded-credentials"
34//! ).into();
35//! let signing_settings = SigningSettings::default();
36//! let signing_params = v4::SigningParams::builder()
37//!     .identity(&identity)
38//!     .region("us-east-1")
39//!     .name("exampleservice")
40//!     .time(SystemTime::now())
41//!     .settings(signing_settings)
42//!     .build()
43//!     .unwrap()
44//!     .into();
45//! // Convert the HTTP request into a signable request
46//! let signable_request = SignableRequest::new(
47//!     "GET",
48//!     "https://some-endpoint.some-region.amazonaws.com",
49//!     std::iter::empty(),
50//!     SignableBody::Bytes(&[])
51//! ).expect("signable request");
52//!
53//! let mut my_req = http::Request::new("...");
54//! // Sign and then apply the signature to the request
55//! let (signing_instructions, _signature) = sign(signable_request, &signing_params)?.into_parts();
56//! signing_instructions.apply_to_request_http1x(&mut my_req);
57//! # Ok(())
58//! # }
59//! ```
60
61mod canonical_request;
62mod error;
63mod settings;
64mod sign;
65mod uri_path_normalization;
66mod url_escape;
67
68#[cfg(test)]
69pub(crate) mod test;
70
71use crate::sign::v4;
72#[cfg(feature = "sigv4a")]
73use crate::sign::v4a;
74use crate::SignatureVersion;
75use aws_credential_types::Credentials;
76pub use error::SigningError;
77pub use settings::{
78    PayloadChecksumKind, PercentEncodingMode, SessionTokenMode, SignatureLocation, SigningSettings,
79    UriPathNormalizationMode,
80};
81pub use sign::{sign, SignableBody, SignableRequest, SigningInstructions};
82use std::time::SystemTime;
83
84// Individual Debug impls are responsible for redacting sensitive fields.
85#[derive(Debug)]
86#[non_exhaustive]
87/// Parameters for signing an HTTP request.
88pub enum SigningParams<'a> {
89    /// Sign with the SigV4 algorithm
90    V4(v4::SigningParams<'a, SigningSettings>),
91    #[cfg(feature = "sigv4a")]
92    /// Sign with the SigV4a algorithm
93    V4a(v4a::SigningParams<'a, SigningSettings>),
94}
95
96impl<'a> From<v4::SigningParams<'a, SigningSettings>> for SigningParams<'a> {
97    fn from(value: v4::SigningParams<'a, SigningSettings>) -> Self {
98        Self::V4(value)
99    }
100}
101
102#[cfg(feature = "sigv4a")]
103impl<'a> From<v4a::SigningParams<'a, SigningSettings>> for SigningParams<'a> {
104    fn from(value: v4a::SigningParams<'a, SigningSettings>) -> Self {
105        Self::V4a(value)
106    }
107}
108
109impl SigningParams<'_> {
110    /// Return the credentials within the signing params.
111    pub(crate) fn credentials(&self) -> Result<&Credentials, SigningError> {
112        let identity = match self {
113            Self::V4(v4::SigningParams { identity, .. }) => identity,
114            #[cfg(feature = "sigv4a")]
115            Self::V4a(v4a::SigningParams { identity, .. }) => identity,
116        };
117
118        identity
119            .data::<Credentials>()
120            .ok_or_else(SigningError::unsupported_identity_type)
121    }
122
123    /// If the signing params are for SigV4, return the region. Otherwise, return `None`.
124    pub fn region(&self) -> Option<&str> {
125        match self {
126            SigningParams::V4(v4::SigningParams { region, .. }) => Some(region),
127            #[allow(unreachable_patterns)]
128            _ => None,
129        }
130    }
131
132    #[cfg(feature = "sigv4a")]
133    /// If the signing params are for SigV4a, return the region set. Otherwise, return `None`.
134    pub fn region_set(&self) -> Option<&str> {
135        match self {
136            SigningParams::V4a(v4a::SigningParams { region_set, .. }) => Some(region_set),
137            _ => None,
138        }
139    }
140
141    /// Return a reference to the settings held by the signing params.
142    pub fn settings(&self) -> &SigningSettings {
143        match self {
144            Self::V4(v4::SigningParams { settings, .. }) => settings,
145            #[cfg(feature = "sigv4a")]
146            Self::V4a(v4a::SigningParams { settings, .. }) => settings,
147        }
148    }
149
150    /// Return a mutable reference to the settings held by the signing params.
151    pub fn settings_mut(&mut self) -> &mut SigningSettings {
152        match self {
153            Self::V4(v4::SigningParams { settings, .. }) => settings,
154            #[cfg(feature = "sigv4a")]
155            Self::V4a(v4a::SigningParams { settings, .. }) => settings,
156        }
157    }
158
159    #[cfg(test)]
160    /// Set the [`PayloadChecksumKind`] for the signing params.
161    pub fn set_payload_checksum_kind(&mut self, kind: PayloadChecksumKind) {
162        let settings = self.settings_mut();
163
164        settings.payload_checksum_kind = kind;
165    }
166
167    #[cfg(test)]
168    /// Set the [`SessionTokenMode`] for the signing params.
169    pub fn set_session_token_mode(&mut self, mode: SessionTokenMode) {
170        let settings = self.settings_mut();
171
172        settings.session_token_mode = mode;
173    }
174
175    /// Return a reference to the time in the signing params.
176    pub fn time(&self) -> &SystemTime {
177        match self {
178            Self::V4(v4::SigningParams { time, .. }) => time,
179            #[cfg(feature = "sigv4a")]
180            Self::V4a(v4a::SigningParams { time, .. }) => time,
181        }
182    }
183
184    /// Return a reference to the name in the signing params.
185    pub fn name(&self) -> &str {
186        match self {
187            Self::V4(v4::SigningParams { name, .. }) => name,
188            #[cfg(feature = "sigv4a")]
189            Self::V4a(v4a::SigningParams { name, .. }) => name,
190        }
191    }
192
193    /// Return the name of the configured signing algorithm.
194    pub fn algorithm(&self) -> &'static str {
195        match self {
196            Self::V4(params) => params.algorithm(),
197            #[cfg(feature = "sigv4a")]
198            Self::V4a(params) => params.algorithm(),
199        }
200    }
201
202    /// Return the name of the signing scheme
203    pub fn signature_version(&self) -> SignatureVersion {
204        match self {
205            Self::V4(..) => SignatureVersion::V4,
206            #[cfg(feature = "sigv4a")]
207            Self::V4a(..) => SignatureVersion::V4a,
208        }
209    }
210}