IdentityServer4 does not work on a shared Azure App Service

Created on 26 Sep 2019  Â·  6Comments  Â·  Source: IdentityServer/IdentityServer4

The reason for this is that when trying to create a security token, IdentityServer4 fails with the following error:

2019-09-26 07:53:28.798 +00:00 [INF] Credentials validated for username: maxime
2019-09-26 07:53:28.799 +00:00 [INF] {"Username":"maxime","ClientId":"client.ro","EventType":"Success","$type":"UserLoginSuccessEvent",…}
2019-09-26 07:53:28.802 +00:00 [DBG] Resource owner password token request validation success.
2019-09-26 07:53:28.803 +00:00 [INF] Token request validation success, {"ClientId":"client.ro","GrantType":"password","Scopes":"api",…}
2019-09-26 07:53:28.804 +00:00 [DBG] Getting claims for access token for client: client.ro
2019-09-26 07:53:28.805 +00:00 [DBG] Getting claims for access token for subject: 746ede49-975c-45b8-bfd5-78f5770a236e
2019-09-26 07:53:28.866 +00:00 [INF] {"Details":"Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The system cannot find the file specified.\r\n
   at System.Security.Cryptography.CngKey.Open(String keyName, CngProvider provider, CngKeyOpenOptions openOptions)\r\n 
  at System.Security.Cryptography.CngKey.Open(String keyName, CngProvider provider)\r\n
  at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)\r\n 
  at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()\r\n
  …
   at IdentityServer4.Services.DefaultTokenCreationService.CreateJwtAsync(JwtSecurityToken jwt)
   at IdentityServer4.Services.DefaultTokenCreationService.CreateTokenAsync(Token token)
   at IdentityServer4.Services.DefaultTokenService.CreateSecurityTokenAsync(Token token)
   at IdentityServer4.ResponseHandling.TokenResponseGenerator.CreateAccessTokenAsync(ValidatedTokenRequest request)
   at IdentityServer4.ResponseHandling.TokenResponseGenerator.ProcessTokenRequestAsync(TokenRequestValidationResult validationResult)
   at IdentityServer4.ResponseHandling.TokenResponseGenerator.ProcessAsync(TokenRequestValidationResult request)
   at IdentityServer4.Endpoints.TokenEndpoint.ProcessTokenRequestAsync(HttpContext context)
   at IdentityServer4.Endpoints.TokenEndpoint.ProcessAsync(HttpContext context)
   at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)

The solution is to upgrade the App Service Plan to a Basic instance and add the following configuration key:

WEBSITE_LOAD_USER_PROFILE =  1

It would be great if there was an alternative to be able to use the Free Tier from Azure.

question

All 6 comments

How are you configuring your signing key?

I use the following code with a PFX certificate, available on the file system.

               Logger.LogDebug("Loading signing certificate...");

                var password = Configuration["SigningCertificate:Password"];
                var certificatePath = Path.Combine(Environment.ContentRootPath, @"App_Data\signing.pfx");
                if (File.Exists(certificatePath))
                {
                    var certificate = new X509Certificate2(File.ReadAllBytes(certificatePath), password);
                    builder.AddSigningCredential(certificate);

                    Logger.LogDebug($"File '{certificatePath}' successfully loaded.");

And I confirm that the certificate is successfully loaded.

I have not tested this on Azure App Services, but I had a similar situation where I did not want to load a user profile. This is how I'm loading the pfx.

// load certificate into MachineKeySet which does NOT require a User Profile to be loaded for crypto: https://github.com/dotnet/corefx/issues/23780
builder.AddSigningCredential(new X509Certificate2(keyFilePath, keyFilePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.EphemeralKeySet));

I don't know if there are issues loading the certificate into MachineKeySet -- perhaps that makes it usable to anyone on the machine? In my case its a dedicated machine under my control so I was not concerned with it.

IIRC you need to pass in the storage flags as @fuzzzerd shows.

Or you load the key from KeyVault. Or you use an RSA key.

Indeed, that solves the problem.
It works correctly now.
I should have seen those flags, sorry about that.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

eshorgan picture eshorgan  Â·  3Comments

leastprivilege picture leastprivilege  Â·  3Comments

chrisrestall picture chrisrestall  Â·  3Comments

mackie1001 picture mackie1001  Â·  3Comments

leksim picture leksim  Â·  3Comments