diff --git a/aws/rust-runtime/aws-config/Cargo.toml b/aws/rust-runtime/aws-config/Cargo.toml index daf10d31f2e0dcba68387ec1ab4d1c71fd0d2318..fb2cd18465c15989c80ab9562da0f2d3eebc2856 100644 --- a/aws/rust-runtime/aws-config/Cargo.toml +++ b/aws/rust-runtime/aws-config/Cargo.toml @@ -23,6 +23,7 @@ aws-smithy-async = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-async" } aws-smithy-client = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-client", default-features = false } aws-smithy-types = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-types" } aws-types = { path = "../../sdk/build/aws-sdk/sdk/aws-types" } +time = { version = "0.3.4", features = ["parsing"] } tokio = { version = "1", features = ["sync"] } tracing = { version = "0.1" } hyper = { version = "0.14", default-features = false } diff --git a/aws/rust-runtime/aws-config/src/credential_process.rs b/aws/rust-runtime/aws-config/src/credential_process.rs index 5a75089ac45b399c3c6095ef65173899649024e3..fc3409b401af2af2bf7d73e6443dcd4eb4f69ce9 100644 --- a/aws/rust-runtime/aws-config/src/credential_process.rs +++ b/aws/rust-runtime/aws-config/src/credential_process.rs @@ -7,13 +7,13 @@ use crate::json_credentials::{json_parse_loop, InvalidJsonCredentials, RefreshableCredentials}; use aws_smithy_json::deserialize::Token; -use aws_smithy_types::date_time::Format; -use aws_smithy_types::DateTime; use aws_types::credentials::{future, CredentialsError, ProvideCredentials}; use aws_types::{credentials, Credentials}; use std::fmt; use std::process::Command; use std::time::SystemTime; +use time::format_description::well_known::Rfc3339; +use time::OffsetDateTime; #[derive(Clone)] pub(crate) struct CommandWithSensitiveArgs(T); @@ -232,19 +232,18 @@ pub(crate) fn parse_credential_process_json_credentials( secret_access_key.ok_or(InvalidJsonCredentials::MissingField("SecretAccessKey"))?; let session_token = session_token.ok_or(InvalidJsonCredentials::MissingField("Token"))?; let expiration = expiration.ok_or(InvalidJsonCredentials::MissingField("Expiration"))?; - let expiration = SystemTime::try_from( - DateTime::from_str(expiration.as_ref(), Format::DateTime).map_err(|err| { + let expiration = + SystemTime::try_from(OffsetDateTime::parse(&expiration, &Rfc3339).map_err(|err| { InvalidJsonCredentials::InvalidField { field: "Expiration", err: err.into(), } - })?, - ) - .map_err(|_| { - InvalidJsonCredentials::Other( - "credential expiration time cannot be represented by a DateTime".into(), - ) - })?; + })?) + .map_err(|_| { + InvalidJsonCredentials::Other( + "credential expiration time cannot be represented by a DateTime".into(), + ) + })?; Ok(RefreshableCredentials { access_key_id, secret_access_key, @@ -256,10 +255,10 @@ pub(crate) fn parse_credential_process_json_credentials( #[cfg(test)] mod test { use crate::credential_process::CredentialProcessProvider; - use aws_smithy_types::date_time::Format; - use aws_smithy_types::DateTime; use aws_types::credentials::ProvideCredentials; use std::time::SystemTime; + use time::format_description::well_known::Rfc3339; + use time::OffsetDateTime; #[tokio::test] async fn test_credential_process() { @@ -274,7 +273,7 @@ mod test { creds.expiry(), Some( SystemTime::try_from( - DateTime::from_str("2022-05-02T18:36:00+00:00", Format::DateTime) + OffsetDateTime::parse("2022-05-02T18:36:00+00:00", &Rfc3339) .expect("static datetime") ) .expect("static datetime") diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt index e694e2cc4e7a86cbdec6b139a9ff319e3b311e16..38446695d053c84c9f26a2e03e0d0b96b370ffa5 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt @@ -695,12 +695,10 @@ class ServerProtocolTestGenerator( FailingTest(RestJson, "RestJsonBodyShortUnderflowOverflow_case2", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonBodyShortUnderflowOverflow_case3", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonHeaderMalformedStringInvalidBase64MediaType_case1", TestType.MalformedRequest), - FailingTest(RestJson, "RestJsonBodyTimestampDateTimeRejectsUTCOffsets_case0", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonBodyTimestampDefaultRejectsMalformedEpochSeconds_case5", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonBodyTimestampDefaultRejectsMalformedEpochSeconds_case7", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonBodyTimestampDefaultRejectsMalformedEpochSeconds_case9", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonPathTimestampDefaultRejectsDifferent8601Formats_case13", TestType.MalformedRequest), - FailingTest(RestJson, "RestJsonPathTimestampDefaultRejectsUTCOffsets", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonQueryTimestampDefaultRejectsDifferent8601Formats_case13", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonMalformedUnionNoFieldsSet", TestType.MalformedRequest), FailingTest(RestJson, "RestJsonMalformedSetDuplicateBlobs", TestType.MalformedRequest), diff --git a/rust-runtime/aws-smithy-types/src/date_time/format.rs b/rust-runtime/aws-smithy-types/src/date_time/format.rs index 9923aeb36e9d6c2a7e1cfd9ae2bfbe5c133eb82c..dd5d72d1b37bb9d9ba87c6383c2f4d74417d4cdf 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/format.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/format.rs @@ -377,6 +377,11 @@ pub(crate) mod rfc3339 { // Timezones not supported: // Not OK: 1985-04-12T23:20:50-02:00 pub(crate) fn parse(s: &str) -> Result { + if !matches!(s.chars().last(), Some('Z')) { + return Err(DateTimeParseError::Invalid( + "Smithy does not support timezone offsets in RFC-3339 date times".into(), + )); + } let date_time = OffsetDateTime::parse(s, &Rfc3339).map_err(|err| { DateTimeParseError::Invalid(format!("invalid RFC-3339 date-time: {}", err).into()) })?; @@ -626,6 +631,12 @@ mod tests { assert_eq!(e2, expected); } + #[test] + fn parse_rfc3339_timezone_forbidden() { + let dt = rfc3339::parse("1985-04-12T23:20:50-02:00"); + assert!(matches!(dt.unwrap_err(), DateTimeParseError::Invalid(_))); + } + #[test] fn http_date_out_of_range() { assert_eq!(