2

I want to know that how to generate signurl using google cloud storage classes in .net

I have created string as per the requirement

GET


1388534400
/bucket/objectname

but I now want to sign this url with p12 key and then want to make it url friendly

This library doesn't show specific function for it -> https://developers.google.com/resources/api-libraries/documentation/storage/v1/csharp/latest/annotated.html

So, basically I need .net alternate of Google_Signer_P12 class of php

$signer = new Google_Signer_P12(file_get_contents(__DIR__.'/'."final.p12"), "notasecret");
$signature = $signer->sign($to_sign);
Parag Bhayani
  • 3,280
  • 2
  • 28
  • 52

4 Answers4

8

Now there is a UrlSigner in the pre-release package Google.Cloud.Storage.V1 that can be used to to provide read-only access to existing objects:

// Create a signed URL which can be used to get a specific object for one hour.
UrlSigner urlSigner = UrlSigner.FromServiceAccountCredential(credential);
string url = urlSigner.Sign(
    bucketName,
    objectName,
    TimeSpan.FromHours(1),
    HttpMethod.Get);

Or write-only access to put specific object content into a bucket:

// Create a signed URL which allows the requester to PUT data with the text/plain content-type.
UrlSigner urlSigner = UrlSigner.FromServiceAccountCredential(credential);
var destination = "places/world.txt";
string url = urlSigner.Sign(
    bucketName,
    destination,
    TimeSpan.FromHours(1),
    HttpMethod.Put,
    contentHeaders: new Dictionary<string, IEnumerable<string>> {
        { "Content-Type", new[] { "text/plain" } }
    });

// Upload the content into the bucket using the signed URL.
string source = "world.txt";

ByteArrayContent content;
using (FileStream stream = File.OpenRead(source))
{
    byte[] data = new byte[stream.Length];
    stream.Read(data, 0, data.Length);
    content = new ByteArrayContent(data)
    {
        Headers = { ContentType = new MediaTypeHeaderValue("text/plain") }
    };
}

HttpResponseMessage response = await httpClient.PutAsync(url, content);
moondaisy
  • 4,303
  • 6
  • 41
  • 70
5

I know the question was for P12, but Google lead me here when I was looking to do this for the newer, preferred JSON method. I pieced this together with other samples and sites I found. Hope this help save some time.

    public string GetSignedURL()
    {
        var myObj = "theObject";
        var scopes = new string[] { "https://www.googleapis.com/auth/devstorage.read_write" };
        var myBucket = "theBucket";
        ServiceAccountCredential cred;

        using ( var stream = new FileStream(@"\path to\private-key.json", FileMode.Open, FileAccess.Read) )
        {
            cred = GoogleCredential.FromStream(stream)
                                   .CreateScoped(scopes)
                                   .UnderlyingCredential as ServiceAccountCredential;
        }

        var urlSigner = UrlSigner.FromServiceAccountCredential(cred);

        return urlSigner.Sign(myBucket, myObj, TimeSpan.FromHours(1), HttpMethod.Get);
    }

A list of Scopes can be found here

John Hanley
  • 74,467
  • 6
  • 95
  • 159
Ron Rebennack
  • 2,666
  • 1
  • 22
  • 17
  • Thank you for your example of grabbing the credentials. Many of the other SDK objects just pull from the default application credentials, but the UrlSigner doesn't, which is irritating. – chrisdrobison Sep 13 '22 at 20:41
3

The .NET client doesn't support signing URLs (it is an XML-only API), so you will need to either make a callout to a tool like gsutil or generate an RSA signature internal to your application (Signing and verifying signatures with RSA C#)

Community
  • 1
  • 1
Travis Hobrla
  • 5,411
  • 23
  • 22
0

This is my google signer code, One can make it more dynamic as per their needs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

using System.Web;
using System.Security.Cryptography.X509Certificates;

namespace HHAFSGoogle
{
    static class GoogleSigner
    {
        private static string hashAlgo = "SHA256";
        public static string ServiceAccountEmail
        {
            get
            {
                return "XXXXXXXXXXXXX-YYYYYYYYYYYYYYYYYYYYYYYY@developer.gserviceaccount.com";
            }
        }

        public static string GoogleSecreat
        {
            get
            {
                return "notasecret";
            }
        }

        public static string GoogleBucketDir
        {
            get
            {
                return "MyBucketDirectory";
            }
        }

        public static string GoogleBucketName
        {
            get
            {
                return "MyBucket";
            }
        }

        public static string CertiFilelocation
        {
            get
            {
                return System.Web.HttpContext.Current.Server.MapPath("p12file.p12");
            }
        }

        /// <summary>
        /// Get URL signature
        /// </summary>
        /// <param name="base64EncryptedData"></param>
        /// <param name="certiFilelocation"></param>
        /// <returns></returns>
        public static string GetSignature(string base64EncryptedData, string certiFilelocation)
        {
            X509Certificate2 certificate = new X509Certificate2(certiFilelocation, GoogleSecreat, X509KeyStorageFlags.Exportable);

            RSACryptoServiceProvider csp = (RSACryptoServiceProvider)certificate.PrivateKey;

            RSACryptoServiceProvider privateKey1 = new RSACryptoServiceProvider();
            privateKey1.ImportParameters(csp.ExportParameters(true));

            csp.ImportParameters(privateKey1.ExportParameters(true));

            byte[] data = Encoding.UTF8.GetBytes(base64EncryptedData.Replace("\r", ""));

            byte[] signature = privateKey1.SignData(data, hashAlgo);

            bool isValid = privateKey1.VerifyData(data, hashAlgo, signature);

            if (isValid)
            {
                return Convert.ToBase64String(signature);
            }
            else
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// Get signed URL by Signature
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="method"></param>
        /// <param name="content_type"></param>
        /// <param name="duration"></param>
        /// <returns></returns>
        public static string GetSignedURL(string fileName, string method = "GET", string content_type = "", int duration = 10)
        {
            TimeSpan span = (DateTime.UtcNow.AddMinutes(10) - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc));
            var expires = Math.Round(span.TotalSeconds, 0);

            // Encode filename, so URL characters like %20 for space could be handled properly in signature
            fileName = HttpUtility.UrlPathEncode(fileName);

            // Generate a string to sign
            StringBuilder sbFileParam = new StringBuilder();
            sbFileParam.AppendLine(method);  //Could be GET, PUT, DELETE, POST
            //  /* Content-MD5 */ "\n" .
            sbFileParam.AppendLine();
            sbFileParam.AppendLine(content_type);   // Type of content you would upload e.g. image/jpeg
            sbFileParam.AppendLine(expires.ToString());     // Time when link should expire and shouldn't work longer
            sbFileParam.Append("/" + GoogleBucketName + "/" + fileName);

            var signature = System.Web.HttpContext.Current.Server.UrlEncode(GetSignature(sbFileParam.ToString(), CertiFilelocation));

            return ("https://storage.googleapis.com/MyBucket/" + fileName +
                        "?response-content-disposition=attachment;&GoogleAccessId=" + ServiceAccountEmail +
                        "&Expires=" + expires + "&Signature=" + signature);
        }
    }
}

and to download file call above class to get signed url

GoogleSigner.GetSignedURL(bucketFileName)

and to upload file call above class to get signed url for upload url

GoogleSigner.GetSignedURL(fileName, "PUT", type);
Parag Bhayani
  • 3,280
  • 2
  • 28
  • 52
  • What value should go in the `GoogleSecreat`? I'm getting an exception when I try to create the certificate – moondaisy Jan 23 '17 at 16:35
  • 1
    Which code line exactly you are talking about?, If you are talking about 'notasecret' string than put it as it is i.e. 'notasecret' – Parag Bhayani Jan 24 '17 at 04:22