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}