42

I'm using the Google Analytics API and I followed this SO question to set up the OAuth: https://stackoverflow.com/a/13013265/1299363

Here is my OAuth code:

public void SetupOAuth ()
{
    var Cert = new X509Certificate2(
        PrivateKeyPath, 
        "notasecret", 
        X509KeyStorageFlags.Exportable);
    var Provider = new AssertionFlowClient(GoogleAuthenticationServer.Description, Cert)
    {
        ServiceAccountId = ServiceAccountUser,
        Scope = ApiUrl + "analytics.readonly"
    };
    var Auth = new OAuth2Authenticator<AssertionFlowClient>(Provider, AssertionFlowClient.GetState);
    Service = new AnalyticsService(Auth);
}

PrivateKeyPath is the path of the private key file provided by Google API Console. This works perfectly on my local machine, but when I push it up to our test server I get

System.Security.Cryptography.CryptographicException: An internal error occurred.

with the following stack trace (irrelevant parts removed):

System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) +33
System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromFile(String fileName, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx) +0
System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromFile(String fileName, Object password, X509KeyStorageFlags keyStorageFlags) +237
System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags) +140
Metrics.APIs.GoogleAnalytics.SetupOAuth() in <removed>\Metrics\APIs\GoogleAnalytics.cs:36
Metrics.APIs.GoogleAnalytics..ctor(String PrivateKeyPath) in <removed>\Metrics\APIs\GoogleAnalytics.cs:31

So it appears as if it is having trouble loading the file. I've checked the PrivateKeyPath that is passed in and it is pointing to the correct location.

Any ideas? I don't know if this is an issue with the server, the file, the code or what.

Community
  • 1
  • 1
wholol
  • 918
  • 2
  • 9
  • 22

5 Answers5

84

One of things that comes to my mind is the identity of your app pool, make sure that the Load user profile is turned on otherwise the crypto subsystem does not work.

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
30

I'm loading my p12 file with

new X509Certificate2(
HostingEnvironment.MapPath(@"~/App_Data/GoogleAnalytics-privatekey.p12"), ....

I actually got a FileNotFoundException even though File.Exists(filename) returned true.

As @Wiktor Zychla said it's as simple as enabling Load User Profile

Here's an image of the setting that needs changing

Just right click on the app pool under 'Application Pools' in IIS and select 'Advanced Settings' and the setting you need is about halfway down.

enter image description here

Tip: I'd recommend commenting your code with this to prevent future time wasted since it's so obscure if you've never come across it before.

  // If this gives FileNotFoundException see 
  // http://stackoverflow.com/questions/14263457/
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
  • Hello! I have the same problem i think, where do i make these changes? Thx – WhoAmI Mar 03 '14 at 11:34
  • @KristofferAndersson i've updated the answer. just right click the app pool in IIS and choose 'advanced settings' - and then upvote me :-) – Simon_Weaver Mar 04 '14 at 05:25
  • Hmm it seem my problem must be something else. All the pools where chacked "True". Very strange.. My Keypath looks like this: var certificate = new X509Certificate2(@"Models/GAStatistics/\key.p12", "notasecret", X509KeyStorageFlags.Exportable); Somehow the app can't localize the file (key.p12) even though i placed it in my MVC application. Thanks annyways – WhoAmI Mar 04 '14 at 07:24
  • other than making sure you were looking at the right pool did you try `File.Exists(...)` on the file to make sure it returns true? – Simon_Weaver Mar 04 '14 at 09:17
  • Nope, is "File.Exists(...)" also in advanced settings? I had 3 pools, all of them had true enabled for "Load User Profile". I'm thinking my problem might have something to do with dependencies and NuGet Packages as the code worked just fine as a Console App but gives me problem in MVC. Thx – WhoAmI Mar 04 '14 at 10:20
13

Also try specifying X509KeyStorageFlags

    var certificate = new X509Certificate2(KeyFilePath, KeyFilePassword, 
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | 
X509KeyStorageFlags.Exportable);
VahidN
  • 18,457
  • 8
  • 73
  • 117
  • 2
    Adding X509KeyStorageFlags.MachineKeySet, specifically, worked for me. – John B Jul 01 '15 at 14:15
  • This is a great solution to avoid messing with the configuration of IIS – AlfonsoML Sep 04 '15 at 17:57
  • 2
    If you set X509KeyStorageFlags parameter it will create a key file in the C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys folder every time you instantiate an X509Certificate2 object, if you do this often you could end up filling up the disk, so use this carefully. – NahuelGQ Mar 31 '16 at 20:56
  • It wants a file to be in C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys -- that file won't be created if you don't put MachineKeySet in the options. In PowerShell it looks like this: New-Object System.Security.Cryptography.X509Certificates.X509Certificate2.Import($certPath,$certPass,"MachineKeySet,Exportable,PersistKeySet") – Jeremy Dec 12 '20 at 03:44
2

As mentioned above you need to configure IIS but as our case, some time you need to check the permission of the following folder:

C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys

If you set X509KeyStorageFlags parameter it will create a key file in this folder. In my case there was a difference in permission of this folder. Pool account was not added in the mentioned folder.

garfbradaz
  • 3,424
  • 7
  • 43
  • 70
Shani
  • 53
  • 6
-2

Nope, is "File.Exists(...)" also in advanced settings? I had 3 pools, all of them had true enabled for "Load User Profile". I'm thinking my problem might have something to do with dependencies and NuGet Packages as the code worked just fine as a Console App but gives me problem in MVC.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
WhoAmI
  • 1,188
  • 6
  • 17
  • 47