// Note: It's irritating to have to convert from base64 to bytes and then to hex, but we can't change the IBlobSigner implementation // and ServiceAccountCredential.CreateSignature returns base64 anyway. public string Sign(RequestTemplate requestTemplate, Options options, IBlobSigner blobSigner, IClock clock) { var state = new UrlSigningState(requestTemplate, options, blobSigner, clock); var base64Signature = blobSigner.CreateSignature(state._blobToSign); var rawSignature = Convert.FromBase64String(base64Signature); var hexSignature = FormatHex(rawSignature); return(state.GetResult(hexSignature)); }
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 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)); }
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); }
public async Task <string> SignAsync( RequestTemplate requestTemplate, Options options, IBlobSigner blobSigner, IClock clock, CancellationToken cancellationToken) { var state = new UrlSigningState(requestTemplate, options, blobSigner, clock); var base64Signature = await blobSigner.CreateSignatureAsync(state._blobToSign, cancellationToken).ConfigureAwait(false); var rawSignature = Convert.FromBase64String(base64Signature); var hexSignature = FormatHex(rawSignature); return(state.GetResult(hexSignature)); }
public ActionResult Create(RequestTemplate requestTemplate) { if (ModelState.IsValid) { _repositoryFactory.RequestTemplateRepository.EnsurePersistent(requestTemplate); return Redirect("index"); } var viewModel = RequestTemplateViewModel.Create(_repositoryFactory, Site, requestTemplate); return View(viewModel); }
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 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); }
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 async Task ApplyAsync(RequestTemplate requestTemplate) { requestTemplate.Headers.Add("testHeader", new List <string>() { "123" }); var b = await testFeign.Test(new test() { Name = "hzp2", Age = 10 }); await Task.CompletedTask; }
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 Request(RequestTemplate template) { SetDefaults(); NeedsEmail = template.NeedsEmail; DefaultSave = template.DefaultSave; HireType = template.HireType; HardwareType = template.HardwareType; foreach(var dl in template.DistributionLists) { DistributionLists.Add(dl); } foreach(var sf in template.Software) { Software.Add(sf); } foreach(var ns in template.NetworkShares) { NetworkShares.Add(ns);} }
/// <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 ApplyAsync(RequestTemplate requestTemplate) { requestTemplate.Headers.Add("testHeader", new List <string>() { "123" }); requestTemplate.Headers.Add("d", new List <string>() { "d" }); //var f = requestTemplate.HttpContent.ReadAsStringAsync().Result; //var b= await testFeign.Test(new Test() { Name = "hzp2", Age = 10 }); await Task.CompletedTask; }
/// <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)); }
public ActionResult Edit(int id, RequestTemplate requestTemplate) { var templateToEdit = _repositoryFactory.RequestTemplateRepository.GetNullableById(id); if (ModelState.IsValid) { AutoMapper.Mapper.Map(requestTemplate, templateToEdit); _repositoryFactory.RequestTemplateRepository.EnsurePersistent(templateToEdit); return RedirectToAction("Index"); } var viewModel = RequestTemplateViewModel.Create(_repositoryFactory, Site, templateToEdit); return View(viewModel); }
public IHttpActionResult CreateTemplate(RequestTemplate Request) { try { DAL.Models.Template template = new DAL.Models.Template(); template.Wassaya_Template = Request.wassaya; db.Templates.Add(template); db.SaveChanges(); return(Ok(template)); } catch (Exception e) { return(InternalServerError()); } }
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); }
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); }
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 async Task ApplyAsync(RequestTemplate requestTemplate) { var username = configuration.GetSection("username").Value; var password = configuration.GetSection("password").Value; var loginResultDto = await this.loginFeign.LoginAsync(new LoginDto() { Name = username, Password = password }); if (loginResultDto != null) { requestTemplate.Headers.Add("Authorization", new List <string>() { "Bearer " + loginResultDto.Token }); } await Task.CompletedTask; }
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); }
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); }
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); }
public void Intercept(IInvocation invocation) { Console.WriteLine($"Feign start:{invocation.Method.Name}"); try { if (true) { FeignOptions feignOptions = AppConfig.GetSection <FeignOptions>("Feign"); IJsonSerialize jsonSerialize = AutofacUtil.GetService <IJsonSerialize>(); Console.WriteLine($"Feign arguments:{jsonSerialize.ObjectToJSON(invocation.Arguments)}"); var url = RoutingHelper.GetRouteUrlByInterface(feignOptions.Service.FirstOrDefault(p => p.DllName == invocation.TargetType.Assembly.GetName().Name)?.ServiceName, invocation.Method); Console.WriteLine($"Feign url:{url}"); var apiMethodAttribute = ReflectionHelper.GetSingleAttributeOrDefault <ApiMethodAttribute>(invocation.Method); var paramInfo = invocation.Method.GetParameters(); var parameterType = paramInfo.Select(it => it.ParameterType).ToArray(); var returnType = invocation.Method.ReturnType; IClient client = AutofacUtil.GetService <IClient>(); RequestTemplate requestTemplate = new RequestTemplate(apiMethodAttribute.HttpMethod, url); ResponseTemplate responseTemplate = client.ExecuteAsync(requestTemplate, new System.Threading.CancellationToken()).Result; //throw new Exception(); invocation.ReturnValue = invocation.Arguments[0]; } Console.WriteLine($"Feign end:{invocation.Method.Name} | ReturnValue: Success = {invocation.ReturnValue}"); } catch { invocation.Proceed(); Console.WriteLine($"Feign end:{invocation.Method.Name} | ReturnValue: Fallback = {invocation.ReturnValue}"); } }
private static void PutTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null) { Func <Task> expireAction1 = null; Func <Task> expireAction2 = null; Func <Task> expireAction3 = null; Func <Task> expireAction4 = null; fixture.RegisterDelayTest( s_duration, beforeDelay: async duration => { expireAction1 = await PutTestHelper(duration, useContentMD5: false, useContentType: false); expireAction2 = await PutTestHelper(duration, useContentMD5: true, useContentType: false); expireAction3 = await PutTestHelper(duration, useContentMD5: false, useContentType: true); expireAction4 = await PutTestHelper(duration, useContentMD5: true, useContentType: true); }, afterDelay: async() => { await expireAction1(); await expireAction2(); await expireAction3(); await expireAction4(); }, caller); async Task <Func <Task> > PutTestHelper(TimeSpan duration, bool useContentMD5, bool useContentType) { var bucket = fixture.SingleVersionBucket; var name = IdGenerator.FromGuid(); var data = fixture.SmallContent; Func <ByteArrayContent> createPutContent = () => { var putContent = new ByteArrayContent(data); if (useContentMD5) { using (var md5 = MD5.Create()) { putContent.Headers.ContentMD5 = md5.ComputeHash(data); } } if (useContentType) { putContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain"); } return(putContent); }; var content = createPutContent(); var requestTemplate = RequestTemplate .FromBucket(bucket) .WithObjectName(name) .WithHttpMethod(HttpMethod.Put) .WithContentHeaders(content.Headers.ToDictionary(h => h.Key, h => h.Value)); var url = fixture.UrlSigner.Sign(requestTemplate, Options.FromDuration(duration).WithSigningVersion(signingVersion)); // Verify that the URL works initially. var response = await fixture.HttpClient.PutAsync(url, content); await VerifyResponseAsync(response); var result = new MemoryStream(); await fixture.Client.DownloadObjectAsync(bucket, name, result); AssertContentEqual(data, result.ToArray()); // Reset the state and wait until the URL expires. await fixture.Client.DeleteObjectAsync(bucket, name); return(async() => { // Verify that the URL no longer works. content = createPutContent(); response = await fixture.HttpClient.PutAsync(url, content); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); var obj = await fixture.Client.ListObjectsAsync(bucket, name).FirstOrDefaultAsync(o => o.Name == name); Assert.Null(obj); }); } }
/// <summary> /// Asynchronously 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> /// </remarks> /// <param name="requestTemplate">The request template that will be used to generate the signed URL for. Must not be null.</param> /// <param name="options">The options used to generate the signed URL. Must not be null.</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 Task <string> SignAsync(RequestTemplate requestTemplate, Options options, CancellationToken cancellationToken = default) => GetEffectiveSigner(GaxPreconditions.CheckNotNull(options, nameof(options)).SigningVersion).SignAsync( GaxPreconditions.CheckNotNull(requestTemplate, nameof(requestTemplate)), options, _blobSigner, _clock, cancellationToken);
/// <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> /// </remarks> /// <param name="requestTemplate">The request template that will be used to generate the signed URL for. Must not be null.</param> /// <param name="options">The options used to generate the signed URL. Must not be null.</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(RequestTemplate requestTemplate, Options options) => GetEffectiveSigner(GaxPreconditions.CheckNotNull(options, nameof(options)).SigningVersion).Sign( GaxPreconditions.CheckNotNull(requestTemplate, nameof(requestTemplate)), options, _blobSigner, _clock);
private RequestTemplate GetTemplateFromDataRow(DataTableRows row) { try { var t = new RequestTemplate(); t.TemplateID = row.AsInt32("RequestTemplateID"); t.Description = row.AsString("RequestDescription"); t.DocumentType = row.AsString("DocumentType"); t.DocStatus = row.AsString("DocStatus"); t.ProcessType = row.AsString("ProcessType"); t.BusinessType = row.AsString("BusinessType"); t.PsrType = row.AsString("PsrType"); t.TypeMarketAgreementType = row.AsString("TypeMarketAgreementType"); t.ContractMarketAgreementType = row.AsString("ContractMarketAgreementType"); t.AuctionType = row.AsString("AuctionType"); t.AuctionCategory = row.AsString("AuctionCategory"); t.ClassificationSequenceAttributeInstanceComponent = row.AsString("ClassificationSequenceAttributeInstanceComponent"); if (row.AsBool("OutBiddingZoneDomain")) { t.UsedDomains |= RequestTemplate.DomainsInUse.OutBiddingZoneDomain; } if (row.AsBool("BiddingZoneDomain")) { t.UsedDomains |= RequestTemplate.DomainsInUse.BiddingZoneDomain; } if (row.AsBool("InDomain")) { t.UsedDomains |= RequestTemplate.DomainsInUse.InDomain; } if (row.AsBool("OutDomain")) { t.UsedDomains |= RequestTemplate.DomainsInUse.OutDomain; } if (row.AsBool("AcquiringDomain")) { t.UsedDomains |= RequestTemplate.DomainsInUse.AcquiringDomain; } if (row.AsBool("ConnectingDomain")) { t.UsedDomains |= RequestTemplate.DomainsInUse.ConnectingDomain; } if (row.AsBool("ControlAreaDomain")) { t.UsedDomains |= RequestTemplate.DomainsInUse.ControlAreaDomain; } t.InDomainAndOutDomainMustMatch = row.AsBool("InDomainAndOutDomainMustMatch"); if (row.AsBool("TimeInterval")) { t.UsedTimePeriods |= RequestTemplate.TimePeriodsInUse.TimeInterval; } if (row.AsBool("TimeIntervalUpdate")) { t.UsedTimePeriods |= RequestTemplate.TimePeriodsInUse.TimeIntervalUpdate; } if (row.AsBool("PeriodStart")) { t.UsedTimePeriods |= RequestTemplate.TimePeriodsInUse.PeriodStart; } if (row.AsBool("PeriodEnd")) { t.UsedTimePeriods |= RequestTemplate.TimePeriodsInUse.PeriodEnd; } if (row.AsBool("PeriodStartUpdate")) { t.UsedTimePeriods |= RequestTemplate.TimePeriodsInUse.TimeInterval; } if (row.AsBool("PeriodEndUpdate")) { t.UsedTimePeriods |= RequestTemplate.TimePeriodsInUse.TimeInterval; } return(t); } catch (Exception ex) { throw new Exception("Exception occurred while converting template to an object.", ex); } }
private static void PutWithCustomHeadersTest_Common(StorageFixture fixture, SigningVersion signingVersion, [CallerMemberName] string caller = null) { var bucket = fixture.SingleVersionBucket; var name = IdGenerator.FromGuid(); var content = fixture.SmallContent; string url = null; Func <HttpRequestMessage> createRequest = () => { using (var md5 = MD5.Create()) { return(new HttpRequestMessage() { Content = new ByteArrayContent(content) { Headers = { { "Content-MD5", Convert.ToBase64String(md5.ComputeHash(content)) }, { "Content-Type", "text/plain" }, { "x-goog-z-content-foo", "val1" }, { "x-goog-a-content-bar", "val2" }, { "x-goog-foo", new [] { "val3", "val4" } } } }, Method = HttpMethod.Put, Headers = { { "x-goog-foo2", "xy\r\n z" }, { "x-goog-bar", " 12345 " }, { "x-goog-foo2", new [] { "A B C", "def"} } } }); } }; fixture.RegisterDelayTest( s_duration, beforeDelay: async duration => { var request = createRequest(); 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); await VerifyResponseAsync(response); var result = new MemoryStream(); await fixture.Client.DownloadObjectAsync(bucket, name, result); AssertContentEqual(fixture.SmallContent, result.ToArray()); // Reset the state. await fixture.Client.DeleteObjectAsync(bucket, name); }, 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); var obj = await fixture.Client.ListObjectsAsync(bucket, name).FirstOrDefaultAsync(o => o.Name == name); Assert.Null(obj); }, caller); }