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); } }
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; } }
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))); }
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); }
/// <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; } }
/// /// <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); }
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); }
/// <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); }
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)); }
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}"); }
/// <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()); }
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)); }
/// <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); }
/// <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); }
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); } }
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); } }
/// <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); }
/// <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); } } }
/// <summary> /// Converts instance into a ISO8601 basic date format of 'yyyyMMdd'. /// </summary> public static string ToIso8601BasicDate(this DateTime self) => AWS4Signer.FormatDateTime(self, AWSSDKUtils.ISO8601BasicDateFormat);
public static string GetAWSSignatureKey(String key, String dateStamp, String regionName, String serviceName) { return(StringUtils.ToHexString(AWS4Signer.ComposeSigningKey(key, regionName, dateStamp, serviceName)).Trim().ToLower()); }
/// <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); }
/// <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); }