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