Unverified Commit 5f49f7cc authored by 82marbag's avatar 82marbag Committed by GitHub
Browse files

forbid timezone in rfc3339 (#1521)

* forbid rfc3339 timezone

According to [0], "Date time as defined by the date-time production
in RFC3339 section 5.6 with no UTC offset..."

This commit makes the parsing compliant.

[0] https://awslabs.github.io/smithy/1.0/spec/core/protocol-traits.html#timestampformat-trait



Signed-off-by: default avatarDaniele Ahmed <ahmeddan@amazon.de>
parent 700cee65
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 }
+13 −14
Original line number Diff line number Diff line
@@ -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>(T);
@@ -232,14 +232,13 @@ 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(),
@@ -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")
+0 −2
Original line number Diff line number Diff line
@@ -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),
+11 −0
Original line number Diff line number Diff line
@@ -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<DateTime, DateTimeParseError> {
        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!(