示例#1
0
        private static void GetBucketTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            var bucket          = fixture.ReadBucket;
            var requestTemplate = RequestTemplate
                                  .FromBucket(bucket);
            string url = null;

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));

                // Verify that the URL works initially.
                var response = await fixture.HttpClient.GetAsync(url);
                var result   = await response.Content.ReadAsStringAsync();
                Assert.True(response.IsSuccessStatusCode, result.ToString());
                var document    = XDocument.Parse(result);
                var ns          = document.Root.GetDefaultNamespace();
                var keys        = document.Root.Elements(ns + "Contents").Select(contents => contents.Element(ns + "Key").Value).ToList();
                var objectNames = await fixture.Client.ListObjectsAsync(bucket, null).Select(o => o.Name).ToListAsync();
                Assert.Equal(objectNames, keys);
            },
                afterDelay: async() =>
            {
                // Verify that the URL no longer works.
                var response = await fixture.HttpClient.GetAsync(url);
                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
            },
                caller);
        }
示例#2
0
        private static void ResumableUploadWithCustomerSuppliedEncryptionKeysTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            var bucket          = fixture.SingleVersionBucket;
            var name            = IdGenerator.FromGuid();
            var requestTemplate = RequestTemplate
                                  .FromBucket(bucket)
                                  .WithObjectName(name)
                                  .WithHttpMethod(ResumableHttpMethod)
                                  .WithRequestHeaders(new Dictionary <string, IEnumerable <string> >
            {
                { "x-goog-encryption-algorithm", new [] { "AES256" } }
            });
            var    content = fixture.SmallContent;
            string url     = null;

            EncryptionKey key = EncryptionKey.Generate();

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));

                // Verify that the URL works initially.
                var uploader = SignedUrlResumableUpload.Create(
                    url,
                    new MemoryStream(content),
                    new ResumableUploadOptions {
                    ModifySessionInitiationRequest = key.ModifyRequest
                });
                var progress = await uploader.UploadAsync();
                Assert.Null(progress.Exception);
                Assert.Equal(UploadStatus.Completed, progress.Status);

                // Make sure the encryption succeeded.
                var downloadedData = new MemoryStream();
                await Assert.ThrowsAsync <GoogleApiException>(
                    () => fixture.Client.DownloadObjectAsync(bucket, name, downloadedData));

                await fixture.Client.DownloadObjectAsync(bucket, name, downloadedData, new DownloadObjectOptions {
                    EncryptionKey = key
                });
                AssertContentEqual(content, downloadedData.ToArray());
            },
                afterDelay: async() =>
            {
                var uploader = SignedUrlResumableUpload.Create(
                    url,
                    new MemoryStream(content),
                    new ResumableUploadOptions {
                    ModifySessionInitiationRequest = key.ModifyRequest
                });

                // Verify that the URL no longer works.
                var progress = await uploader.UploadAsync();
                Assert.Equal(UploadStatus.Failed, progress.Status);
                Assert.IsType <GoogleApiException>(progress.Exception);
            },
                caller);
        }
            public void EncryptionKeyAndHashAreIgnored()
            {
                var signer = UrlSigner.FromServiceAccountCredential(CreateFakeServiceAccountCredential());
                var baseRequestTemplate = RequestTemplate.FromBucket("bucket-name").WithObjectName("object-name");
                var options             = Options
                                          .FromExpiration(DateTimeOffset.UtcNow + TimeSpan.FromDays(1))
                                          .WithSigningVersion(SigningVersion.V2);

                var algorithmTemplate = baseRequestTemplate.WithRequestHeaders(
                    new Dictionary <string, IEnumerable <string> >
                {
                    { EncryptionKey.AlgorithmHeader, new [] { EncryptionKey.AlgorithmValue } }
                });

                var keyAndHashTemplate = baseRequestTemplate.WithRequestHeaders(
                    new Dictionary <string, IEnumerable <string> >
                {
                    { EncryptionKey.AlgorithmHeader, new [] { EncryptionKey.AlgorithmValue } },
                    { EncryptionKey.KeyHeader, new [] { "abc" } },
                    { EncryptionKey.KeyHashHeader, new [] { "def" } }
                });

                var url1 = signer.Sign(algorithmTemplate, options);
                var url2 = signer.Sign(keyAndHashTemplate, options);

                Assert.Equal(url1, url2);

                // However, make sure the encryption algorithm is not ignored.
                var url3 = signer.Sign(baseRequestTemplate, options);

                Assert.NotEqual(url1, url3);
            }
示例#4
0
        private static void HeadWithGetMethodSignedURLTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            Func <HttpRequestMessage> createRequest = null;
            var requestTemplate = RequestTemplate
                                  .FromBucket(fixture.ReadBucket)
                                  .WithObjectName(fixture.SmallObject)
                                  .WithHttpMethod(HttpMethod.Get);
            string url = null;

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                url           = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));
                createRequest = () => new HttpRequestMessage(HttpMethod.Head, url);

                // Verify that the URL works initially.
                var response = await fixture.HttpClient.SendAsync(createRequest());
                await VerifyResponseAsync(response);
            },
                afterDelay: async() =>
            {
                // Verify that the URL no longer works.
                var response = await fixture.HttpClient.SendAsync(createRequest());
                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
            },
                caller);
        }
            public void WithHttpRequestMessage()
            {
                var requestTemplate = RequestTemplate.FromBucket("bucket-name");

                var message = new HttpRequestMessage(HttpMethod.Post, "http://will.be.ignored.com?param1=value1&param2=value2&param1=value3");

                message.Headers.Add("requestHeader", "value1");
                using (MemoryStream stream = new MemoryStream())
                {
                    message.Content = new StreamContent(stream);
                    message.Content.Headers.Add("contentHeader", "value2");
                }
                var newRequestTemplate = requestTemplate.WithHttpRequestMessage(message);

                Assert.NotSame(requestTemplate, newRequestTemplate);
                Assert.Equal(HttpMethod.Post, newRequestTemplate.HttpMethod);
                Assert.Collection(newRequestTemplate.RequestHeaders, pair => AssertHeader(pair, "requestHeader", "value1"));
                Assert.Collection(newRequestTemplate.ContentHeaders, pair => AssertHeader(pair, "contentHeader", "value2"));
                Assert.Equal(2, newRequestTemplate.QueryParameters.Count);
                Assert.Equal(2, newRequestTemplate.QueryParameters["param1"].Count);
                Assert.Equal(1, newRequestTemplate.QueryParameters["param2"].Count);
                Assert.Equal("value2", newRequestTemplate.QueryParameters["param2"].First());

                void AssertHeader(KeyValuePair <string, IReadOnlyCollection <string> > pair, string header, string value)
                {
                    Assert.Equal(header, pair.Key);
                    Assert.Equal(value, pair.Value.Single());
                }
            }
示例#6
0
        public async Task Sign_Validations()
        {
            var signer = UrlSigner.FromBlobSigner(new FakeBlobSigner());

            Assert.Throws <ArgumentNullException>(() => signer.Sign(null, null));
            await Assert.ThrowsAsync <ArgumentNullException>(() => signer.SignAsync(null, null));

            Assert.Throws <ArgumentNullException>(() => signer.Sign(null, Options.FromDuration(TimeSpan.Zero)));
            await Assert.ThrowsAsync <ArgumentNullException>(() => signer.SignAsync(null, Options.FromDuration(TimeSpan.Zero)));

            Assert.Throws <ArgumentNullException>(() => signer.Sign(RequestTemplate.FromBucket("bucket"), null));
            await Assert.ThrowsAsync <ArgumentNullException>(() => signer.SignAsync(RequestTemplate.FromBucket("bucket"), null));

            // Bucket names cannot be null or contain uppercase letters (among other rules).
            // Make sure we verify the presence and format of the bucket name in all overloads.
            Assert.Throws <ArgumentNullException>(() => signer.Sign(null, "objectName", TimeSpan.FromDays(1)));
            await Assert.ThrowsAsync <ArgumentNullException>(() => signer.SignAsync(null, "objectName", TimeSpan.FromDays(1)));

            Assert.Throws <ArgumentException>(() => signer.Sign("BUCKETNAME", "objectName", TimeSpan.FromDays(1)));
            await Assert.ThrowsAsync <ArgumentException>(() => signer.SignAsync("BUCKETNAME", "objectName", TimeSpan.FromDays(1)));

            // Make sure exceptions are not thrown for things which may be null or uppercase.
            signer.Sign("bucketname", null, TimeSpan.FromDays(1), null, null);
            await signer.SignAsync("bucketname", null, TimeSpan.FromDays(1), null, null);
        }
        public override string SavePrivate(string domain, string path, System.IO.Stream stream, DateTime expires)
        {
            using var storage = GetStorage();

            var objectKey = MakePath(domain, path);
            var buffered  = TempStream.GetBuffered(stream);

            var uploadObjectOptions = new UploadObjectOptions
            {
                PredefinedAcl = PredefinedObjectAcl.BucketOwnerFullControl
            };

            buffered.Position = 0;

            var uploaded = storage.UploadObject(_bucket, MakePath(domain, path), "application/octet-stream", buffered, uploadObjectOptions, null);

            uploaded.CacheControl       = string.Format("public, maxage={0}", (int)TimeSpan.FromDays(5).TotalSeconds);
            uploaded.ContentDisposition = "attachment";

            if (uploaded.Metadata == null)
            {
                uploaded.Metadata = new Dictionary <string, string>();
            }

            uploaded.Metadata["Expires"] = DateTime.UtcNow.Add(TimeSpan.FromDays(5)).ToString("R");
            uploaded.Metadata.Add("private-expire", expires.ToFileTimeUtc().ToString(CultureInfo.InvariantCulture));

            storage.UpdateObject(uploaded);

            using var mStream = new MemoryStream(Encoding.UTF8.GetBytes(_json ?? ""));
            var preSignedURL = FromServiceAccountData(mStream).Sign(RequestTemplate.FromBucket(_bucket).WithObjectName(MakePath(domain, path)), UrlSigner.Options.FromExpiration(expires));

            //TODO: CNAME!
            return(preSignedURL);
        }
示例#8
0
        private static void GetObjectWithSpacesTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            var bucket          = fixture.SingleVersionBucket;
            var name            = IdGenerator.FromGuid() + " with spaces";
            var requestTemplate = RequestTemplate
                                  .FromBucket(bucket)
                                  .WithObjectName(name);
            var    content = fixture.SmallContent;
            string url     = null;

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                fixture.Client.UploadObject(bucket, name, null, new MemoryStream(content));
                url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));

                // Verify that the URL works initially.
                var response = await fixture.HttpClient.GetAsync(url);
                await VerifyResponseAsync(response);
                var result = await response.Content.ReadAsByteArrayAsync();
                AssertContentEqual(content, result);
            },
                afterDelay: async() =>
            {
                // Verify that the URL no longer works.
                var response = await fixture.HttpClient.GetAsync(url);
                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
            },
                caller);
        }
示例#9
0
        private static void GetTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            string url = null;

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                url = fixture.UrlSigner.Sign(
                    RequestTemplate.FromBucket(fixture.ReadBucket).WithObjectName(fixture.SmallObject),
                    Options.FromDuration(duration).WithSigningVersion(signingVersion));

                // Verify that the URL works initially.
                var response = await fixture.HttpClient.GetAsync(url);
                var result   = await response.Content.ReadAsByteArrayAsync();
                AssertContentEqual(fixture.SmallContent, result);
            },
                afterDelay: async() =>
            {
                // Verify that the URL no longer works.
                var response = await fixture.HttpClient.GetAsync(url);
                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
            },
                caller);
        }
示例#10
0
        private static void PutWithCustomerSuppliedEncryptionKeysTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            var    bucket  = fixture.SingleVersionBucket;
            var    name    = IdGenerator.FromGuid();
            var    content = fixture.SmallContent;
            string url     = null;

            EncryptionKey key = EncryptionKey.Generate();

            Func <HttpRequestMessage> createPutRequest = () =>
            {
                var request = new HttpRequestMessage
                {
                    Method  = HttpMethod.Put,
                    Content = new ByteArrayContent(content)
                };
                key.ModifyRequest(request);
                return(request);
            };

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                var request         = createPutRequest();
                var requestTemplate = RequestTemplate
                                      .FromBucket(bucket)
                                      .WithObjectName(name)
                                      .WithHttpRequestMessage(request);
                url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));

                // Verify that the URL works initially.
                request.RequestUri = new Uri(url);
                var response       = await fixture.HttpClient.SendAsync(request);
                await VerifyResponseAsync(response);

                // Make sure the encryption succeeded.
                var downloadedContent = new MemoryStream();
                await Assert.ThrowsAsync <GoogleApiException>(
                    () => fixture.Client.DownloadObjectAsync(bucket, name, downloadedContent));

                await fixture.Client.DownloadObjectAsync(bucket, name, downloadedContent, new DownloadObjectOptions {
                    EncryptionKey = key
                });
                AssertContentEqual(content, downloadedContent.ToArray());
            },
                afterDelay: async() =>
            {
                // Verify that the URL no longer works.
                var request        = createPutRequest();
                request.RequestUri = new Uri(url);
                var response       = await fixture.HttpClient.SendAsync(request);
                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                // Cleanup
                await fixture.Client.DeleteObjectAsync(bucket, name);
            },
                caller);
        }
            public void WithHttpMethod()
            {
                var requestTemplate = RequestTemplate.FromBucket("bucket-name");

                var newRequestTemplate = requestTemplate.WithHttpMethod(HttpMethod.Post);

                Assert.NotSame(requestTemplate, newRequestTemplate);
                Assert.Equal(HttpMethod.Post, newRequestTemplate.HttpMethod);
            }
            public void WithBucket()
            {
                var requestTemplate = RequestTemplate.FromBucket("bucket-name");

                var newRequestTemplate = requestTemplate.WithBucket("another-bucket");

                Assert.NotSame(requestTemplate, newRequestTemplate);
                Assert.Equal("another-bucket", newRequestTemplate.Bucket);
            }
            public void WithObjectName()
            {
                var requestTemplate = RequestTemplate.FromBucket("bucket-name");

                var newRequestTemplate = requestTemplate.WithObjectName("object-name");

                Assert.NotSame(requestTemplate, newRequestTemplate);
                Assert.Equal("object-name", newRequestTemplate.ObjectName);
            }
示例#14
0
            public void ExpiryValidation_Invalid(int seconds)
            {
                var signer = UrlSigner
                             .FromServiceAccountCredential(StorageConformanceTestData.TestCredential)
                             .WithClock(new FakeClock());
                var requestTemplate = RequestTemplate.FromBucket("bucket").WithObjectName("object");
                var options         = Options.FromDuration(TimeSpan.FromSeconds(seconds)).WithSigningVersion(SigningVersion.V4);

                Assert.Throws <ArgumentOutOfRangeException>(() => signer.Sign(requestTemplate, options));
            }
        private static void GetWithCustomerSuppliedEncryptionKeysTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            var    bucket  = fixture.SingleVersionBucket;
            var    name    = IdGenerator.FromGuid();
            var    content = fixture.SmallContent;
            string url     = null;

            EncryptionKey key = EncryptionKey.Generate();

            Func <HttpRequestMessage> createGetRequest = () =>
            {
                var request = new HttpRequestMessage {
                    Method = HttpMethod.Get
                };
                key.ModifyRequest(request);
                return(request);
            };

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                var encryptingClient = StorageClient.Create(encryptionKey: key);
                encryptingClient.UploadObject(bucket, name, "application/octet-stream", new MemoryStream(content));

                // We don't need to specify the encryption key headers explicitly in the signer template.
                // The request message we are using in the template already has them set
                // (by key.ModifyRequest(request)) and the signer will extract them from there.
                var request         = createGetRequest();
                var requestTemplate = RequestTemplate
                                      .FromBucket(bucket)
                                      .WithObjectName(name)
                                      .WithHttpRequestMessage(request);
                url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));
                request.RequestUri = new Uri(url);

                // Verify that the URL works initially.
                var response = await fixture.HttpClient.SendAsync(request);
                var result   = await response.Content.ReadAsByteArrayAsync();
                AssertContentEqual(content, result);
            },
                afterDelay: async() =>
            {
                // Verify that the URL no longer works.
                var request        = createGetRequest();
                request.RequestUri = new Uri(url);
                var response       = await fixture.HttpClient.SendAsync(request);
                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);

                // Cleanup
                await fixture.Client.DeleteObjectAsync(bucket, name);
            },
                caller);
        }
            public void FromBucket()
            {
                var requestTemplate = RequestTemplate.FromBucket("bucket-name");

                Assert.Equal("bucket-name", requestTemplate.Bucket);
                Assert.Null(requestTemplate.ObjectName);
                Assert.Empty(requestTemplate.RequestHeaders);
                Assert.Empty(requestTemplate.ContentHeaders);
                Assert.Empty(requestTemplate.QueryParameters);
                Assert.Equal(HttpMethod.Get, requestTemplate.HttpMethod);
            }
示例#17
0
            public void ExpiryValidation_Exactly1Week()
            {
                var signer = UrlSigner
                             .FromServiceAccountCredential(StorageConformanceTestData.TestCredential)
                             .WithClock(new FakeClock());

                var requestTemplate = RequestTemplate.FromBucket("bucket").WithObjectName("object");
                var options         = Options.FromDuration(TimeSpan.FromDays(7)).WithSigningVersion(SigningVersion.V4);

                // Just testing that no exception is thrown.
                signer.Sign(requestTemplate, options);
            }
            public void BlobSignerSync()
            {
                var signer = UrlSigner.FromBlobSigner(new FakeBlobSigner());
                var baseRequestTemplate = RequestTemplate.FromBucket("bucket-name").WithObjectName("object-name");
                var options             = Options
                                          .FromExpiration(new DateTime(1970, 1, 1, 0, 0, 30, DateTimeKind.Utc))
                                          .WithSigningVersion(SigningVersion.V2);

                var url = signer.Sign(baseRequestTemplate, options);

                Assert.Equal("https://storage.googleapis.com/bucket-name/object-name?GoogleAccessId=FakeId&Expires=30&Signature=AAA%3D", url);
            }
示例#19
0
        /// <summary>
        /// Creates a signed URL which can be used to provide limited access to specific buckets and objects to anyone
        /// in possession of the URL, regardless of whether they have a Google account.
        /// </summary>
        /// <remarks>
        /// <para>
        /// When a <see cref="UrlSigner"/> is created with a service account credential, the signing can be performed
        /// with no network access. When it is created with an implementation of <see cref="IBlobSigner"/>, that may require
        /// network access or other IO. In that case, one of the asynchronous methods should be used when the caller is
        /// in a context that should not block.
        /// </para>
        /// <para>
        /// See https://cloud.google.com/storage/docs/access-control/signed-urls for more information on signed URLs.
        /// </para>
        /// <para>
        /// Note that when GET is specified as the <paramref name="httpMethod"/> (or it is null, in which case GET is
        /// used), both GET and HEAD requests can be made with the created signed URL.
        /// </para>
        /// </remarks>
        /// <param name="bucket">The name of the bucket. Must not be null.</param>
        /// <param name="objectName">The name of the object within the bucket. May be null, in which case the signed URL
        /// will refer to the bucket instead of an object.</param>
        /// <param name="duration">The length of time for which the signed URL should remain usable.</param>
        /// <param name="httpMethod">The HTTP request method for which the signed URL is allowed to be used. May be null,
        /// in which case GET will be used.</param>
        /// <param name="signingVersion">The signing version to use to generate the signed URL. May be null, in which case
        /// <see cref="SigningVersion.Default"/> will be used.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns> A task representing the asynchronous operation, with a result returning the
        /// signed URL which can be used to provide access to a bucket or object for a limited amount of time.</returns>
        public async Task <string> SignAsync(string bucket, string objectName, TimeSpan duration, HttpMethod httpMethod = null, SigningVersion?signingVersion = null, CancellationToken cancellationToken = default)
        {
            var template = RequestTemplate
                           .FromBucket(bucket)
                           .WithObjectName(objectName)
                           .WithHttpMethod(httpMethod);
            var options = Options.FromDuration(duration);

            if (signingVersion.HasValue)
            {
                options = options.WithSigningVersion(signingVersion.Value);
            }
            return(await SignAsync(template, options, cancellationToken).ConfigureAwait(false));
        }
示例#20
0
        /// <summary>
        /// Creates a signed URL which can be used to provide limited access to specific buckets and objects to anyone
        /// in possession of the URL, regardless of whether they have a Google account.
        /// </summary>
        /// <remarks>
        /// <para>
        /// When a <see cref="UrlSigner"/> is created with a service account credential, the signing can be performed
        /// with no network access. When it is created with an implementation of <see cref="IBlobSigner"/>, that may require
        /// network access or other IO. In that case, one of the asynchronous methods should be used when the caller is
        /// in a context that should not block.
        /// </para>
        /// <para>
        /// See https://cloud.google.com/storage/docs/access-control/signed-urls for more information on signed URLs.
        /// </para>
        /// <para>
        /// Note that when GET is specified as the <paramref name="httpMethod"/> (or it is null, in which case GET is
        /// used), both GET and HEAD requests can be made with the created signed URL.
        /// </para>
        /// </remarks>
        /// <param name="bucket">The name of the bucket. Must not be null.</param>
        /// <param name="objectName">The name of the object within the bucket. May be null, in which case the signed URL
        /// will refer to the bucket instead of an object.</param>
        /// <param name="duration">The length of time for which the signed URL should remain usable.</param>
        /// <param name="httpMethod">The HTTP request method for which the signed URL is allowed to be used. May be null,
        /// in which case GET will be used.</param>
        /// <param name="signingVersion">The signing version to use to generate the signed URL. May be null, in which case
        /// <see cref="SigningVersion.Default"/> will be used.</param>
        /// <returns>The signed URL which can be used to provide access to a bucket or object for a limited amount of time.</returns>
        public string Sign(string bucket, string objectName, TimeSpan duration, HttpMethod httpMethod = null, SigningVersion?signingVersion = null)
        {
            var template = RequestTemplate
                           .FromBucket(bucket)
                           .WithObjectName(objectName)
                           .WithHttpMethod(httpMethod);
            var options = Options.FromDuration(duration);

            if (signingVersion.HasValue)
            {
                options = options.WithSigningVersion(signingVersion.Value);
            }
            return(Sign(template, options));
        }
            public async Task ThrowsIfBucketBoundHostSpecified()
            {
                var signer          = UrlSigner.FromServiceAccountCredential(CreateFakeServiceAccountCredential());
                var requestTemplate = RequestTemplate
                                      .FromBucket("bucket-name")
                                      .WithObjectName("object-name");
                var options = Options
                              .FromExpiration(DateTimeOffset.UtcNow + TimeSpan.FromDays(1))
                              .WithSigningVersion(SigningVersion.V2)
                              .WithBucketBoundHostname("my.bucket.domain");

                Assert.Throws <ArgumentOutOfRangeException>(() => signer.Sign(requestTemplate, options));
                await Assert.ThrowsAsync <ArgumentOutOfRangeException>(() => signer.SignAsync(requestTemplate, options));
            }
            public async Task ThrowsIfQueryParametersSpecified()
            {
                var signer          = UrlSigner.FromServiceAccountCredential(CreateFakeServiceAccountCredential());
                var requestTemplate = RequestTemplate
                                      .FromBucket("bucket-name")
                                      .WithObjectName("object-name")
                                      .WithQueryParameters(
                    new Dictionary <string, IEnumerable <string> >
                {
                    { "param1", new string[] { "value1" } }
                });
                var options = Options
                              .FromExpiration(DateTimeOffset.UtcNow + TimeSpan.FromDays(1))
                              .WithSigningVersion(SigningVersion.V2);

                Assert.Throws <ArgumentException>(() => signer.Sign(requestTemplate, options));
                await Assert.ThrowsAsync <ArgumentException>(() => signer.SignAsync(requestTemplate, options));
            }
        public void SigningTest(SigningV4Test test)
        {
            var timestamp = test.Timestamp.ToDateTime();
            var clock     = new FakeClock(timestamp);
            var signer    = UrlSigner
                            .FromServiceAccountCredential(StorageConformanceTestData.TestCredential)
                            .WithClock(clock);

            var requestTemplate = RequestTemplate
                                  .FromBucket(test.Bucket)
                                  .WithObjectName(test.Object)
                                  .WithHttpMethod(s_methods[test.Method])
                                  .WithRequestHeaders(test.Headers.ToDictionary(kvp => kvp.Key, kvp => Enumerable.Repeat(kvp.Value, 1)))
                                  .WithQueryParameters(test.QueryParameters.ToDictionary(kvp => kvp.Key, kvp => Enumerable.Repeat(kvp.Value, 1)));
            var options = Options
                          .FromDuration(TimeSpan.FromSeconds(test.Expiration))
                          .WithSigningVersion(SigningVersion.V4)
                          .WithScheme(test.Scheme);

            switch (test.UrlStyle)
            {
            case UrlStyle.VirtualHostedStyle:
                options = options.WithUrlStyle(UrlSigner.UrlStyle.VirtualHostedStyle);
                break;

            case UrlStyle.BucketBoundHostname:
                options = options.WithBucketBoundHostname(test.BucketBoundHostname);
                break;

            default:
                break;
            }

            var actualUrl = signer.Sign(requestTemplate, options);

            // We almost always want the complete URL afterwards, which xUnit doesn't give us.
            if (test.ExpectedUrl != actualUrl)
            {
                FileLogger.Log($"{test.Description} failure");
                FileLogger.Log($"Expected: {test.ExpectedUrl}");
                FileLogger.Log($"Actual: {actualUrl}");
            }
            Assert.Equal(test.ExpectedUrl, actualUrl);
        }
示例#24
0
        private static void ResumableUploadTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            var bucket          = fixture.SingleVersionBucket;
            var name            = IdGenerator.FromGuid();
            var requestTemplate = RequestTemplate
                                  .FromBucket(bucket)
                                  .WithObjectName(name)
                                  .WithHttpMethod(ResumableHttpMethod);
            var    content = fixture.SmallContent;
            string url     = null;

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));

                // Verify that the URL works initially.
                var uploader = SignedUrlResumableUpload.Create(url, new MemoryStream(content));
                var progress = await uploader.UploadAsync();
                Assert.Equal(UploadStatus.Completed, progress.Status);

                var result = new MemoryStream();
                await fixture.Client.DownloadObjectAsync(bucket, name, result);
                AssertContentEqual(content, result.ToArray());

                // Reset the state.
                await fixture.Client.DeleteObjectAsync(bucket, name);
            },
                afterDelay: async() =>
            {
                var uploader = SignedUrlResumableUpload.Create(url, new MemoryStream(content));

                // Verify that the URL no longer works.
                var progress = await uploader.UploadAsync();
                Assert.Equal(UploadStatus.Failed, progress.Status);
                Assert.IsType <GoogleApiException>(progress.Exception);

                var obj = await fixture.Client.ListObjectsAsync(bucket, name).FirstOrDefaultAsync(o => o.Name == name);
                Assert.Null(obj);
            },
                caller);
        }
示例#25
0
        private static void GetWithCustomHeadersTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            string url = null;

            Func <HttpRequestMessage> createRequest = () => new HttpRequestMessage()
            {
                Method  = HttpMethod.Get,
                Headers =
                {
                    { "x-goog-foo", "xy\r\n z"   },
                    { "x-goog-bar", "  12345   " },
                    { "x-goog-foo", new [] { "A B  C", "def"} }
                }
            };

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                var request         = createRequest();
                var requestTemplate = RequestTemplate
                                      .FromBucket(fixture.ReadBucket)
                                      .WithObjectName(fixture.SmallObject)
                                      .WithHttpRequestMessage(request);
                url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));
                request.RequestUri = new Uri(url);

                // Verify that the URL works initially.
                var response = await fixture.HttpClient.SendAsync(request);
                var result   = await response.Content.ReadAsByteArrayAsync();
                AssertContentEqual(fixture.SmallContent, result);
            },
                afterDelay: async() =>
            {
                // Verify that the URL no longer works.
                var request        = createRequest();
                request.RequestUri = new Uri(url);
                var response       = await fixture.HttpClient.SendAsync(request);
                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
            },
                caller);
        }
            public void WithContentHeaders()
            {
                var requestTemplate = RequestTemplate.FromBucket("bucket-name");

                var headers = new Dictionary <string, IEnumerable <string> >
                {
                    { "header1", new List <string> {
                          "value1", "value2"
                      } },
                    { "header2", new List <string> {
                          "value3"
                      } }
                };
                var newRequestTemplate = requestTemplate.WithContentHeaders(headers);

                var expectedHeaders = ToExpectedEntries(headers);

                Assert.NotSame(requestTemplate, newRequestTemplate);
                Assert.Equal(expectedHeaders, newRequestTemplate.ContentHeaders);
            }
            public void WithQueryParameters()
            {
                var requestTemplate = RequestTemplate.FromBucket("bucket-name");

                var queryParameters = new Dictionary <string, IEnumerable <string> >
                {
                    { "query1", new List <string> {
                          "value1", "value2"
                      } },
                    { "query2", new List <string> {
                          "value3"
                      } }
                };
                var newRequestTemplate = requestTemplate.WithQueryParameters(queryParameters);

                var expectedParameters = ToExpectedEntries(queryParameters);

                Assert.NotSame(requestTemplate, newRequestTemplate);
                Assert.Equal(expectedParameters, newRequestTemplate.QueryParameters);
            }
示例#28
0
        private static void DeleteTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null)
        {
            var bucket          = fixture.SingleVersionBucket;
            var name            = IdGenerator.FromGuid();
            var requestTemplate = RequestTemplate
                                  .FromBucket(bucket)
                                  .WithObjectName(name)
                                  .WithHttpMethod(HttpMethod.Delete);
            string url = null;

            fixture.RegisterDelayTest(
                s_duration,
                beforeDelay: async duration =>
            {
                url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion));

                // Upload an object which can be deleted with the URL.
                await fixture.Client.UploadObjectAsync(bucket, name, "", new MemoryStream(fixture.SmallContent));

                // Verify that the URL works initially.
                var response = await fixture.HttpClient.DeleteAsync(url);
                await VerifyResponseAsync(response);
                var obj = await fixture.Client.ListObjectsAsync(bucket, name).FirstOrDefaultAsync(o => o.Name == name);
                Assert.Null(obj);

                // Restore the object.
                await fixture.Client.UploadObjectAsync(bucket, name, "", new MemoryStream(fixture.SmallContent));
            },
                afterDelay: async() =>
            {
                // Verify that the URL no longer works.
                var response = await fixture.HttpClient.DeleteAsync(url);
                Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
                var obj = await fixture.Client.ListObjectsAsync(bucket, name).FirstOrDefaultAsync(o => o.Name == name);
                Assert.NotNull(obj);

                // Cleanup
                await fixture.Client.DeleteObjectAsync(bucket, name);
            },
                caller);
        }
示例#29
0
            public void SampleRequest()
            {
                var clock           = new FakeClock(new DateTime(2018, 11, 19, 5, 56, 54, DateTimeKind.Utc));
                var requestTemplate = RequestTemplate.FromBucket("jessefrank2").WithObjectName("kitten.png");
                var options         = Options.FromDuration(TimeSpan.FromHours(1)).WithSigningVersion(SigningVersion.V4);
                var serviceAccount  = CreateFakeServiceAccountCredential("*****@*****.**");
                var signer          = UrlSigner
                                      .FromServiceAccountCredential(serviceAccount)
                                      .WithClock(clock);

                var uriString  = signer.Sign(requestTemplate, options);
                var parameters = ExtractQueryParameters(uriString);

                Assert.Equal("GOOG4-RSA-SHA256", parameters["X-Goog-Algorithm"]);
                Assert.Equal("test-account%40spec-test-ruby-samples.iam.gserviceaccount.com%2F20181119%2Fauto%2Fstorage%2Fgoog4_request", parameters["X-Goog-Credential"]);
                Assert.Equal("20181119T055654Z", parameters["X-Goog-Date"]);
                Assert.Equal("3600", parameters["X-Goog-Expires"]);
                Assert.Equal("host", parameters["X-Goog-SignedHeaders"]);

                // No check for the exact signature.
            }
            public void ResumableEquivalentToPostWithStartHeader()
            {
                var signer = UrlSigner.FromServiceAccountCredential(CreateFakeServiceAccountCredential());
                var baseRequestTemplate = RequestTemplate.FromBucket("bucket-name").WithObjectName("object-name");
                var options             = Options
                                          .FromExpiration(DateTimeOffset.UtcNow + TimeSpan.FromDays(1))
                                          .WithSigningVersion(SigningVersion.V2);

                var resumableTemplate   = baseRequestTemplate.WithHttpMethod(ResumableHttpMethod);
                var startHeaderTemplate = baseRequestTemplate
                                          .WithHttpMethod(HttpMethod.Post)
                                          .WithRequestHeaders(
                    new Dictionary <string, IEnumerable <string> >
                {
                    { "x-goog-resumable", new[] { "start" } }
                });

                var url1 = signer.Sign(resumableTemplate, options);
                var url2 = signer.Sign(startHeaderTemplate, options);

                Assert.Equal(url1, url2);
            }