Google Calendar API and shared hosting issue

I'm trying to use a public Google calendar in a webpage that will need editing functionalities. To that effect, I created the calendar and made it public. I then created a Google service account and the related client id. I also enabled the Calendar API and added the v3 dlls to the project. I downloaded the p12 certificate and that's when the problems start.

The call to Google goes with a X509 cert but the way the .NET framework is built is that it uses a user temp folder. Since it's a shared host for the web server (GoDaddy), I cannot have the app pool identity modified. As a result, I'm getting this error:

System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

when calling:

X509Certificate2 certificate = new X509Certificate2(GoogleOAuth2CertificatePath,
                "notasecret", X509KeyStorageFlags.Exportable);

that cerificate var is then to be used in the google call:

ServiceAccountCredential credential = new ServiceAccountCredential(
                new ServiceAccountCredential.Initializer(GoogleOAuth2EmailAddress)
                {
                    User = GoogleAccount,
                    Scopes = new[] { CalendarService.Scope.Calendar }
                }.FromCertificate(certificate));

... but I never get that far.

Question: is there a way to make the call differently, i.e. not to use a X509 certificate but JSON instead? Or can I get the x509 function to use a general temp location rather than a user location to which I have no access to since I can't change the identity in the app pool?

Since I'm completely stuck, any help would be appreciated.

Jon Skeet
people
quotationmark

One simple option which avoids needing to worry about file locations is to embed the certificate within your assembly. In Visual Studio, right-click on the file and show its properties. Under Build Action, pick "Embedded resource".

You should then be able to load the data with something like this:

// In a helper class somewhere...
private static byte[] LoadResourceContent(Type type, string resourceName)
{
    string fullName = type.Namespace + "." + resourceName;
    using (var stream = type.Assembly.GetManifestResourceStream(fullName)
    {
        var output = new MemoryStream();
        stream.CopyTo(output);
        return output.ToArray();
    }
}

Then:

byte[] data = ResourceHelper.LoadResourceContent(typeof(MyType), "Certificate.p12");
var certificate = new X509Certificate2(data, "notasecret", X509KeyStorageFlags.Exportable);

Here MyType is some type which is in the same folder as your resource.

Note that there are lots of different "web" project types in .NET... depending on the exact project type you're using, you may need to tweak this.

people

See more on this question at Stackoverflow