From ad238518510923abdd7f3004c76392fe8d218537 Mon Sep 17 00:00:00 2001 From: poornas Date: Sun, 18 Mar 2018 01:11:29 -0700 Subject: [PATCH] Fix presign operations to honor request params (#216) --- Minio.Functional.Tests/FunctionalTest.cs | 9 +++++++-- Minio/V4Authenticator.cs | 11 +++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Minio.Functional.Tests/FunctionalTest.cs b/Minio.Functional.Tests/FunctionalTest.cs index 23b9b00eb..cdc674b6d 100644 --- a/Minio.Functional.Tests/FunctionalTest.cs +++ b/Minio.Functional.Tests/FunctionalTest.cs @@ -233,7 +233,6 @@ public static void Main(string[] args) // Test Presigned Get/Put operations PresignedGetObject_Test1(minioClient).Wait(); - PresignedGetObject_Test1(minioClient).Wait(); PresignedGetObject_Test2(minioClient).Wait(); PresignedGetObject_Test3(minioClient).Wait(); PresignedPutObject_Test1(minioClient).Wait(); @@ -1779,7 +1778,7 @@ private async static Task PresignedGetObject_Test3(MinioClient minio) {"bucketName", bucketName}, {"objectName", objectName}, {"expiresInt", expiresInt.ToString()}, - {"reqParams", "response-content-type:application/json"} + {"reqParams", "response-content-type:application/json,response-content-disposition:attachment;filename=MyDocument.json;"} }; try { @@ -1792,15 +1791,21 @@ await minio.PutObjectAsync(bucketName, ObjectStat stats = await minio.StatObjectAsync(bucketName, objectName); Dictionary reqParams = new Dictionary(); reqParams["response-content-type"] = "application/json"; + reqParams["response-content-disposition"] = "attachment;filename=MyDocument.json;"; string presigned_url = await minio.PresignedGetObjectAsync(bucketName, objectName, 1000, reqParams); WebRequest httpRequest = WebRequest.Create(presigned_url); var response = (HttpWebResponse)(await Task.Factory.FromAsync(httpRequest.BeginGetResponse, httpRequest.EndGetResponse, null)); + Assert.AreEqual(response.ContentType,reqParams["response-content-type"]); + Assert.AreEqual(response.Headers["Content-Disposition"],"attachment;filename=MyDocument.json;"); + Assert.AreEqual(response.Headers["Content-Type"],"application/json"); + Assert.AreEqual(response.Headers["Content-Length"],stats.Size.ToString()); Stream stream = response.GetResponseStream(); var fileStream = File.Create(downloadFile); stream.CopyTo(fileStream); fileStream.Dispose(); FileInfo writtenInfo = new FileInfo(downloadFile); long file_read_size = writtenInfo.Length; + // Compare size of file downloaded with presigned curl request and actual object size on server Assert.AreEqual(file_read_size, stats.Size); diff --git a/Minio/V4Authenticator.cs b/Minio/V4Authenticator.cs index 1e8ae5dbf..b78092c9e 100644 --- a/Minio/V4Authenticator.cs +++ b/Minio/V4Authenticator.cs @@ -278,7 +278,9 @@ public string PresignURL(IRestClient client, IRestRequest request, int expires) + "&"; requestQuery += "X-Amz-SignedHeaders=host"; - string canonicalRequest = GetPresignCanonicalRequest(client, request, requestQuery); + SortedDictionary headersToSign = GetHeadersToSign(request); + string canonicalRequest = GetPresignCanonicalRequest(client, request, requestQuery, headersToSign); + string headers = string.Join("&", headersToSign.Select(p => p.Key + "=" + utils.UrlEncode(p.Value))); byte[] canonicalRequestBytes = System.Text.Encoding.UTF8.GetBytes(canonicalRequest); string canonicalRequestHash = BytesToHex(ComputeSha256(canonicalRequestBytes)); string stringToSign = GetStringToSign(this.Region, signingDate, canonicalRequestHash); @@ -288,7 +290,7 @@ public string PresignURL(IRestClient client, IRestRequest request, int expires) string signature = BytesToHex(signatureBytes); // Return presigned url. - return client.BaseUrl + path + "?" + requestQuery + "&X-Amz-Signature=" + signature; + return client.BaseUrl + path + "?" + requestQuery + "&" + headers + "&X-Amz-Signature=" + signature; } /// @@ -298,7 +300,7 @@ public string PresignURL(IRestClient client, IRestRequest request, int expires) /// Instantiated request object /// Additional request query params /// Presigned canonical request - private string GetPresignCanonicalRequest(IRestClient client, IRestRequest request, string requestQuery) + private string GetPresignCanonicalRequest(IRestClient client, IRestRequest request, string requestQuery, SortedDictionary headersToSign) { LinkedList canonicalStringList = new LinkedList(); // METHOD @@ -310,7 +312,8 @@ private string GetPresignCanonicalRequest(IRestClient client, IRestRequest reque path = "/" + path; } canonicalStringList.AddLast(path); - canonicalStringList.AddLast(requestQuery); + String query = headersToSign.Aggregate(requestQuery, (pv, cv) => $"{pv}&{utils.UrlEncode((string)cv.Key)}={utils.UrlEncode((string)cv.Value)}"); + canonicalStringList.AddLast(query); if (client.BaseUrl.Port > 0 && (client.BaseUrl.Port != 80 && client.BaseUrl.Port != 443)) { canonicalStringList.AddLast("host:" + client.BaseUrl.Host + ":" + client.BaseUrl.Port);