Unverified Commit de97b3d7 authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Remove deprecated ResolveAwsEndpoint and related interfaces. (#2464)

* Remove deprecated ResolveAwsEndpoint and related interfaces.

* update changelog with pointer

* Rename AwsEndpointDecorator to have a more appropriate name

* Allow endpoint resolver to be omitted
parent 05f920f6
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -288,7 +288,6 @@ references = ["smithy-rs#2448"]
meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "client" }
author = "jdisanti"


[[smithy-rs]]
message = "Fix bug in timestamp format resolution. Prior to this fix, the timestamp format may have been incorrect if set on the target instead of on the member."
references = ["smithy-rs#2226"]
@@ -339,8 +338,6 @@ references = ["smithy-rs#2467"]
meta = { "breaking" = true, "tada" = true, "bug" = false, "target" = "all" }
author = "Velfi"

###############

[[aws-sdk-rust]]
message = """Default connector provided by `aws-config` now respects `ConnectorSettings`.

@@ -353,6 +350,14 @@ references = ["smithy-rs#2471", "smithy-rs#2333", "smithy-rs#2151"]
meta = { "breaking" = false, "tada" = false, "bug" = true }
author = "rcoh"

[[aws-sdk-rust]] # remove interfaces
message = """Remove deprecated `ResolveAwsEndpoint` interfaces.
[For details see the longform changelog entry](https://github.com/awslabs/aws-sdk-rust/discussions/755).
"""
author = "rcoh"
references = ["smithy-rs#2390", "smithy-rs#1784"]
meta = { "breaking" = true, "tada" = false, "bug" = false }

[[smithy-rs]] # tokio-upgrade
message = "Increase Tokio version to 1.23.1 for all crates. This is to address [RUSTSEC-2023-0001](https://rustsec.org/advisories/RUSTSEC-2023-0001)"
references = ["smithy-rs#2474"]
+0 −35
Original line number Diff line number Diff line
@@ -159,7 +159,6 @@ mod loader {
    use aws_smithy_types::timeout::TimeoutConfig;
    use aws_types::app_name::AppName;
    use aws_types::docs_for;
    use aws_types::endpoint::ResolveAwsEndpoint;
    use aws_types::SdkConfig;

    use crate::connector::default_connector;
@@ -181,7 +180,6 @@ mod loader {
        app_name: Option<AppName>,
        credentials_cache: Option<CredentialsCache>,
        credentials_provider: Option<SharedCredentialsProvider>,
        endpoint_resolver: Option<Arc<dyn ResolveAwsEndpoint>>,
        endpoint_url: Option<String>,
        region: Option<Box<dyn ProvideRegion>>,
        retry_config: Option<RetryConfig>,
@@ -345,36 +343,6 @@ mod loader {
            self
        }

        /// Override the endpoint resolver used for **all** AWS Services
        ///
        /// This method is deprecated. Use [`Self::endpoint_url`] instead.
        ///
        /// This method will override the endpoint resolver used for **all** AWS services. This mainly
        /// exists to set a static endpoint for tools like `LocalStack`. For live traffic, AWS services
        /// require the service-specific endpoint resolver they load by default.
        ///
        /// # Examples
        ///
        /// Use a static endpoint for all services
        /// ```no_run
        /// # async fn create_config() -> Result<(), aws_smithy_http::endpoint::error::InvalidEndpointError> {
        /// use aws_config::endpoint::Endpoint;
        ///
        /// let sdk_config = aws_config::from_env()
        ///     .endpoint_resolver(Endpoint::immutable("http://localhost:1234")?)
        ///     .load()
        ///     .await;
        /// # Ok(())
        /// # }
        #[deprecated(note = "use `.endpoint_url(...)` instead")]
        pub fn endpoint_resolver(
            mut self,
            endpoint_resolver: impl ResolveAwsEndpoint + 'static,
        ) -> Self {
            self.endpoint_resolver = Some(Arc::new(endpoint_resolver));
            self
        }

        /// Provides the ability to programmatically override the profile files that get loaded by the SDK.
        ///
        /// The [`Default`] for `ProfileFiles` includes the default SDK config and credential files located in
@@ -600,8 +568,6 @@ mod loader {
                SharedCredentialsProvider::new(builder.build().await)
            };

            let endpoint_resolver = self.endpoint_resolver;

            let mut builder = SdkConfig::builder()
                .region(region)
                .retry_config(retry_config)
@@ -610,7 +576,6 @@ mod loader {
                .credentials_provider(credentials_provider)
                .http_connector(http_connector);

            builder.set_endpoint_resolver(endpoint_resolver);
            builder.set_app_name(app_name);
            builder.set_sleep_impl(sleep_impl);
            builder.set_endpoint_url(self.endpoint_url);
+1 −68
Original line number Diff line number Diff line
@@ -5,84 +5,17 @@

#![allow(clippy::derive_partial_eq_without_eq)]

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::sync::Arc;

use aws_smithy_http::endpoint::error::ResolveEndpointError;
use aws_smithy_http::endpoint::ResolveEndpoint;
use aws_smithy_http::middleware::MapRequest;
use aws_smithy_http::operation::Request;
use aws_smithy_types::endpoint::Endpoint as SmithyEndpoint;
use aws_smithy_types::Document;

pub use aws_types::endpoint::{AwsEndpoint, BoxError, CredentialScope, ResolveAwsEndpoint};
use aws_types::region::{Region, SigningRegion};
use aws_types::SigningService;

#[doc(hidden)]
pub struct Params {
    region: Option<Region>,
}

impl Params {
    pub fn new(region: Option<Region>) -> Self {
        Self { region }
    }
}

#[doc(hidden)]
pub struct EndpointShim(Arc<dyn ResolveAwsEndpoint>);
impl EndpointShim {
    pub fn from_resolver(resolver: impl ResolveAwsEndpoint + 'static) -> Self {
        Self(Arc::new(resolver))
    }

    pub fn from_arc(arc: Arc<dyn ResolveAwsEndpoint>) -> Self {
        Self(arc)
    }
}

impl<T> ResolveEndpoint<T> for EndpointShim
where
    T: Clone + Into<Params>,
{
    fn resolve_endpoint(&self, params: &T) -> Result<SmithyEndpoint, ResolveEndpointError> {
        let params: Params = params.clone().into();
        let aws_endpoint = self
            .0
            .resolve_endpoint(
                params
                    .region
                    .as_ref()
                    .ok_or_else(|| ResolveEndpointError::message("no region in params"))?,
            )
            .map_err(|err| {
                ResolveEndpointError::message("failure resolving endpoint").with_source(Some(err))
            })?;
        let uri = aws_endpoint.endpoint().uri();
        let mut auth_scheme =
            HashMap::from([("name".to_string(), Document::String("sigv4".into()))]);
        if let Some(region) = aws_endpoint.credential_scope().region() {
            auth_scheme.insert(
                "signingRegion".to_string(),
                region.as_ref().to_string().into(),
            );
        }
        if let Some(service) = aws_endpoint.credential_scope().service() {
            auth_scheme.insert(
                "signingName".to_string(),
                service.as_ref().to_string().into(),
            );
        }
        Ok(SmithyEndpoint::builder()
            .url(uri.to_string())
            .property("authSchemes", vec![Document::Object(auth_scheme)])
            .build())
    }
}

/// Middleware Stage to add authentication information from a Smithy endpoint into the property bag
///
/// AwsAuthStage implements [`MapRequest`](MapRequest). It will:
@@ -95,7 +28,7 @@ pub struct AwsAuthStage;
#[derive(Debug)]
enum AwsAuthStageErrorKind {
    NoEndpointResolver,
    EndpointResolutionError(BoxError),
    EndpointResolutionError(Box<dyn Error + Send + Sync>),
}

#[derive(Debug)]
+0 −192
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

//! AWS SDK endpoint support.
#![allow(deprecated)]

use crate::region::{Region, SigningRegion};
use crate::SigningService;
use aws_smithy_http::endpoint::error::InvalidEndpointError;
use aws_smithy_http::endpoint::{Endpoint, EndpointPrefix};
use std::error::Error;
use std::fmt::Debug;

/// Endpoint to connect to an AWS Service
///
/// An `AwsEndpoint` captures all necessary information needed to connect to an AWS service, including:
/// - The URI of the endpoint (needed to actually send the request)
/// - The name of the service (needed downstream for signing)
/// - The signing region (which may differ from the actual region)
#[derive(Clone, Debug)]
pub struct AwsEndpoint {
    endpoint: Endpoint,
    credential_scope: CredentialScope,
}

impl AwsEndpoint {
    /// Constructs a new AWS endpoint.
    pub fn new(endpoint: Endpoint, credential_scope: CredentialScope) -> AwsEndpoint {
        AwsEndpoint {
            endpoint,
            credential_scope,
        }
    }

    /// Returns the underlying endpoint.
    pub fn endpoint(&self) -> &Endpoint {
        &self.endpoint
    }

    /// Returns the credential scope.
    pub fn credential_scope(&self) -> &CredentialScope {
        &self.credential_scope
    }

    /// Sets the endpoint on a given `uri` based on this endpoint
    pub fn set_endpoint(
        &self,
        uri: &mut http::Uri,
        endpoint_prefix: Option<&EndpointPrefix>,
    ) -> Result<(), InvalidEndpointError> {
        self.endpoint.set_endpoint(uri, endpoint_prefix)
    }
}

/// A boxed error.
pub type BoxError = Box<dyn Error + Send + Sync + 'static>;

/// Resolve the AWS Endpoint for a given region
///
/// To provide a static endpoint, [`Endpoint`](aws_smithy_http::endpoint::Endpoint) implements this trait.
/// Example usage:
/// ```rust
/// # mod dynamodb {
/// # use aws_types::endpoint::ResolveAwsEndpoint;
/// # pub struct ConfigBuilder;
/// # impl ConfigBuilder {
/// #     pub fn endpoint(&mut self, resolver: impl ResolveAwsEndpoint + 'static) {
/// #         // ...
/// #     }
/// # }
/// # pub struct Config;
/// # impl Config {
/// #     pub fn builder() -> ConfigBuilder {
/// #         ConfigBuilder
/// #     }
/// # }
/// # }
/// # fn wrapper() -> Result<(), aws_smithy_http::endpoint::error::InvalidEndpointError> {
/// use aws_smithy_http::endpoint::Endpoint;
/// let config = dynamodb::Config::builder()
///     .endpoint(Endpoint::immutable("http://localhost:8080")?);
/// #     Ok(())
/// # }
/// ```
/// Each AWS service generates their own implementation of `ResolveAwsEndpoint`.
pub trait ResolveAwsEndpoint: Send + Sync + Debug {
    /// Resolves the AWS endpoint for a given region.
    fn resolve_endpoint(&self, region: &Region) -> Result<AwsEndpoint, BoxError>;
}

/// The scope for AWS credentials.
#[derive(Clone, Default, Debug)]
pub struct CredentialScope {
    region: Option<SigningRegion>,
    service: Option<SigningService>,
}

impl CredentialScope {
    /// Creates a builder for [`CredentialScope`].
    pub fn builder() -> credential_scope::Builder {
        credential_scope::Builder::default()
    }
}

/// Types associated with [`CredentialScope`].
pub mod credential_scope {
    use crate::endpoint::CredentialScope;
    use crate::region::SigningRegion;
    use crate::SigningService;

    /// A builder for [`CredentialScope`].
    #[derive(Debug, Default)]
    pub struct Builder {
        region: Option<SigningRegion>,
        service: Option<SigningService>,
    }

    impl Builder {
        /// Sets the signing region.
        pub fn region(mut self, region: impl Into<SigningRegion>) -> Self {
            self.region = Some(region.into());
            self
        }

        /// Sets the signing service.
        pub fn service(mut self, service: impl Into<SigningService>) -> Self {
            self.service = Some(service.into());
            self
        }

        /// Constructs a [`CredentialScope`] from the builder.
        pub fn build(self) -> CredentialScope {
            CredentialScope {
                region: self.region,
                service: self.service,
            }
        }
    }
}

impl CredentialScope {
    /// Returns the signing region.
    pub fn region(&self) -> Option<&SigningRegion> {
        self.region.as_ref()
    }

    /// Returns the signing service.
    pub fn service(&self) -> Option<&SigningService> {
        self.service.as_ref()
    }

    /// Uses the values from `other` to fill in unconfigured parameters on this
    /// credential scope object.
    pub fn merge(&self, other: &CredentialScope) -> CredentialScope {
        CredentialScope {
            region: self.region.clone().or_else(|| other.region.clone()),
            service: self.service.clone().or_else(|| other.service.clone()),
        }
    }
}

/// An `Endpoint` can be its own resolver to support static endpoints
impl ResolveAwsEndpoint for Endpoint {
    fn resolve_endpoint(&self, _region: &Region) -> Result<AwsEndpoint, BoxError> {
        Ok(AwsEndpoint {
            endpoint: self.clone(),
            credential_scope: Default::default(),
        })
    }
}

#[cfg(test)]
mod test {
    use crate::endpoint::CredentialScope;
    use crate::region::SigningRegion;
    use crate::SigningService;

    #[test]
    fn create_credentials_scope_from_strs() {
        let scope = CredentialScope::builder()
            .service("s3")
            .region("us-east-1")
            .build();
        assert_eq!(scope.service(), Some(&SigningService::from_static("s3")));
        assert_eq!(
            scope.region(),
            Some(&SigningRegion::from_static("us-east-1"))
        );
    }
}
+0 −3
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

pub mod app_name;
pub mod build_metadata;
#[deprecated(since = "0.9.0", note = "renamed to sdk_config")]
pub mod config;
pub mod endpoint;
#[doc(hidden)]
pub mod os_shim_internal;
pub mod region;
Loading