Пример #1
0
        public static void ProcessRequestHandlers(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.Request;
            var config  = executionContext.RequestContext.ClientConfig;

            string accountId;

            request.Headers.TryGetValue(HeaderKeys.XAmzAccountId, out accountId);

            if (accountId != null)
            {
                if (!IsValidAccountId(accountId))
                {
                    throw new AmazonClientException("AccountId can only contain alphanumeric characters and dashes and must be between 1 and 63 characters long.");
                }

                request.Headers.Remove(HeaderKeys.XAmzAccountId);

                var ub = new UriBuilder(EndpointResolver.DetermineEndpoint(config, request));

                // Add account id to host
                ub.Host          = string.Concat(accountId, ".", ub.Host);
                request.Endpoint = ub.Uri;
            }
        }
Пример #2
0
        ///
        /// If the STS regional endpoints environment variable is set to
        /// regional, then the endpoint created by DetermineEndpoint
        /// should always be specific to the customer's region
        /// If it is set to legacy, it should be the default sts
        /// endpoint for legacy global regions
        ///
        public void TestDetermineEndpointStsFlag(StsRegionalEndpointsValue stsRegionalFlag, string region, string expected)
        {
            var endpointResolver = new EndpointResolver();
            var executionContext = CreateExecutionContextSTS(SetupSTSConfig(RegionEndpoint.GetBySystemName(region), stsRegionalFlag));
            Uri endpoint         = endpointResolver.DetermineEndpoint(executionContext.RequestContext);

            Assert.AreEqual(expected, endpoint.ToString());
        }
Пример #3
0
        public void TestSuccessfulCall()
        {
            var endpointResolver = new EndpointResolver();
            var executionContext = CreateExecutionContext(SetupConfig());
            Uri endpoint         = endpointResolver.DetermineEndpoint(executionContext.RequestContext);

            Assert.AreEqual(@"https://testprefix.test123-s3.amazonaws.com/", endpoint.ToString());
        }
        public static void ProcessRequestHandlers(IExecutionContext executionContext)
        {
            //IL_006c: Unknown result type (might be due to invalid IL or missing references)
            //IL_013c: Unknown result type (might be due to invalid IL or missing references)
            IRequest      request      = executionContext.get_RequestContext().get_Request();
            IClientConfig clientConfig = executionContext.get_RequestContext().get_ClientConfig();

            if (request.get_Headers().TryGetValue("x-amz-server-side-encryption", out string value) && string.Equals(value, ServerSideEncryptionMethod.AWSKMS.get_Value(), StringComparison.Ordinal))
            {
                request.set_UseSigV4(true);
            }
            string bucketName = GetBucketName(request.get_ResourcePath());

            if (!string.IsNullOrEmpty(bucketName))
            {
                AmazonS3Config amazonS3Config = clientConfig as AmazonS3Config;
                if (amazonS3Config == null)
                {
                    throw new AmazonClientException("Current config object is not of type AmazonS3Config");
                }
                bool       flag       = IsDnsCompatibleBucketName(bucketName);
                UriBuilder uriBuilder = new UriBuilder(EndpointResolver.DetermineEndpoint(amazonS3Config, request));
                bool       flag2      = string.Equals(uriBuilder.Scheme, "http", StringComparison.OrdinalIgnoreCase);
                if (!amazonS3Config.ForcePathStyle && flag && (flag2 || bucketName.IndexOf('.') < 0))
                {
                    uriBuilder.Host = bucketName + "." + uriBuilder.Host;
                    request.set_Endpoint(uriBuilder.Uri);
                    string text  = request.get_ResourcePath();
                    string text2 = "/" + bucketName;
                    if (text.IndexOf(text2, StringComparison.Ordinal) == 0)
                    {
                        text = text.Substring(text2.Length);
                    }
                    request.set_ResourcePath(text);
                    request.set_CanonicalResourcePrefix(text2);
                }
                if (amazonS3Config.UseAccelerateEndpoint)
                {
                    if (!flag || BucketNameContainsPeriod(bucketName))
                    {
                        throw new AmazonClientException("S3 accelerate is enabled for this request but the bucket name is not accelerate compatible. The bucket name must be DNS compatible (http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html) and must not contain any period (.) characters to be accelerate compatible.");
                    }
                    AmazonWebServiceRequest originalRequest = request.get_OriginalRequest();
                    if (!UnsupportedAccelerateRequestTypes.Contains(((object)originalRequest).GetType()))
                    {
                        request.set_Endpoint(GetAccelerateEndpoint(bucketName, amazonS3Config));
                        if (request.get_UseSigV4() && amazonS3Config.get_RegionEndpoint() != null)
                        {
                            request.set_AlternateEndpoint(amazonS3Config.get_RegionEndpoint());
                        }
                    }
                }
                if (flag2)
                {
                    ValidateHttpsOnlyHeaders(request);
                }
            }
        }
Пример #5
0
        public static void ProcessRequestHandlers(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.Request;
            var config = executionContext.RequestContext.ClientConfig;

            // If the marshalled request has the SSE header and it is set to KMS,
            // force SigV4 for this request.
            // Current operations that may set this header:
            //  CopyObject, CopyPart, InitiateMultipart, PutObject
            string sseHeaderValue;
            if (request.Headers.TryGetValue(HeaderKeys.XAmzServerSideEncryptionHeader, out sseHeaderValue) &&
                string.Equals(sseHeaderValue, ServerSideEncryptionMethod.AWSKMS.Value, StringComparison.Ordinal))
            {
                    request.UseSigV4 = true;
            }

            var bucketName = GetBucketName(request.ResourcePath);
            if (string.IsNullOrEmpty(bucketName))
                return;

            var s3Config = config as AmazonS3Config;

            // If path style is not forced and the bucket name is DNS
            // compatible modify the endpoint to use virtual host style
            // addressing
            var bucketIsDnsCompatible = IsDnsCompatibleBucketName(bucketName);
            var ub = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));
            var isHttp = string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase);

            if (!s3Config.ForcePathStyle && bucketIsDnsCompatible)
            {
                // If using HTTPS, bucketName cannot contain a period
                if (isHttp || bucketName.IndexOf('.') < 0)
                {
                    // Add bucket to host
                    ub.Host = string.Concat(bucketName, ".", ub.Host);
                    request.Endpoint = ub.Uri;

                    // Remove bucket from resource path but retain in canonical resource
                    // prefix, so it gets included when we sign the request later
                    var resourcePath = request.ResourcePath;
                    var canonicalBucketName = string.Concat("/", bucketName);
                    if (resourcePath.IndexOf(canonicalBucketName, StringComparison.Ordinal) == 0)
                        resourcePath = resourcePath.Substring(canonicalBucketName.Length);
                    request.ResourcePath = resourcePath;

                    request.CanonicalResourcePrefix = canonicalBucketName;
                }
            }

            // Some parameters should not be sent over HTTP, just HTTPS
            if (isHttp)
            {
                ValidateHttpsOnlyHeaders(request);
            }
        }
Пример #6
0
        public void TestDisableHostPrefixInjection()
        {
            var config = SetupConfig();

            config.DisableHostPrefixInjection = true;

            var endpointResolver = new EndpointResolver();
            var executionContext = CreateExecutionContext(config);
            Uri endpoint         = endpointResolver.DetermineEndpoint(executionContext.RequestContext);

            Assert.AreEqual(@"https://s3.amazonaws.com/", endpoint.ToString());
        }
Пример #7
0
        public void TestSignerScope(IClientConfig config, string expectedAuthRegion, string expectedAuthService, string expectedEndpoint)
        {
            var signer  = new AWS4Signer();
            var mock    = new Moq.Mock <IRequest>().SetupAllProperties();
            var request = mock.Object;

            mock.SetupGet(x => x.Headers).Returns(new Dictionary <string, string>());
            request.Endpoint = EndpointResolver.DetermineEndpoint(config, request);

            var result = signer.SignRequest(request, config, null, "accessKey", "secretKey");

            var scopePieces = result.Scope.Split('/'); // expected to be date/region/service/aws4_request

            Assert.AreEqual(expectedAuthRegion, scopePieces[1]);
            Assert.AreEqual(expectedAuthService, scopePieces[2]);
            Assert.AreEqual(expectedEndpoint, request.Endpoint.Host);
        }
Пример #8
0
        public void ProcessRequestHandlers(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.Request;
            var config  = executionContext.RequestContext.ClientConfig;

            var bucketName = GetBucketName(request.ResourcePath);

            if (string.IsNullOrEmpty(bucketName))
            {
                return;
            }

            var s3Config = config as AmazonS3Config;

            // If path style is not forced and the bucket name is DNS
            // compatible modify the endpoint to use virtual host style
            // addressing
            var bucketIsDnsCompatible = IsDnsCompatibleBucketName(bucketName);
            var ub = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));

            if (!s3Config.ForcePathStyle && bucketIsDnsCompatible)
            {
                // If using HTTPS, bucketName cannot contain a period
                if (string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase) || bucketName.IndexOf('.') < 0)
                {
                    // Add bucket to host
                    ub.Host          = string.Concat(bucketName, ".", ub.Host);
                    request.Endpoint = ub.Uri;

                    // Remove bucket from resource path but retain in canonical resource
                    // prefix, so it gets included when we sign the request later
                    var resourcePath        = request.ResourcePath;
                    var canonicalBucketName = string.Concat("/", bucketName);
                    if (resourcePath.IndexOf(canonicalBucketName, StringComparison.Ordinal) == 0)
                    {
                        resourcePath = resourcePath.Substring(canonicalBucketName.Length);
                    }
                    request.ResourcePath = resourcePath;

                    request.CanonicalResourcePrefix = canonicalBucketName;
                }
            }
        }
Пример #9
0
        /// <summary>
        /// Create a signed URL allowing access to a resource that would
        /// usually require authentication.
        /// </summary>
        /// <remarks>
        /// <para>
        /// When using query string authentication you create a query,
        /// specify an expiration time for the query, sign it with your
        /// signature, place the data in an HTTP request, and distribute
        /// the request to a user or embed the request in a web page.
        /// </para>
        /// <para>
        /// A PreSigned URL can be generated for GET, PUT, DELETE and HEAD
        /// operations on your bucketName, keys, and versions.
        /// </para>
        /// </remarks>
        /// <param name="request">The GetPreSignedUrlRequest that defines the
        /// parameters of the operation.</param>
        /// <param name="useSigV2Fallback">determines if signing will fall back to SigV2 if the
        /// signing region is us-east-1
        /// <returns>A string that is the signed http request.</returns>
        /// <exception cref="T:System.ArgumentException" />
        /// <exception cref="T:System.ArgumentNullException" />
        internal string GetPreSignedURLInternal(GetPreSignedUrlRequest request, bool useSigV2Fallback = true)
        {
            if (Credentials == null)
            {
                throw new AmazonS3Exception("Credentials must be specified, cannot call method anonymously");
            }

            if (request == null)
            {
                throw new ArgumentNullException("request", "The PreSignedUrlRequest specified is null!");
            }

            if (!request.IsSetExpires())
            {
                throw new InvalidOperationException("The Expires specified is null!");
            }

            var aws4Signing = AWSConfigsS3.UseSignatureVersion4;
            var region      = AWS4Signer.DetermineSigningRegion(Config, "s3", alternateEndpoint: null, request: null);

            if (aws4Signing && string.IsNullOrEmpty(region))
            {
                throw new InvalidOperationException("To use AWS4 signing, a region must be specified in the client configuration using the AuthenticationRegion or Region properties, or be determinable from the service URL.");
            }

            RegionEndpoint endpoint = RegionEndpoint.GetBySystemName(region);

            if (endpoint.GetEndpointForService("s3").SignatureVersionOverride == "4" || endpoint.GetEndpointForService("s3").SignatureVersionOverride == null)
            {
                aws4Signing = true;
            }

            var fallbackToSigV2 = useSigV2Fallback && !AWSConfigsS3.UseSigV4SetExplicitly;

            if (endpoint == RegionEndpoint.USEast1 && fallbackToSigV2)
            {
                aws4Signing = false;
            }

            // If the expiration is longer than SigV4 will allow then automatically use SigV2 instead.
            // But only if the region we're signing for allows SigV2.
            if (aws4Signing)
            {
                var secondsUntilExpiration = GetSecondsUntilExpiration(request, aws4Signing);

                if (secondsUntilExpiration > AWS4PreSignedUrlSigner.MaxAWS4PreSignedUrlExpiry &&
                    endpoint.GetEndpointForService("s3").SignatureVersionOverride == "2")
                {
                    aws4Signing = false;
                }
            }

            var immutableCredentials = Credentials.GetCredentials();
            var irequest             = Marshall(request, immutableCredentials.AccessKey, immutableCredentials.Token, aws4Signing);

            irequest.Endpoint = EndpointResolver.DetermineEndpoint(this.Config, irequest);

            var context = new Amazon.Runtime.Internal.ExecutionContext(new Amazon.Runtime.Internal.RequestContext(true)
            {
                Request = irequest, ClientConfig = this.Config
            }, null);

            AmazonS3PostMarshallHandler.ProcessRequestHandlers(context);

            var metrics = new RequestMetrics();

            string authorization;

            if (aws4Signing)
            {
                var aws4Signer    = new AWS4PreSignedUrlSigner();
                var signingResult = aws4Signer.SignRequest(irequest,
                                                           this.Config,
                                                           metrics,
                                                           immutableCredentials.AccessKey,
                                                           immutableCredentials.SecretKey);
                authorization = "&" + signingResult.ForQueryParameters;
            }
            else
            {
                S3Signer.SignRequest(irequest, metrics, immutableCredentials.AccessKey, immutableCredentials.SecretKey);
                authorization = irequest.Headers[HeaderKeys.AuthorizationHeader];
                authorization = authorization.Substring(authorization.IndexOf(":", StringComparison.Ordinal) + 1);
                authorization = "&Signature=" + AmazonS3Util.UrlEncode(authorization, false);
            }

            Uri    url    = AmazonServiceClient.ComposeUrl(irequest);
            string result = url.AbsoluteUri + authorization;

            Protocol protocol = DetermineProtocol();

            if (request.Protocol != protocol)
            {
                switch (protocol)
                {
                case Protocol.HTTP:
                    result = result.Replace("http://", "https://");
                    break;

                case Protocol.HTTPS:
                    result = result.Replace("https://", "http://");
                    break;
                }
            }
            return(result);
        }
Пример #10
0
        public static void ProcessRequestHandlers(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.Request;
            var config  = executionContext.RequestContext.ClientConfig;

            // If the marshalled request has the SSE header and it is set to KMS,
            // force SigV4 for this request.
            // Current operations that may set this header:
            //  CopyObject, CopyPart, InitiateMultipart, PutObject
            string sseHeaderValue;

            if (request.Headers.TryGetValue(HeaderKeys.XAmzServerSideEncryptionHeader, out sseHeaderValue) &&
                string.Equals(sseHeaderValue, ServerSideEncryptionMethod.AWSKMS.Value, StringComparison.Ordinal))
            {
                request.UseSigV4 = true;
            }
            var bucketResourcePathToken = GetBucketName(request.ResourcePath);

            if (string.IsNullOrEmpty(bucketResourcePathToken))
            {
                return;
            }

            var s3Config = config as AmazonS3Config;

            if (s3Config == null)
            {
                throw new AmazonClientException("Current config object is not of type AmazonS3Config");
            }

            //If a ServiceURL is set the config ClientRegion should be null. Under this case
            //the region needs to be determined from the ServiceURL.
            var regionEndpoint = config.RegionEndpoint;

            if (regionEndpoint == null && !string.IsNullOrEmpty(config.ServiceURL))
            {
                var regionName = AWSSDKUtils.DetermineRegion(config.ServiceURL);
                regionEndpoint = RegionEndpoint.GetBySystemName(regionName);
            }

            bool isHttp;
            bool removeBucketFromResourcePath = false;

            if (Arn.IsArn(bucketResourcePathToken))
            {
                string accessPoint;
                Arn    s3Arn = Arn.Parse(bucketResourcePathToken);
                if (s3Arn.IsService("s3") && s3Arn.TryParseAccessPoint(out accessPoint))
                {
                    ValidateS3AccessPoint(s3Arn, s3Config, regionEndpoint);
                    UriBuilder ub;
                    if (!string.IsNullOrEmpty(config.ServiceURL))
                    {
                        ub      = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));
                        isHttp  = string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase);
                        ub.Host = string.Concat($"{accessPoint}-{s3Arn.AccountId}.", ub.Host);
                    }
                    else
                    {
                        isHttp = config.UseHttp;
                        var scheme = isHttp ? "http" : "https";
                        ub = new UriBuilder($"{scheme}://{accessPoint}-{s3Arn.AccountId}.s3-accesspoint{(config.UseDualstackEndpoint ? ".dualstack" : "")}.{s3Arn.Region}.{config.RegionEndpoint.PartitionDnsSuffix}");
                    }

                    request.Endpoint = ub.Uri;
                }
                else if (s3Arn.IsService(s3ObjectLambdaServiceName) && s3Arn.TryParseAccessPoint(out accessPoint))
                {
                    ValidateS3ObjectLambdaAccessPoint(s3Arn, s3Config, regionEndpoint);
                    UriBuilder ub;

                    if (!string.IsNullOrEmpty(config.ServiceURL))
                    {
                        ub      = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));
                        isHttp  = string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase);
                        ub.Host = string.Concat($"{accessPoint}-{s3Arn.AccountId}.", ub.Host);
                    }
                    else
                    {
                        isHttp = s3Config.UseHttp;
                        var scheme = isHttp ? "http" : "https";
                        ub = new UriBuilder($"{scheme}://{accessPoint}-{s3Arn.AccountId}.{s3ObjectLambdaServiceName}.{s3Arn.Region}.{config.RegionEndpoint.PartitionDnsSuffix}");
                    }

                    request.Endpoint = ub.Uri;
                }
                else if (s3Arn.IsOutpostArn())
                {
                    var outpost = s3Arn.ParseOutpost();
                    ValidateOutpostAccessPoint(s3Arn, s3Config, regionEndpoint);
                    var region = s3Config.UseArnRegion ? s3Arn.Region : regionEndpoint.SystemName;
                    bucketResourcePathToken = outpost.FullAccessPointName;

                    UriBuilder ub;
                    if (!string.IsNullOrEmpty(config.ServiceURL))
                    {
                        ub      = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));
                        isHttp  = string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase);
                        ub.Host = string.Concat($"{outpost.AccessPointName}-{s3Arn.AccountId}.{outpost.OutpostId}.", ub.Host);
                    }
                    else
                    {
                        isHttp = config.UseHttp;
                        var scheme = isHttp ? "http" : "https";
                        ub = new UriBuilder($"{scheme}://{outpost.AccessPointName}-{s3Arn.AccountId}.{outpost.OutpostId}.s3-outposts.{region}.{config.RegionEndpoint.PartitionDnsSuffix}");
                    }

                    request.Endpoint = ub.Uri;
                }
                else
                {
                    throw new AmazonClientException("Invalid ARN specified for bucket name. Only access point ARNs are allowed for the value of bucket name.");
                }
                request.OverrideSigningServiceName = s3Arn.Service;
                // The access point arn can be using a region different from the configured region for the service client.
                // If so be sure to set the authentication region so the signer will use the correct region.
                request.AuthenticationRegion = s3Arn.Region;
                request.UseSigV4             = true;
                removeBucketFromResourcePath = true;
            }
            else
            {
                // If path style is not forced and the bucket name is DNS
                // compatible modify the endpoint to use virtual host style
                // addressing
                var bucketIsDnsCompatible = IsDnsCompatibleBucketName(bucketResourcePathToken);
                var ub = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));
                isHttp = string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase);

                if (!s3Config.ForcePathStyle && bucketIsDnsCompatible)
                {
                    // If using HTTPS, bucketName cannot contain a period
                    if (isHttp || bucketResourcePathToken.IndexOf('.') < 0)
                    {
                        // Add bucket to host
                        ub.Host                      = string.Concat(bucketResourcePathToken, ".", ub.Host);
                        request.Endpoint             = ub.Uri;
                        removeBucketFromResourcePath = true;
                    }
                }

                if (request.OriginalRequest.GetType() == typeof(WriteGetObjectResponseRequest))
                {
                    if (!string.IsNullOrEmpty(config.ServiceURL))
                    {
                        ub     = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));
                        isHttp = string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase);
                    }
                    else
                    {
                        isHttp = s3Config.UseHttp;
                        var scheme = isHttp ? "http" : "https";
                        var region = regionEndpoint.SystemName == "us-east-1-regional" ? "us-east-1" : regionEndpoint.SystemName;
                        ub = new UriBuilder($"{scheme}://{request.Headers["x-amz-request-route"]}.{s3ObjectLambdaServiceName}.{region}.{config.RegionEndpoint.PartitionDnsSuffix}");
                    }

                    request.Endpoint = ub.Uri;
                    request.OverrideSigningServiceName = s3ObjectLambdaServiceName;
                    request.UseSigV4 = true;
                }

                if (s3Config.UseAccelerateEndpoint)
                {
                    // Validate if bucket name is accelerate compatible and enable acceleration by using
                    // Accelerate endpoint for this request

                    if (!bucketIsDnsCompatible || BucketNameContainsPeriod(bucketResourcePathToken))
                    {
                        throw new AmazonClientException(
                                  @"S3 accelerate is enabled for this request but the bucket name is not accelerate compatible." +
                                  " The bucket name must be DNS compatible (http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html)" +
                                  " and must not contain any period (.) characters to be accelerate compatible.");
                    }

                    var  originalRequest        = request.OriginalRequest;
                    bool accelerateSupportedApi = !UnsupportedAccelerateRequestTypes.Contains(originalRequest.GetType());

                    // Skip requests which are not supported
                    if (accelerateSupportedApi)
                    {
                        request.Endpoint = GetAccelerateEndpoint(bucketResourcePathToken, s3Config);

                        if (request.UseSigV4 && s3Config.RegionEndpoint != null)
                        {
                            request.AlternateEndpoint = s3Config.RegionEndpoint;
                        }
                    }
                }
            }

            if (removeBucketFromResourcePath)
            {
                // Remove bucket from resource path but retain in canonical resource
                // prefix, so it gets included when we sign the request later
                var resourcePath        = request.ResourcePath;
                var canonicalBucketName = string.Concat("/", bucketResourcePathToken);
                if (resourcePath.IndexOf(canonicalBucketName, StringComparison.Ordinal) == 0)
                {
                    resourcePath = resourcePath.Substring(canonicalBucketName.Length);
                }

                request.ResourcePath            = resourcePath;
                request.CanonicalResourcePrefix = canonicalBucketName;
            }

            // Some parameters should not be sent over HTTP, just HTTPS
            if (isHttp)
            {
                ValidateHttpsOnlyHeaders(request);
            }
        }
Пример #11
0
        public static void ProcessRequestHandlers(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.Request;
            var config  = executionContext.RequestContext.ClientConfig;

            // If the marshalled request has the SSE header and it is set to KMS,
            // force SigV4 for this request.
            // Current operations that may set this header:
            //  CopyObject, CopyPart, InitiateMultipart, PutObject
            string sseHeaderValue;

            if (request.Headers.TryGetValue(HeaderKeys.XAmzServerSideEncryptionHeader, out sseHeaderValue) &&
                string.Equals(sseHeaderValue, ServerSideEncryptionMethod.AWSKMS.Value, StringComparison.Ordinal))
            {
                request.UseSigV4 = true;
            }

            var bucketName = GetBucketName(request.ResourcePath);

            if (string.IsNullOrEmpty(bucketName))
            {
                return;
            }

            var s3Config = config as AmazonS3Config;

            if (s3Config == null)
            {
                throw new AmazonClientException("Current config object is not of type AmazonS3Config");
            }

            // If path style is not forced and the bucket name is DNS
            // compatible modify the endpoint to use virtual host style
            // addressing
            var bucketIsDnsCompatible = IsDnsCompatibleBucketName(bucketName);
            var ub     = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));
            var isHttp = string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase);

            if (!s3Config.ForcePathStyle && bucketIsDnsCompatible)
            {
                // If using HTTPS, bucketName cannot contain a period
                if (isHttp || bucketName.IndexOf('.') < 0)
                {
                    // Add bucket to host
                    ub.Host          = string.Concat(bucketName, ".", ub.Host);
                    request.Endpoint = ub.Uri;

                    // Remove bucket from resource path but retain in canonical resource
                    // prefix, so it gets included when we sign the request later
                    var resourcePath        = request.ResourcePath;
                    var canonicalBucketName = string.Concat("/", bucketName);
                    if (resourcePath.IndexOf(canonicalBucketName, StringComparison.Ordinal) == 0)
                    {
                        resourcePath = resourcePath.Substring(canonicalBucketName.Length);
                    }
                    request.ResourcePath = resourcePath;

                    request.CanonicalResourcePrefix = canonicalBucketName;
                }
            }

            if (s3Config.UseAccelerateEndpoint)
            {
                // Validate if bucket name is accelerate compatible and enable acceleration by using
                // Accelerate endpoint for this request

                if (!bucketIsDnsCompatible || BucketNameContainsPeriod(bucketName))
                {
                    throw new AmazonClientException(
                              @"S3 accelerate is enabled for this request but the bucket name is not accelerate compatible." +
                              " The bucket name must be DNS compatible (http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html)" +
                              " and must not contain any period (.) characters to be accelerate compatible.");
                }

                var  originalRequest        = request.OriginalRequest;
                bool accelerateSupportedApi = !UnsupportedAccelerateRequestTypes.Contains(originalRequest.GetType());

                // Skip requests which are not supported
                if (accelerateSupportedApi)
                {
                    request.Endpoint = GetAccelerateEndpoint(bucketName, s3Config);

                    if (request.UseSigV4 && s3Config.RegionEndpoint != null)
                    {
                        request.AlternateEndpoint = s3Config.RegionEndpoint;
                    }
                }
            }

            // Some parameters should not be sent over HTTP, just HTTPS
            if (isHttp)
            {
                ValidateHttpsOnlyHeaders(request);
            }
        }
Пример #12
0
        /// <summary>
        /// Create a signed URL allowing access to a resource that would
        /// usually require authentication.
        /// </summary>
        /// <remarks>
        /// <para>
        /// When using query string authentication you create a query,
        /// specify an expiration time for the query, sign it with your
        /// signature, place the data in an HTTP request, and distribute
        /// the request to a user or embed the request in a web page.
        /// </para>
        /// <para>
        /// A PreSigned URL can be generated for GET, PUT, DELETE and HEAD
        /// operations on your bucketName, keys, and versions.
        /// </para>
        /// </remarks>
        /// <param name="request">The GetPreSignedUrlRequest that defines the
        /// parameters of the operation.</param>
        /// <param name="useSigV2Fallback">determines if signing will fall back to SigV2 if the
        /// signing region is us-east-1</param>
        /// <returns>A string that is the signed http request.</returns>
        /// <exception cref="T:System.ArgumentException" />
        /// <exception cref="T:System.ArgumentNullException" />
        internal string GetPreSignedURLInternal(GetPreSignedUrlRequest request, bool useSigV2Fallback = true)
        {
            if (Credentials == null)
            {
                throw new AmazonS3Exception("Credentials must be specified, cannot call method anonymously");
            }

            if (request == null)
            {
                throw new ArgumentNullException("request", "The PreSignedUrlRequest specified is null!");
            }

            if (!request.IsSetExpires())
            {
                throw new InvalidOperationException("The Expires specified is null!");
            }

            var signatureVersionToUse = AWSConfigsS3.UseSignatureVersion4 ? SignatureVersion.SigV4 : SignatureVersion.SigV2;

            Arn    arn;
            string accessPoint;

            if (Arn.TryParse(request.BucketName, out arn) &&
                (arn.TryParseAccessPoint(out accessPoint) || arn.IsOutpostArn()))
            {
                signatureVersionToUse = SignatureVersion.SigV4;

                if (arn.IsMRAPArn())
                {
                    signatureVersionToUse = SignatureVersion.SigV4a;
                }
            }
            else
            {
                var region = AWS4Signer.DetermineSigningRegion(Config, "s3", alternateEndpoint: null, request: null);
                if (signatureVersionToUse == SignatureVersion.SigV4 && string.IsNullOrEmpty(region))
                {
                    throw new InvalidOperationException("To use AWS4 signing, a region must be specified in the client configuration using the AuthenticationRegion or Region properties, or be determinable from the service URL.");
                }

                RegionEndpoint endpoint = RegionEndpoint.GetBySystemName(region);
                var            s3SignatureVersionOverride = endpoint.GetEndpointForService("s3", Config.ToGetEndpointForServiceOptions()).SignatureVersionOverride;
                if (s3SignatureVersionOverride == "4" || s3SignatureVersionOverride == null)
                {
                    signatureVersionToUse = SignatureVersion.SigV4;
                }

                var fallbackToSigV2 = useSigV2Fallback && !AWSConfigsS3.UseSigV4SetExplicitly;
                if (endpoint?.SystemName == RegionEndpoint.USEast1.SystemName && fallbackToSigV2)
                {
                    signatureVersionToUse = SignatureVersion.SigV2;
                }

                // If the expiration is longer than SigV4 will allow then automatically use SigV2 instead.
                // But only if the region we're signing for allows SigV2.
                if (signatureVersionToUse == SignatureVersion.SigV4)
                {
                    var secondsUntilExpiration = GetSecondsUntilExpiration(this.Config, request, signatureVersionToUse);

                    if (secondsUntilExpiration > AWS4PreSignedUrlSigner.MaxAWS4PreSignedUrlExpiry &&
                        s3SignatureVersionOverride == "2")
                    {
                        signatureVersionToUse = SignatureVersion.SigV2;
                    }
                }
            }


            var immutableCredentials = Credentials.GetCredentials();
            var irequest             = Marshall(this.Config, request, immutableCredentials.AccessKey, immutableCredentials.Token, signatureVersionToUse);

            irequest.Endpoint = EndpointResolver.DetermineEndpoint(this.Config, irequest);

            var context = new Amazon.Runtime.Internal.ExecutionContext(new Amazon.Runtime.Internal.RequestContext(true, new NullSigner())
            {
                Request = irequest, ClientConfig = this.Config
            }, null);

            AmazonS3PostMarshallHandler.ProcessRequestHandlers(context);

            var    metrics = new RequestMetrics();
            string result;
            string authorization;

            switch (signatureVersionToUse)
            {
            case SignatureVersion.SigV4a:
                var aws4aSigner     = new AWS4aSignerCRTWrapper();
                var signingResult4a = aws4aSigner.Presign4a(irequest,
                                                            Config,
                                                            metrics,
                                                            immutableCredentials,
                                                            "s3",
                                                            arn.IsMRAPArn() ? "*" : "");
                result = signingResult4a.PresignedUri;
                break;

            case SignatureVersion.SigV4:
                var aws4Signer     = new AWS4PreSignedUrlSigner();
                var signingResult4 = aws4Signer.SignRequest(irequest,
                                                            Config,
                                                            metrics,
                                                            immutableCredentials.AccessKey,
                                                            immutableCredentials.SecretKey);
                authorization = "&" + signingResult4.ForQueryParameters;
                result        = ComposeUrl(irequest).AbsoluteUri + authorization;
                break;

            default:     // SigV2
                Amazon.S3.Internal.S3Signer.SignRequest(irequest, metrics, immutableCredentials.AccessKey, immutableCredentials.SecretKey);
                authorization = irequest.Headers[HeaderKeys.AuthorizationHeader];
                authorization = authorization.Substring(authorization.IndexOf(":", StringComparison.Ordinal) + 1);
                authorization = "&Signature=" + AmazonS3Util.UrlEncode(authorization, false);
                result        = ComposeUrl(irequest).AbsoluteUri + authorization;
                break;
            }

            Protocol protocol = DetermineProtocol();

            if (request.Protocol != protocol)
            {
                switch (protocol)
                {
                case Protocol.HTTP:
                    result = result.Replace("http://", "https://");
                    break;

                case Protocol.HTTPS:
                    result = result.Replace("https://", "http://");
                    break;
                }
            }
            return(result);
        }
        protected virtual void PreInvoke(IExecutionContext executionContext)
        {
            var originalRequest = executionContext.RequestContext.OriginalRequest;
            var request         = executionContext.RequestContext.Request;

            var copySnapshotRequest = originalRequest as CopySnapshotRequest;

            if (copySnapshotRequest != null)
            {
                request.AlternateEndpoint = RegionEndpoint.GetBySystemName(copySnapshotRequest.DestinationRegion);
                request.Endpoint          = EndpointResolver.DetermineEndpoint(executionContext.RequestContext.ClientConfig, request);

                return;
            }

            var requestSpotInstancesRequest = originalRequest as RequestSpotInstancesRequest;

            if (requestSpotInstancesRequest != null)
            {
                if (requestSpotInstancesRequest.LaunchSpecification != null)
                {
                    if (requestSpotInstancesRequest.LaunchSpecification.AllSecurityGroups != null)
                    {
                        int count = 1;
                        foreach (var group in requestSpotInstancesRequest.LaunchSpecification.AllSecurityGroups)
                        {
                            if (group != null && group.GroupId != null)
                            {
                                var key = "LaunchSpecification.SecurityGroupId." + count++;
                                request.Parameters[key] = group.GroupId;
                            }
                        }
                    }

                    if (requestSpotInstancesRequest.LaunchSpecification.SecurityGroups != null)
                    {
                        int count = 1;
                        foreach (var group in requestSpotInstancesRequest.LaunchSpecification.SecurityGroups)
                        {
                            var key = "LaunchSpecification.SecurityGroup." + count++;
                            request.Parameters[key] = group;
                        }
                    }
                }

                if (request.Parameters.ContainsKey("LaunchSpecification.Monitoring"))
                {
                    var val = request.Parameters["LaunchSpecification.Monitoring"];
                    request.Parameters.Remove("LaunchSpecification.Monitoring");
                    request.Parameters.Add("LaunchSpecification.Monitoring.Enabled", val);
                }

                var keysToRemove = new List <string>();
                foreach (var parameter in request.Parameters.Keys)
                {
                    if (parameter.StartsWith("LaunchSpecification.GroupSet.", StringComparison.Ordinal))
                    {
                        keysToRemove.Add(parameter);
                    }
                }
                foreach (var key in keysToRemove)
                {
                    request.Parameters.Remove(key);
                }
            }
        }
Пример #14
0
        public static void ProcessRequestHandlers(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.Request;
            var config  = executionContext.RequestContext.ClientConfig;

            // If the marshalled request has the SSE header and it is set to KMS,
            // force SigV4 for this request.
            // Current operations that may set this header:
            //  CopyObject, CopyPart, InitiateMultipart, PutObject
            string sseHeaderValue;

            if (request.Headers.TryGetValue(HeaderKeys.XAmzServerSideEncryptionHeader, out sseHeaderValue) &&
                string.Equals(sseHeaderValue, ServerSideEncryptionMethod.AWSKMS.Value, StringComparison.Ordinal))
            {
                request.UseSigV4 = true;
            }

            var bucketResourcePathToken = GetBucketName(request.ResourcePath);

            if (string.IsNullOrEmpty(bucketResourcePathToken))
            {
                return;
            }

            var s3Config = config as AmazonS3Config;

            if (s3Config == null)
            {
                throw new AmazonClientException("Current config object is not of type AmazonS3Config");
            }

            bool isHttp;
            bool removeBucketFromResourcePath = false;

            if (Arn.IsArn(bucketResourcePathToken))
            {
                string accessPoint;
                Arn    accessPointArn;
                if ((accessPointArn = Arn.Parse(bucketResourcePathToken)).TryParseAccessPoint(out accessPoint))
                {
                    if (!string.IsNullOrEmpty(config.ServiceURL))
                    {
                        throw new AmazonClientException(
                                  "The request is using an access point ARN for the bucket name and the S3 service client is configured to use a specific host using the ServiceURL property. " +
                                  "Access point ARNs define the host for the request which makes it incompatible with the host being set ServiceURL. " +
                                  "When using access point arns set the region and not the ServiceURL for the S3 service client.");
                    }
                    if (s3Config.UseAccelerateEndpoint)
                    {
                        throw new AmazonClientException(
                                  "The request is using an access point ARN for the bucket name and the S3 service client is configured to use accelerate endpoints which is not supported. " +
                                  "To use this access point create a new S3 service client with the UseAccelerateEndpoint property set to false."
                                  );
                    }
                    if (string.IsNullOrEmpty(accessPointArn.AccountId))
                    {
                        throw new AmazonClientException("Account ID is missing in access point ARN");
                    }
                    if (string.IsNullOrEmpty(accessPointArn.Region))
                    {
                        throw new AmazonClientException("AWS region is missing in access point ARN");
                    }


                    if (!string.Equals(config.RegionEndpoint.PartitionName, accessPointArn.Partition, StringComparison.Ordinal))
                    {
                        throw new AmazonClientException("The access point used in the request is in a different AWS partition then the region configured for the AmazonS3Client.");
                    }

                    ValidateUseArnRegion(accessPointArn, s3Config);

                    request.UseSigV4 = true;
                    isHttp           = config.UseHttp;

                    removeBucketFromResourcePath = true;

                    var scheme = isHttp ? "http" : "https";

                    UriBuilder ub = new UriBuilder($"{scheme}://{accessPoint}-{accessPointArn.AccountId}.s3-accesspoint{(config.UseDualstackEndpoint ? ".dualstack" : "")}.{accessPointArn.Region}.{config.RegionEndpoint.PartitionDnsSuffix}");
                    request.Endpoint = ub.Uri;

                    // The access point arn can be using a region different from the configured region for the service client.
                    // If so be sure to set the authentication region so the signer will use the correct region.
                    request.AuthenticationRegion = accessPointArn.Region;
                }
                else
                {
                    throw new AmazonClientException("Invalid ARN specified for bucket name. Only access point ARNs are allowed for the value of bucket name.");
                }
            }
            else
            {
                // If path style is not forced and the bucket name is DNS
                // compatible modify the endpoint to use virtual host style
                // addressing
                var bucketIsDnsCompatible = IsDnsCompatibleBucketName(bucketResourcePathToken);
                var ub = new UriBuilder(EndpointResolver.DetermineEndpoint(s3Config, request));
                isHttp = string.Equals(ub.Scheme, "http", StringComparison.OrdinalIgnoreCase);

                if (!s3Config.ForcePathStyle && bucketIsDnsCompatible)
                {
                    // If using HTTPS, bucketName cannot contain a period
                    if (isHttp || bucketResourcePathToken.IndexOf('.') < 0)
                    {
                        // Add bucket to host
                        ub.Host                      = string.Concat(bucketResourcePathToken, ".", ub.Host);
                        request.Endpoint             = ub.Uri;
                        removeBucketFromResourcePath = true;
                    }
                }

                if (s3Config.UseAccelerateEndpoint)
                {
                    // Validate if bucket name is accelerate compatible and enable acceleration by using
                    // Accelerate endpoint for this request

                    if (!bucketIsDnsCompatible || BucketNameContainsPeriod(bucketResourcePathToken))
                    {
                        throw new AmazonClientException(
                                  @"S3 accelerate is enabled for this request but the bucket name is not accelerate compatible." +
                                  " The bucket name must be DNS compatible (http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html)" +
                                  " and must not contain any period (.) characters to be accelerate compatible.");
                    }

                    var  originalRequest        = request.OriginalRequest;
                    bool accelerateSupportedApi = !UnsupportedAccelerateRequestTypes.Contains(originalRequest.GetType());

                    // Skip requests which are not supported
                    if (accelerateSupportedApi)
                    {
                        request.Endpoint = GetAccelerateEndpoint(bucketResourcePathToken, s3Config);

                        if (request.UseSigV4 && s3Config.RegionEndpoint != null)
                        {
                            request.AlternateEndpoint = s3Config.RegionEndpoint;
                        }
                    }
                }
            }

            if (removeBucketFromResourcePath)
            {
                // Remove bucket from resource path but retain in canonical resource
                // prefix, so it gets included when we sign the request later
                var resourcePath        = request.ResourcePath;
                var canonicalBucketName = string.Concat("/", bucketResourcePathToken);
                if (resourcePath.IndexOf(canonicalBucketName, StringComparison.Ordinal) == 0)
                {
                    resourcePath = resourcePath.Substring(canonicalBucketName.Length);
                }

                request.ResourcePath            = resourcePath;
                request.CanonicalResourcePrefix = canonicalBucketName;
            }


            // Some parameters should not be sent over HTTP, just HTTPS
            if (isHttp)
            {
                ValidateHttpsOnlyHeaders(request);
            }
        }