예제 #1
0
        static void Main(string[] args)
        {
            var uri       = "https://jnhisz7ebh.execute-api.eu-west-1.amazonaws.com/api/hostedzone/Z6ZMEKJJ7H3SC/domain/marcelrienks.com";
            var region    = "af-south-1";
            var service   = "execute-api";
            var secretKey = "";
            var secret    = "";

            var httpRequestMethod    = "PATCH";
            var canonicalUri         = "%2Fapi%2Fhostedzone%2FZ6ZMEKJJ7H3SC%2Fdomain%2Fmarcelrienks.com";
            var canonicalQueryString = string.Empty;
            var canonicalHeaders     = string.Empty;
            var signedHeaders        = string.Empty;
            var requestPayload       = string.Empty;

            var canonicalRequest = $"{httpRequestMethod}\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{requestPayload}";

            var signature = AWS4Signer.ComputeSignature(
                awsAccessKey: secretKey,
                awsSecretAccessKey: secret,
                region: region,
                signedAt: DateTime.Now,
                service: service,
                signedHeaders: signedHeaders,
                canonicalRequest: canonicalRequest
                );

            Console.WriteLine(signature.Signature);
            Console.ReadLine();
        }
        /// <summary>
        /// Computes the derived signature for a chunk of data of given length in the input buffer,
        /// placing a formatted chunk with headers, signature and data into the output buffer
        /// ready for streaming back to the consumer.
        /// </summary>
        /// <param name="dataLen"></param>
        private void ConstructOutputBufferChunk(int dataLen)
        {
            // if the input wasn't sufficient to fill the buffer, size it
            // down to make the subseqent hashing/computations easier since
            // they don't take any length arguments
            if (dataLen > 0 && dataLen < _inputBuffer.Length)
            {
                var temp = new byte[dataLen];
                Buffer.BlockCopy(_inputBuffer, 0, temp, 0, dataLen);
                _inputBuffer = temp;
            }

            var chunkHeader = new StringBuilder();

            // variable-length size of the embedded chunk data in hex
            chunkHeader.Append(dataLen.ToString("X", CultureInfo.InvariantCulture));

            const string nonsigExtension = "";

            // signature-extension
            var chunkStringToSign =
                CHUNK_STRING_TO_SIGN_PREFIX + "\n" +
                HeaderSigningResult.ISO8601DateTime + "\n" +
                HeaderSigningResult.Scope + "\n" +
                PreviousChunkSignature + "\n" +
                AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(nonsigExtension), true) + "\n" +
                (dataLen > 0
                    ? AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(_inputBuffer), true)
                    : AWS4Signer.EmptyBodySha256);

            var chunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(HeaderSigningResult.SigningKey, chunkStringToSign), true);

            PreviousChunkSignature = chunkSignature;
            chunkHeader.Append(nonsigExtension + CHUNK_SIGNATURE_HEADER + chunkSignature);
            chunkHeader.Append(CLRF);

            try
            {
                var header  = Encoding.UTF8.GetBytes(chunkHeader.ToString());
                var trailer = Encoding.UTF8.GetBytes(CLRF);

                var writePos = 0;
                Buffer.BlockCopy(header, 0, _outputBuffer, writePos, header.Length);
                writePos += header.Length;
                if (dataLen > 0)
                {
                    Buffer.BlockCopy(_inputBuffer, 0, _outputBuffer, writePos, dataLen);
                    writePos += dataLen;
                }
                Buffer.BlockCopy(trailer, 0, _outputBuffer, writePos, trailer.Length);

                _outputBufferPos     = 0;
                _outputBufferDataLen = header.Length + dataLen + trailer.Length;
            }
            catch (Exception e)
            {
                throw new AmazonClientException("Unable to sign the chunked data. " + e.Message, e);
            }
        }
예제 #3
0
        protected override void PreInvoke(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.OriginalRequest;
            var config  = executionContext.RequestContext.ClientConfig;

            var copySnapshotRequest = request as CopySnapshotRequest;

            if (copySnapshotRequest != null)
            {
                if (string.IsNullOrEmpty(copySnapshotRequest.DestinationRegion))
                {
                    copySnapshotRequest.DestinationRegion = AWS4Signer.DetermineSigningRegion(config, "ec2", alternateEndpoint: null);
                }
                if (string.IsNullOrEmpty(copySnapshotRequest.SourceRegion))
                {
                    throw new AmazonEC2Exception("SourceRegion is required to perform the copy snapshot.");
                }

                var endpoint = RegionEndpoint.GetBySystemName(copySnapshotRequest.SourceRegion);
                if (endpoint == null)
                {
                    throw new AmazonEC2Exception(string.Format(CultureInfo.InvariantCulture, "No endpoint for region {0}.", copySnapshotRequest.SourceRegion));
                }

                // Make sure the presigned URL is currently null so we don't attempt to generate
                // a presigned URL with a presigned URL.
                copySnapshotRequest.PresignedUrl = null;

                // Marshall this request but switch to the source region and make it a GET request.
                var marshaller = new CopySnapshotRequestMarshaller();
                var irequest   = marshaller.Marshall(copySnapshotRequest);
                irequest.UseQueryString = true;
                irequest.HttpMethod     = "GET";
                irequest.Parameters.Add("X-Amz-Expires", AWS4PreSignedUrlSigner.MaxAWS4PreSignedUrlExpiry.ToString(CultureInfo.InvariantCulture));
                irequest.Endpoint = new Uri("https://" + endpoint.GetEndpointForService(config.RegionEndpointServiceName).Hostname);

                // Create presigned URL.
                var metrics = new RequestMetrics();
                var immutableCredentials = _credentials.GetCredentials();

                if (immutableCredentials.UseToken)
                {
                    irequest.Parameters["X-Amz-Security-Token"] = immutableCredentials.Token;
                }

                var signingResult = AWS4PreSignedUrlSigner.SignRequest(irequest,
                                                                       config,
                                                                       metrics,
                                                                       immutableCredentials.AccessKey,
                                                                       immutableCredentials.SecretKey,
                                                                       "ec2",
                                                                       copySnapshotRequest.SourceRegion);

                var authorization = "&" + signingResult.ForQueryParameters;
                var url           = AmazonServiceClient.ComposeUrl(irequest);

                copySnapshotRequest.PresignedUrl = url.AbsoluteUri + authorization;
            }
        }
예제 #4
0
 private string BuildV4aTrailerChunkHelper(AWS4aSigningResult headerResult, string previousSignature, IDictionary <string, string> trailingHeaders)
 {
     return(string.Join('\n',
                        "AWS4-ECDSA-P256-SHA256-TRAILER",
                        headerResult.ISO8601DateTime,
                        headerResult.Scope,
                        previousSignature.TrimEnd('*'),
                        AWSSDKUtils.ToHex(AWS4Signer.ComputeHash("x-amz-foo:bar\n"), true)));
 }
예제 #5
0
        public (string Signature, string Policy) GetSignature(JToken stringToSign)
        {
            var date          = DateTime.UtcNow.ToString("yyyyMMdd");
            var key           = AWS4Signer.ComposeSigningKey(this._awsSecretAccessKey, this._region, date, "s3");
            var policy        = Convert.ToBase64String(Encoding.UTF8.GetBytes(stringToSign.ToString()));
            var signatureHash = AWS4Signer.ComputeKeyedHash(SigningAlgorithm.HmacSHA256, key, policy);
            var signature     = AWSSDKUtils.ToHex(signatureHash, true);

            return(signature, policy);
        }
예제 #6
0
 /// <summary>
 /// Builds the string to sign for a single V4/V4a chunk
 /// </summary>
 /// <param name="prefix">Algorithm being used</param>
 /// <param name="dateTime">ISO8601DateTime that we're signing the request for</param>
 /// <param name="scope">Signing scope (date/region/service/aws4_request)</param>
 /// <param name="previousSignature">Previous chunk's unpadded signature</param>
 /// <param name="dataLength">Length of the content for this chunk</param>
 /// <param name="inputBuffer">Content of this chunk</param>
 /// <returns>The string to sign for this chunk</returns>
 public static string BuildChunkedStringToSign(string prefix, string dateTime, string scope, string previousSignature, int dataLength, byte[] inputBuffer)
 {
     return(prefix + "\n" +
            dateTime + "\n" +
            scope + "\n" +
            previousSignature + "\n" +
            AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(""), true) + "\n" +
            (dataLength > 0
                ? AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(inputBuffer), true)
                : AWS4Signer.EmptyBodySha256));
 }
        protected override void ProcessPreRequestHandlers(AmazonWebServiceRequest request)
        {
            base.ProcessPreRequestHandlers(request);

            var requestCopySnapshot = request as CopySnapshotRequest;

            if (requestCopySnapshot != null)
            {
                if (string.IsNullOrEmpty(requestCopySnapshot.DestinationRegion))
                {
                    requestCopySnapshot.DestinationRegion = AWS4Signer.DetermineSigningRegion(this.Config, "ec2");
                }
                if (string.IsNullOrEmpty(requestCopySnapshot.SourceRegion))
                {
                    throw new AmazonEC2Exception("SourceRegion is required to perform the copy snapshot.");
                }


                var endpoint = RegionEndpoint.GetBySystemName(requestCopySnapshot.SourceRegion);
                if (endpoint == null)
                {
                    throw new AmazonEC2Exception(string.Format(CultureInfo.InvariantCulture, "No endpoint for region {0}.", requestCopySnapshot.SourceRegion));
                }

                // Make sure the presigned URL is currently null so we don't attempt to generate
                // a presigned URL with a presigned URL.
                requestCopySnapshot.PresignedUrl = null;

                // Marshall this request but switch to the source region and make it a GET request.
                CopySnapshotRequestMarshaller marshaller = new CopySnapshotRequestMarshaller();
                var irequest = marshaller.Marshall(requestCopySnapshot);
                irequest.UseQueryString = true;
                irequest.HttpMethod     = "GET";
                irequest.Parameters.Add("X-Amz-Expires", AWS4PreSignedUrlSigner.MaxAWS4PreSignedUrlExpiry.ToString(CultureInfo.InvariantCulture));
                irequest.Endpoint = new Uri("https://" + endpoint.GetEndpointForService(this.Config.RegionEndpointServiceName).Hostname);

                // Create presigned URL.
                var metrics = new RequestMetrics();
                var immutableCredentials = Credentials.GetCredentials();

                var signingResult = AWS4PreSignedUrlSigner.SignRequest(irequest,
                                                                       this.Config,
                                                                       metrics,
                                                                       immutableCredentials.AccessKey,
                                                                       immutableCredentials.SecretKey,
                                                                       "ec2",
                                                                       requestCopySnapshot.SourceRegion);

                var authorization = "&" + signingResult.ForQueryParameters;
                Uri url           = ComposeUrl(irequest, irequest.Endpoint);

                requestCopySnapshot.PresignedUrl = url.AbsoluteUri + authorization;
            }
        }
예제 #8
0
        /// /// <summary>
        /// Calculates the signature for the specified request using the Asymmetric SigV4
        /// signing protocol in preparation for generating a presigned URL.
        /// </summary>
        /// <param name="request">
        /// The request to compute the signature for. Additional headers mandated by the
        /// SigV4a protocol will be added to the request before signing.
        /// </param>
        /// <param name="clientConfig">
        /// Client configuration data encompassing the service call (notably authentication
        /// region, endpoint and service name).
        /// </param>
        /// <param name="metrics">Metrics for the request</param>
        /// <param name="credentials">The AWS credentials for the account making the service call</param>
        /// <param name="service">Service to sign the request for</param>
        /// <param name="overrideSigningRegion">Region to sign the request for</param>
        /// <returns>AWS4aSigningResult for the given request</returns>
        public AWS4aSigningResult Presign4a(IRequest request,
                                            IClientConfig clientConfig,
                                            RequestMetrics metrics,
                                            ImmutableCredentials credentials,
                                            string service,
                                            string overrideSigningRegion)
        {
            var signedAt  = AWS4Signer.InitializeHeaders(request.Headers, request.Endpoint);
            var regionSet = overrideSigningRegion ?? AWS4Signer.DetermineSigningRegion(clientConfig, service, request.AlternateEndpoint, request);

            var signingConfig = PrepareCRTSigningConfig(AwsSignatureType.HTTP_REQUEST_VIA_QUERY_PARAMS, regionSet, service, signedAt, credentials);

            if (AWS4PreSignedUrlSigner.ServicesUsingUnsignedPayload.Contains(service))
            {
                signingConfig.SignedBodyValue = AWS4Signer.UnsignedPayload;
            }
            else
            {
                signingConfig.SignedBodyValue = AWS4Signer.EmptyBodySha256;
            }

            // The expiration may have already be set in a header when marshalling the GetPreSignedUrlRequest -> IRequest
            if (request.Parameters != null && request.Parameters.ContainsKey(HeaderKeys.XAmzExpires))
            {
                signingConfig.ExpirationInSeconds = Convert.ToUInt64(request.Parameters[HeaderKeys.XAmzExpires]);
            }

            var crtRequest    = CrtHttpRequestConverter.ConvertToCrtRequest(request);
            var signingResult = AwsSigner.SignHttpRequest(crtRequest, signingConfig);

            string authorizationValue = Encoding.Default.GetString(signingResult.Get().Signature);
            var    dateStamp          = AWS4Signer.FormatDateTime(signedAt, AWSSDKUtils.ISO8601BasicDateFormat);
            var    scope = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}", dateStamp, service, AWS4Signer.Terminator);

            AWS4aSigningResult result = new AWS4aSigningResult(
                credentials.AccessKey,
                signedAt,
                CrtHttpRequestConverter.ExtractSignedHeaders(signingResult.Get().SignedRequest),
                scope,
                regionSet,
                authorizationValue,
                service,
                signingResult.Get().SignedRequest.Uri,
                credentials);

            return(result);
        }
예제 #9
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);
        }
예제 #10
0
        /// <summary>
        /// Calculates the signature for the specified request using the Asymmetric SigV4 signing protocol
        /// </summary>
        /// <param name="request">
        /// The request to compute the signature for. Additional headers mandated by the
        /// SigV4a protocol will be added to the request before signing.
        /// </param>
        /// <param name="clientConfig">
        /// Client configuration data encompassing the service call (notably authentication
        /// region, endpoint and service name).
        /// </param>
        /// <param name="metrics">Metrics for the request</param>
        /// <param name="credentials">The AWS credentials for the account making the service call</param>
        /// <returns>AWS4aSigningResult for the given request</returns>
        public AWS4aSigningResult SignRequest(IRequest request,
                                              IClientConfig clientConfig,
                                              RequestMetrics metrics,
                                              ImmutableCredentials credentials)
        {
            var signedAt           = AWS4Signer.InitializeHeaders(request.Headers, request.Endpoint);
            var serviceSigningName = !string.IsNullOrEmpty(request.OverrideSigningServiceName) ? request.OverrideSigningServiceName : AWS4Signer.DetermineService(clientConfig);
            var regionSet          = AWS4Signer.DetermineSigningRegion(clientConfig, clientConfig.RegionEndpointServiceName, request.AlternateEndpoint, request);

            request.DeterminedSigningRegion = regionSet;
            AWS4Signer.SetXAmzTrailerHeader(request.Headers, request.TrailingHeaders);

            var signingConfig = PrepareCRTSigningConfig(AwsSignatureType.HTTP_REQUEST_VIA_HEADERS, regionSet, serviceSigningName, signedAt, credentials);

            // If the request should use a fixed x-amz-content-sha256 header value, determine the appropriate one
            var fixedBodyHash = request.TrailingHeaders?.Count > 0
                ? AWS4Signer.V4aStreamingBodySha256WithTrailer
                : AWS4Signer.V4aStreamingBodySha256;

            signingConfig.SignedBodyValue = AWS4Signer.SetRequestBodyHash(request, SignPayload, fixedBodyHash, ChunkedUploadWrapperStream.V4A_SIGNATURE_LENGTH);

            var crtRequest    = CrtHttpRequestConverter.ConvertToCrtRequest(request);
            var signingResult = AwsSigner.SignHttpRequest(crtRequest, signingConfig);

            var authorizationValue = Encoding.Default.GetString(signingResult.Get().Signature);
            var signedCrtRequest   = signingResult.Get().SignedRequest;

            CrtHttpRequestConverter.CopyHeadersFromCrtRequest(request, signedCrtRequest);

            var dateStamp = AWS4Signer.FormatDateTime(signedAt, AWSSDKUtils.ISO8601BasicDateFormat);
            var scope     = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}", dateStamp, serviceSigningName, AWS4Signer.Terminator);

            AWS4aSigningResult result = new AWS4aSigningResult(
                credentials.AccessKey,
                signedAt,
                CrtHttpRequestConverter.ExtractSignedHeaders(signedCrtRequest),
                scope,
                regionSet,
                authorizationValue,
                serviceSigningName,
                "",
                credentials);

            return(result);
        }
예제 #11
0
        public static S3PostUploadSignedPolicy GetSignedPolicyV4(string policy, AWSCredentials credentials, RegionEndpoint region)
        {
            DateTime             correctedUtcNow = AWSSDKUtils.get_CorrectedUtcNow();
            ImmutableCredentials credentials2    = credentials.GetCredentials();
            string text  = "AWS4-HMAC-SHA256";
            string text2 = AWS4Signer.FormatDateTime(correctedUtcNow, "yyyyMMdd");
            string text3 = AWS4Signer.FormatDateTime(correctedUtcNow, "yyyyMMddTHHmmssZ");
            string text4 = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}/{3}/{4}/", credentials2.get_AccessKey(), text2, region.get_SystemName(), "s3", "aws4_request");
            Dictionary <string, string> dictionary = new Dictionary <string, string>
            {
                {
                    S3Constants.PostFormDataXAmzCredential,
                    text4
                },
                {
                    S3Constants.PostFormDataXAmzAlgorithm,
                    text
                },
                {
                    S3Constants.PostFormDataXAmzDate,
                    text3
                }
            };

            if (credentials2.get_UseToken())
            {
                dictionary[S3Constants.PostFormDataSecurityToken] = credentials2.get_Token();
            }
            string text5 = Convert.ToBase64String(addConditionsToPolicy(policy, dictionary));

            byte[] array     = AWS4Signer.ComposeSigningKey(credentials2.get_SecretKey(), region.get_SystemName(), text2, "s3");
            string signature = AWSSDKUtils.ToHex(AWS4Signer.ComputeKeyedHash(1, array, text5), true);

            return(new S3PostUploadSignedPolicy
            {
                Policy = text5,
                Signature = signature,
                AccessKeyId = credentials2.get_AccessKey(),
                SecurityToken = credentials2.get_Token(),
                SignatureVersion = "4",
                Algorithm = text,
                Date = text3,
                Credential = text4
            });
        }
        public static async Task <string> CalculateAsync(HttpContent content)
        {
            // Use a hash (digest) function like SHA256 to create a hashed value from the payload
            // in the body of the HTTP or HTTPS request.
            //
            // If the payload is empty, use an empty string as the input to the hash function.
            if (content == null)
            {
                // Per performance reasons, use the pre-computed hash of an empty string from the
                // AWS SDK
                return(AWS4Signer.EmptyBodySha256);
            }

            var data = await content.ReadAsByteArrayAsync();

            var hash = AWS4Signer.ComputeHash(data);

            return(AWSSDKUtils.ToHex(hash, true));
        }
예제 #13
0
        public static string Build(
            DateTime now,
            string regionName,
            string serviceName,
            ImmutableCredentials credentials,
            string signedHeaders,
            string credentialScope,
            string stringToSign)
        {
            // The following pseudocode shows the construction of the Authorization header value.
            //
            //   <algorithm> Credential=<access key id>/<credential scope>, SignedHeaders=<signed headers>, Signature=<signature>
            //
            // Note the following:
            //
            // - There is no comma between the algorithm and Credential. However, the SignedHeaders
            //   and Signature are separated from the preceding values with a comma.
            // - The Credential value starts with the access key id, which is followed by a forward
            //   slash (/), which is followed by the credential scope. The secret access key is
            //   used to derive the signing key for the signature, but is not included in the
            //   signing information sent in the request.
            //
            // To derive your signing key, use your secret access key to create a series of hash-
            // based message authentication codes (HMACs).
            //
            // Note that the date used in the hashing process is in the format YYYYMMDD (for
            // example, 20150830), and does not include the time.
            var signingKey = AWS4Signer.ComposeSigningKey(
                credentials.SecretKey,
                regionName,
                now.ToIso8601BasicDate(),
                serviceName);

            // Calculate the signature. To do this, use the signing key that you derived and the
            // string to sign as inputs to the keyed hash function. After you calculate the
            // signature, convert the binary value to a hexadecimal representation.
            var hash      = AWS4Signer.ComputeKeyedHash(SigningAlgorithm.HmacSHA256, signingKey, stringToSign);
            var signature = AWSSDKUtils.ToHex(hash, true);

            return($"{AWS4Signer.AWS4AlgorithmTag} Credential={credentials.AccessKey}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}");
        }
예제 #14
0
        /// <summary>
        /// Constructs the signed trailing headers, optionally including
        /// the selected checksum for this stream's data. For example:
        /// trailing-header-A:value CRLF
        /// trailing-header-B:value CRLF
        /// x-amz-trailer-signature:signature_value CRLF
        /// CRLF
        /// </summary>
        /// <returns>Stream chunk containing the trailing headers and their signature</returns>
        private string ConstructSignedTrailersChunk()
        {
            // If the trailing headers included a trailing checksum, set the hash value
            if (_hashAlgorithm != null)
            {
                _hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0);
                _trailingHeaders[ChecksumUtils.GetChecksumHeaderKey(_trailingChecksum)] = Convert.ToBase64String(_hashAlgorithm.Hash);
            }

            string chunkSignature;

            if (HeaderSigningResult is AWS4SigningResult)
            {
                var sortedTrailingHeaders        = AWS4Signer.SortAndPruneHeaders(_trailingHeaders);
                var canonicalizedTrailingHeaders = AWS4Signer.CanonicalizeHeaders(sortedTrailingHeaders);

                var chunkStringToSign =
                    TRAILING_HEADER_STRING_TO_SIGN_PREFIX + "\n" +
                    HeaderSigningResult.ISO8601DateTime + "\n" +
                    HeaderSigningResult.Scope + "\n" +
                    PreviousChunkSignature + "\n" +
                    AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(canonicalizedTrailingHeaders), true);

                chunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(((AWS4SigningResult)HeaderSigningResult).GetSigningKey(), chunkStringToSign), true);
            }
            else // SigV4a
            {
                chunkSignature = Sigv4aSigner.SignTrailingHeaderChunk(_trailingHeaders, PreviousChunkSignature, (AWS4aSigningResult)HeaderSigningResult).PadRight(V4A_SIGNATURE_LENGTH, '*');
            }

            var chunk = new StringBuilder();

            // The order here must match the order of keys sent already in the X-Amz-Trailer header.
            foreach (var kvp in _trailingHeaders.OrderBy(kvp => kvp.Key))
            {
                chunk.Append($"{kvp.Key}:{kvp.Value}{STREAM_NEWLINE}");
            }
            chunk.Append($"{TRAILING_HEADER_SIGNATURE_KEY}:{chunkSignature}{STREAM_NEWLINE}");
            chunk.Append(STREAM_NEWLINE);
            return(chunk.ToString());
        }
예제 #15
0
        public void TestSignerWithMutableHeader()
        {
            var pipeline = new RuntimePipeline(new MockHandler());

            pipeline.AddHandler(new Signer());
            pipeline.AddHandler(new CredentialsRetriever(new BasicAWSCredentials("accessKey", "secretKey")));

            var signer  = new AWS4Signer();
            var context = CreateTestContext(signer);

            // inject a mutable header that the signer should strip out
            context.RequestContext.Request.Headers[HeaderKeys.XAmznTraceIdHeader] = "stuff";
            pipeline.InvokeSync(context);

            // verify that the header is not in the signature
            var t = context.RequestContext.Request.Headers[HeaderKeys.AuthorizationHeader];

            Assert.IsFalse(t.Contains(HeaderKeys.XAmznTraceIdHeader));

            Assert.IsTrue(context.RequestContext.Request.Headers.ContainsKey(HeaderKeys.XAmznTraceIdHeader));
        }
예제 #16
0
        /// <returns>
        /// The first value is the string to sign, the second value is the credentials scope.
        /// </returns>
        public static (string, string) Build(DateTime now, string regionName, string serviceName, string canonicalRequest)
        {
            var builder = new StringBuilder();

            // Start with the algorithm designation, followed by a newline character. This value is
            // the hashing algorithm that you use to calculate the digests in the canonical
            // request. For SHA256, AWS4-HMAC-SHA256 is the algorithm.
            builder.Append($"{AWS4Signer.AWS4AlgorithmTag}\n");

            // Append the request date value, followed by a newline character. The date is
            // specified with ISO8601 basic format in the x-amz-date header in the format
            // YYYYMMDD'T'HHMMSS'Z'. This value must match the value you used in any previous
            // steps.
            builder.Append($"{now.ToIso8601BasicDateTime()}\n");

            // Append the credential scope value, followed by a newline character. This value is a
            // string that includes the date, the region you are targeting, the service you are
            // requesting, and a termination string ("aws4_request") in lowercase characters. The
            // region and service name strings must be UTF-8 encoded.
            //
            // - The date must be in the YYYYMMDD format. Note that the date does not include a
            //   time value.
            // - Verify that the region you specify is the region that you are sending the request
            //   to. See <see href="https://docs.aws.amazon.com/general/latest/gr/rande.html">AWS
            //   Regions and Endpoints</see>.
            var credentialScope = $"{now.ToIso8601BasicDate()}/{regionName}/{serviceName}/{AWS4Signer.Terminator}";

            builder.Append($"{credentialScope}\n");

            // Append the hash of the canonical request. This value is not followed by a newline
            // character. The hashed canonical request must be lowercase base-16 encoded, as
            // defined by <see href="https://tools.ietf.org/html/rfc4648#section-8">Section 8 of
            // RFC 4648</see>.
            var hash = AWS4Signer.ComputeHash(canonicalRequest);
            var hex  = AWSSDKUtils.ToHex(hash, true);

            builder.Append(hex);

            return(builder.ToString(), credentialScope);
        }
예제 #17
0
        /// <summary>
        /// Calculates the signature for the specified request using the Asymmetric SigV4 signing protocol
        /// </summary>
        /// <param name="request">
        /// The request to compute the signature for. Additional headers mandated by the
        /// SigV4a protocol will be added to the request before signing.
        /// </param>
        /// <param name="clientConfig">
        /// Client configuration data encompassing the service call (notably authentication
        /// region, endpoint and service name).
        /// </param>
        /// <param name="metrics">Metrics for the request</param>
        /// <param name="credentials">The AWS credentials for the account making the service call</param>
        /// <returns>AWS4aSigningResult for the given request</returns>
        public AWS4aSigningResult SignRequest(IRequest request,
                                              IClientConfig clientConfig,
                                              RequestMetrics metrics,
                                              ImmutableCredentials credentials)
        {
            var signedAt  = AWS4Signer.InitializeHeaders(request.Headers, request.Endpoint);
            var service   = !string.IsNullOrEmpty(request.OverrideSigningServiceName) ? request.OverrideSigningServiceName : AWS4Signer.DetermineService(clientConfig);
            var regionSet = AWS4Signer.DetermineSigningRegion(clientConfig, service, request.AlternateEndpoint, request);

            request.DeterminedSigningRegion = regionSet;

            var signingConfig = PrepareCRTSigningConfig(AwsSignatureType.HTTP_REQUEST_VIA_HEADERS, regionSet, service, signedAt, credentials);

            // Compute here rather than CRT to support the fixed value for header of a chunked request
            signingConfig.SignedBodyValue = AWS4Signer.SetRequestBodyHash(request, SignPayload, AWS4Signer.V4aStreamingBodySha256, ChunkedUploadWrapperStream.V4A_SIGNATURE_LENGTH);

            var crtRequest    = CrtHttpRequestConverter.ConvertToCrtRequest(request);
            var signingResult = AwsSigner.SignHttpRequest(crtRequest, signingConfig);

            var authorizationValue = Encoding.Default.GetString(signingResult.Get().Signature);
            var signedCrtRequest   = signingResult.Get().SignedRequest;

            CrtHttpRequestConverter.CopyHeadersFromCrtRequest(request, signedCrtRequest);

            var dateStamp = AWS4Signer.FormatDateTime(signedAt, AWSSDKUtils.ISO8601BasicDateFormat);
            var scope     = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}", dateStamp, service, AWS4Signer.Terminator);

            AWS4aSigningResult result = new AWS4aSigningResult(
                credentials.AccessKey,
                signedAt,
                CrtHttpRequestConverter.ExtractSignedHeaders(signedCrtRequest),
                scope,
                regionSet,
                authorizationValue,
                service,
                "",
                credentials);

            return(result);
        }
예제 #18
0
        private void RunTestRequest(AmazonWebServiceRequest request, IMarshaller <IRequest, AmazonWebServiceRequest> marshaller,
                                    bool isArn, string serviceUrl, Flags flags,
                                    string expectedUri, string expectedRegion, string expectedService)
        {
            var clientConfig = CreateConfig(serviceUrl, flags);

            var internalRequest = S3ControlArnTestUtils.RunMockRequest(request, marshaller, clientConfig);

            Assert.AreEqual(new Uri(expectedUri), internalRequest.Endpoint);

            if (isArn)
            {
                Assert.AreEqual(expectedRegion, internalRequest.AuthenticationRegion);
                Assert.AreEqual(expectedService, internalRequest.OverrideSigningServiceName);
            }

            var service       = DetermineService(clientConfig);
            var signingRegion = AWS4Signer.DetermineSigningRegion(clientConfig, service, internalRequest.AlternateEndpoint, internalRequest);

            Assert.AreEqual(expectedRegion, signingRegion);
            Assert.AreEqual(expectedService, internalRequest.OverrideSigningServiceName ?? service);
        }
        private void ConstructOutputBufferChunk(int dataLen)
        {
            if (dataLen > 0 && dataLen < _inputBuffer.Length)
            {
                byte[] array = new byte[dataLen];
                Buffer.BlockCopy(_inputBuffer, 0, array, 0, dataLen);
                _inputBuffer = array;
            }
            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.Append(dataLen.ToString("X", CultureInfo.InvariantCulture));
            string data = "AWS4-HMAC-SHA256-PAYLOAD\n" + HeaderSigningResult.ISO8601DateTime + "\n" + HeaderSigningResult.Scope + "\n" + PreviousChunkSignature + "\n" + AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(""), lowercase: true) + "\n" + ((dataLen > 0) ? AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(_inputBuffer), lowercase: true) : "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
            string str  = PreviousChunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(HeaderSigningResult.SigningKey, data), lowercase: true);

            stringBuilder.Append(";chunk-signature=" + str);
            stringBuilder.Append("\r\n");
            try
            {
                byte[] bytes  = Encoding.UTF8.GetBytes(stringBuilder.ToString());
                byte[] bytes2 = Encoding.UTF8.GetBytes("\r\n");
                int    num    = 0;
                Buffer.BlockCopy(bytes, 0, _outputBuffer, num, bytes.Length);
                num += bytes.Length;
                if (dataLen > 0)
                {
                    Buffer.BlockCopy(_inputBuffer, 0, _outputBuffer, num, dataLen);
                    num += dataLen;
                }
                Buffer.BlockCopy(bytes2, 0, _outputBuffer, num, bytes2.Length);
                _outputBufferPos     = 0;
                _outputBufferDataLen = bytes.Length + dataLen + bytes2.Length;
            }
            catch (Exception ex)
            {
                throw new AmazonClientException("Unable to sign the chunked data. " + ex.Message, ex);
            }
        }
예제 #20
0
        public override void Sign(IRequest request, IClientConfig clientConfig, RequestMetrics metrics, string awsAccessKeyId, string awsSecretAccessKey)
        {
            AWS4Signer val = this.SelectSigner(this, _useSigV4, request, clientConfig) as AWS4Signer;

            if (val != null)
            {
                AmazonS3Uri    amazonS3Uri;
                RegionEndpoint alternateEndpoint = default(RegionEndpoint);
                if (AmazonS3Uri.TryParseAmazonS3Uri(request.get_Endpoint(), out amazonS3Uri) && amazonS3Uri.Bucket != null && BucketRegionDetector.BucketRegionCache.TryGetValue(amazonS3Uri.Bucket, ref alternateEndpoint))
                {
                    request.set_AlternateEndpoint(alternateEndpoint);
                }
                AWS4SigningResult val2 = val.SignRequest(request, clientConfig, metrics, awsAccessKeyId, awsSecretAccessKey);
                request.get_Headers()["Authorization"] = val2.get_ForAuthorizationHeader();
                if (request.get_UseChunkEncoding())
                {
                    request.set_AWS4SignerResult(val2);
                }
            }
            else
            {
                SignRequest(request, metrics, awsAccessKeyId, awsSecretAccessKey);
            }
        }
예제 #21
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);
        }
예제 #22
0
        /// <summary>
        /// Custom pipeline handler
        /// </summary>
        /// <param name="executionContext"></param>
        protected void PreInvoke(IExecutionContext executionContext)
        {
            var request = executionContext.RequestContext.OriginalRequest;
            var config  = executionContext.RequestContext.ClientConfig;

            var runInstancesRequest = request as RunInstancesRequest;

            if (runInstancesRequest != null)
            {
                if (runInstancesRequest.IsSetBlockDeviceMappings())
                {
                    var mappings = runInstancesRequest.BlockDeviceMappings;
                    foreach (var mapping in mappings)
                    {
                        if (mapping.IsSetEbs())
                        {
                            var ebs = mapping.Ebs;
                            if (ebs.IsSetSnapshotId() &&
                                ebs.IsSetEncrypted() &&
                                ebs.Encrypted == false)
                            {
                                ebs.ClearEncryptedFlag();
                            }
                        }
                    }
                }
            }

            // replace null Tag.Value with empty string
            var createTagsRequest = request as CreateTagsRequest;

            if (createTagsRequest != null)
            {
                if (createTagsRequest.IsSetTags())
                {
                    var tags = createTagsRequest.Tags;
                    foreach (var tag in tags)
                    {
                        if (tag != null && tag.Value == null)
                        {
                            tag.Value = string.Empty;
                        }
                    }
                }
            }

            var copySnapshotRequest = request as CopySnapshotRequest;

            if (copySnapshotRequest != null)
            {
                if (string.IsNullOrEmpty(copySnapshotRequest.DestinationRegion))
                {
                    copySnapshotRequest.DestinationRegion = AWS4Signer.DetermineSigningRegion(config, "ec2", alternateEndpoint: null, request: null);
                }
                if (string.IsNullOrEmpty(copySnapshotRequest.SourceRegion))
                {
                    throw new AmazonEC2Exception("SourceRegion is required to perform the copy snapshot.");
                }

                var endpoint = RegionEndpoint.GetBySystemName(copySnapshotRequest.SourceRegion);
                if (endpoint == null)
                {
                    throw new AmazonEC2Exception(string.Format(CultureInfo.InvariantCulture, "No endpoint for region {0}.", copySnapshotRequest.SourceRegion));
                }

                // Make sure the presigned URL is currently null so we don't attempt to generate
                // a presigned URL with a presigned URL.
                copySnapshotRequest.PresignedUrl = null;

                // Marshall this request but switch to the source region and make it a GET request.
                var marshaller = new CopySnapshotRequestMarshaller();
                var irequest   = marshaller.Marshall(copySnapshotRequest);
                irequest.UseQueryString = true;
                irequest.HttpMethod     = "GET";
                irequest.Parameters.Add("X-Amz-Expires", AWS4PreSignedUrlSigner.MaxAWS4PreSignedUrlExpiry.ToString(CultureInfo.InvariantCulture));
                irequest.Endpoint = new Uri("https://" + endpoint.GetEndpointForService(config.RegionEndpointServiceName).Hostname);

                // Create presigned URL.
                var metrics = new RequestMetrics();
                var immutableCredentials = _credentials.GetCredentials();

                if (immutableCredentials.UseToken)
                {
                    irequest.Parameters["X-Amz-Security-Token"] = immutableCredentials.Token;
                }

                var signingResult = AWS4PreSignedUrlSigner.SignRequest(irequest,
                                                                       config,
                                                                       metrics,
                                                                       immutableCredentials.AccessKey,
                                                                       immutableCredentials.SecretKey,
                                                                       "ec2",
                                                                       copySnapshotRequest.SourceRegion);

                var authorization = "&" + signingResult.ForQueryParameters;
                var url           = AmazonServiceClient.ComposeUrl(irequest);

                copySnapshotRequest.PresignedUrl = url.AbsoluteUri + authorization;
            }

            var authorizeSecurityGroupEgressRequest = request as AuthorizeSecurityGroupEgressRequest;

            if (authorizeSecurityGroupEgressRequest != null)
            {
                if (authorizeSecurityGroupEgressRequest.IsSetIpPermissions())
                {
                    SelectModifiedIpRange(authorizeSecurityGroupEgressRequest.IpPermissions);
                }
            }

            var authorizeSecurityGroupIngressRequest = request as AuthorizeSecurityGroupIngressRequest;

            if (authorizeSecurityGroupIngressRequest != null)
            {
                if (authorizeSecurityGroupIngressRequest.IsSetIpPermissions())
                {
                    SelectModifiedIpRange(authorizeSecurityGroupIngressRequest.IpPermissions);
                }
            }

            var revokeSecurityGroupEgressRequest = request as RevokeSecurityGroupEgressRequest;

            if (revokeSecurityGroupEgressRequest != null)
            {
                if (revokeSecurityGroupEgressRequest.IsSetIpPermissions())
                {
                    SelectModifiedIpRange(revokeSecurityGroupEgressRequest.IpPermissions);
                }
            }

            var revokeSecurityGroupIngressRequest = request as RevokeSecurityGroupIngressRequest;

            if (revokeSecurityGroupIngressRequest != null)
            {
                if (revokeSecurityGroupIngressRequest.IsSetIpPermissions())
                {
                    SelectModifiedIpRange(revokeSecurityGroupIngressRequest.IpPermissions);
                }
            }

            var updateSecurityGroupRuleDescriptionsEgressRequest = request as UpdateSecurityGroupRuleDescriptionsEgressRequest;

            if (updateSecurityGroupRuleDescriptionsEgressRequest != null)
            {
                if (updateSecurityGroupRuleDescriptionsEgressRequest.IsSetIpPermissions())
                {
                    SelectModifiedIpRange(updateSecurityGroupRuleDescriptionsEgressRequest.IpPermissions);
                }
            }

            var updateSecurityGroupRuleDescriptionsIngressRequest = request as UpdateSecurityGroupRuleDescriptionsIngressRequest;

            if (updateSecurityGroupRuleDescriptionsIngressRequest != null)
            {
                if (updateSecurityGroupRuleDescriptionsIngressRequest.IsSetIpPermissions())
                {
                    SelectModifiedIpRange(updateSecurityGroupRuleDescriptionsIngressRequest.IpPermissions);
                }
            }
        }
예제 #23
0
 /// <summary>
 /// Converts instance into a ISO8601 basic date format of 'yyyyMMdd'.
 /// </summary>
 public static string ToIso8601BasicDate(this DateTime self) =>
 AWS4Signer.FormatDateTime(self, AWSSDKUtils.ISO8601BasicDateFormat);
예제 #24
0
 public static string GetAWSSignatureKey(String key, String dateStamp, String regionName, String serviceName)
 {
     return(StringUtils.ToHexString(AWS4Signer.ComposeSigningKey(key, regionName, dateStamp, serviceName)).Trim().ToLower());
 }
예제 #25
0
        /// <summary>
        /// Computes the derived signature for a chunk of data of given length in the input buffer,
        /// placing a formatted chunk with headers, signature and data into the output buffer
        /// ready for streaming back to the consumer.
        /// </summary>
        /// <param name="dataLen"></param>
        private void ConstructOutputBufferChunk(int dataLen)
        {
            // if the input wasn't sufficient to fill the buffer, size it
            // down to make the subseqent hashing/computations easier since
            // they don't take any length arguments
            if (dataLen > 0 && dataLen < _inputBuffer.Length)
            {
                var temp = new byte[dataLen];
                Buffer.BlockCopy(_inputBuffer, 0, temp, 0, dataLen);
                _inputBuffer = temp;
            }

            var chunkHeader = new StringBuilder();

            // variable-length size of the embedded chunk data in hex
            chunkHeader.Append(dataLen.ToString("X", CultureInfo.InvariantCulture));

            string chunkSignature = "";

            if (HeaderSigningResult is AWS4aSigningResult v4aHeaderSigningResult)
            {
                if (dataLen == 0)   // _inputBuffer still contains previous chunk, but this is the final 0 content chunk so sign null
                {
                    chunkSignature = Sigv4aSigner.SignChunk(null, PreviousChunkSignature, v4aHeaderSigningResult);
                }
                else
                {
                    chunkSignature = Sigv4aSigner.SignChunk(new MemoryStream(_inputBuffer), PreviousChunkSignature, v4aHeaderSigningResult);
                }
            }
            else if (HeaderSigningResult is AWS4SigningResult v4HeaderSingingResult) // SigV4
            {
                var chunkStringToSign = BuildChunkedStringToSign(CHUNK_STRING_TO_SIGN_PREFIX, v4HeaderSingingResult.ISO8601DateTime,
                                                                 v4HeaderSingingResult.Scope, PreviousChunkSignature, dataLen, _inputBuffer);

                chunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(v4HeaderSingingResult.GetSigningKey(), chunkStringToSign), true);
            }

            // For Sigv4a the chunk signature must be padded when being appended to the chunk metadata,
            // but not when being used as the input for the next chunk
            PreviousChunkSignature = chunkSignature;
            if (HeaderSigningResult is AWS4aSigningResult)
            {
                chunkHeader.Append(CHUNK_SIGNATURE_HEADER + chunkSignature.PadRight(V4A_SIGNATURE_LENGTH, '*'));
            }
            else // SigV4
            {
                chunkHeader.Append(CHUNK_SIGNATURE_HEADER + chunkSignature);
            }
            chunkHeader.Append(CLRF);

            try
            {
                var header  = Encoding.UTF8.GetBytes(chunkHeader.ToString());
                var trailer = Encoding.UTF8.GetBytes(CLRF);

                var writePos = 0;
                Buffer.BlockCopy(header, 0, _outputBuffer, writePos, header.Length);
                writePos += header.Length;
                if (dataLen > 0)
                {
                    Buffer.BlockCopy(_inputBuffer, 0, _outputBuffer, writePos, dataLen);
                    writePos += dataLen;
                }
                Buffer.BlockCopy(trailer, 0, _outputBuffer, writePos, trailer.Length);

                _outputBufferPos     = 0;
                _outputBufferDataLen = header.Length + dataLen + trailer.Length;
            }
            catch (Exception e)
            {
                throw new AmazonClientException("Unable to sign the chunked data. " + e.Message, e);
            }
        }
        /// <returns>
        /// The first value is the canonical request, the second value is the signed headers.
        /// </returns>
        public static async Task <(string, string)> BuildAsync(
            HttpRequestMessage request,
            HttpRequestHeaders defaultHeaders)
        {
            var builder = new StringBuilder();

            // The HTTP request method (GET, PUT, POST, etc.), followed by a newline character
            builder.Append($"{request.Method}\n");

            // Add the canonical URI parameter, followed by a newline character. The canonical URI
            // is the URI-encoded version of the absolute path component of the URI, which is
            // everything in the URI from the HTTP host to the question mark character ("?") that
            // begins the query string parameters (if any).
            //
            // Normalize URI paths according to <see href="https://tools.ietf.org/html/rfc3986">RFC
            // 3986</see>. Remove redundant and relative path components. Each path segment must be
            // URI-encoded twice (
            // <see href="https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html">
            // except for Amazon S3 which only gets URI-encoded once</see>).
            var pathSegments = request.RequestUri.AbsolutePath
                               .Replace("//", "/")
                               .Split('/')
                               .Select(pathSegment => AWSSDKUtils.UrlEncode(pathSegment, false));

            builder.Append($"{string.Join("/", pathSegments)}\n");

            // Add the canonical query string, followed by a newline character. If the request does
            // not include a query string, use an empty string (essentially, a blank line).
            //
            // To construct the canonical query string, complete the following steps:
            //
            // a. Sort the parameter names by character code point in ascending order. Parameters
            //    with duplicate names should be sorted by value. For example, a parameter name
            //    that begins with the uppercase letter F precedes a parameter name that begins
            //    with a lowercase letter b.
            // b. URI-encode each parameter name and value according to the following rules:
            //    - Do not URI-encode any of the unreserved characters that RFC 3986 defines: A-Z,
            //      a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), and tilde ( ~ ).
            //    - Percent-encode all other characters with %XY, where X and Y are hexadecimal
            //      characters (0-9 and uppercase A-F). For example, the space character must be
            //      encoded as %20 (not using '+', as some encoding schemes do) and extended UTF-8
            //      characters must be in the form %XY%ZA%BC.
            // c. Build the canonical query string by starting with the first parameter name in the
            //    sorted list.
            // d. For each parameter, append the URI-encoded parameter name, followed by the equals
            //    sign character (=), followed by the URI-encoded parameter value. Use an empty
            //    string for parameters that have no value.
            // e. Append the ampersand character (&) after each parameter value, except for the
            //    last value in the list.
            var parameters = SortQueryParameters(request.RequestUri.Query)
                             .SelectMany(
                parameter => parameter.Value.Select(
                    parameterValue => $"{AWSSDKUtils.UrlEncode(parameter.Key, false)}={AWSSDKUtils.UrlEncode(parameterValue, false)}"));

            builder.Append($"{string.Join("&", parameters)}\n");

            // Add the canonical headers, followed by a newline character. The canonical headers
            // consist of a list of all the HTTP headers that you are including with the signed
            // request.
            //
            // To create the canonical headers list, convert all header names to lowercase and
            // remove leading spaces and trailing spaces. Convert sequential spaces in the header
            // value to a single space.
            //
            // Build the canonical headers list by sorting the (lowercase) headers by character
            // code and then iterating through the header names. Construct each header according to
            // the following rules:
            //
            // - Append the lowercase header name followed by a colon.
            // - Append a comma-separated list of values for that header. Do not sort the values in
            //   headers that have multiple values.
            //   PLEASE NOTE: Microsoft has chosen to separate the header values with ", ", not ","
            //   as defined by the Canonical Request algorithm.
            // - Append a new line ('\n').
            var sortedHeaders = SortHeaders(request.Headers, defaultHeaders);

            foreach (var header in sortedHeaders)
            {
                builder.Append($"{header.Key}:{string.Join(HeaderValueSeparator, header.Value)}\n");
            }

            builder.Append('\n');

            // Add the signed headers, followed by a newline character. This value is the list of
            // headers that you included in the canonical headers. By adding this list of headers,
            // you tell AWS which headers in the request are part of the signing process and which
            // ones AWS can ignore (for example, any additional headers added by a proxy) for
            // purposes of validating the request.
            //
            // To create the signed headers list, convert all header names to lowercase, sort them
            // by character code, and use a semicolon to separate the header names.
            //
            // Build the signed headers list by iterating through the collection of header names,
            // sorted by lowercase character code. For each header name except the last, append a
            // semicolon (';') to the header name to separate it from the following header name.
            var signedHeaders = string.Join(";", sortedHeaders.Keys);

            builder.Append($"{signedHeaders}\n");

            // Use a hash (digest) function like SHA256 to create a hashed value from the payload
            // in the body of the HTTP or HTTPS request.
            //
            // If the payload is empty, use an empty string as the input to the hash function.
            var requestPayload = request.Content != null
                ? await request.Content.ReadAsByteArrayAsync()
                : new byte[0];

            var hash = AWS4Signer.ComputeHash(requestPayload);
            var hex  = AWSSDKUtils.ToHex(hash, true);

            builder.Append(hex);

            return(builder.ToString(), signedHeaders);
        }
예제 #27
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);
        }
        /// <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>
        /// <returns>A string that is the signed http request.</returns>
        /// <exception cref="T:System.ArgumentException" />
        /// <exception cref="T:System.ArgumentNullException" />
        public string GetPreSignedURL(GetPreSignedUrlRequest request)
        {
            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 = AWSConfigs.S3UseSignatureVersion4;
            var region      = AWS4Signer.DetermineRegion(Config);

            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.");
            }

            if (region.Equals(RegionEndpoint.CNNorth1.SystemName, StringComparison.OrdinalIgnoreCase))
            {
                aws4Signing = true;
            }

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

            irequest.Endpoint = DetermineEndpoint(irequest);
            ProcessRequestHandlers(irequest);
            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
            {
                signer.SignRequest(irequest, metrics, immutableCredentials.AccessKey, immutableCredentials.SecretKey);
                authorization = irequest.Headers[S3QueryParameter.Authorization.ToString()];
                authorization = authorization.Substring(authorization.IndexOf(":", StringComparison.Ordinal) + 1);
                authorization = "&Signature=" + AmazonS3Util.UrlEncode(authorization, false);
            }

            Uri    url    = ComposeUrl(irequest, irequest.Endpoint);
            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);
        }