Friday 7 August 2020

Deploying Angular .Net Core and Identity Server 4 onto iis

 

user is null when await this.userManager.signinCallback


Or at least that's where the problem started


To set the scene, I was using a vanilla .net core angular identity server 4 setup, to test what was happening.  So it's a good place to start to explain what was happening.

The Setup

I followed the step by step guide published here on the docs.microsoft.com site.  You would expect this to work.  To be fair, it does, in iis express or using the ng-serve command .

New Project

dotnet new angular -o pa2020 -au Individual

This gets us 90% of the way to a vanilla build.  However, to deploy onto a test server that has a certificate and running on port 443, we needed to add to the appSettings json file

"IdentityServer": { "Key": { "Type": "Store", "StoreName": "My", "StoreLocation": "CurrentUser", "Name": "CN=MyApplication" } }


Unbreakable - It Broke!

So simple, and you would expect it to work, and in iis express it does.  The error was

There was an error signing in: Error: (400)
at XMLHttpRequest.o.onload [as __zone_symbol__ON_PROPERTYload] (main-es2015.ae9ca0e58964647235f0.js:1)
at XMLHttpRequest.w (polyfills-es2015.5b10b8fd823b6392f1fd.js:1)
at a.invokeTask (polyfills-es2015.5b10b8fd823b6392f1fd.js:1)
at Object.onInvokeTask (main-es2015.ae9ca0e58964647235f0.js:1)
at a.invokeTask (polyfills-es2015.5b10b8fd823b6392f1fd.js:1)
at s.runTask (polyfills-es2015.5b10b8fd823b6392f1fd.js:1)
at c.invokeTask [as invoke] (polyfills-es2015.5b10b8fd823b6392f1fd.js:1)
at u (polyfills-es2015.5b10b8fd823b6392f1fd.js:1)
at XMLHttpRequest.p (polyfills-es2015.5b10b8fd823b6392f1fd.js:1)

But something strange, and it didn't look good.  The single page angular part was saying NOT LOGGED IN.  but click register, and the user is definitely authenticated, with access to the profile.

Debugging the code where this breaks lead me down several rabbit holes, one of which was the oidc-client setup.
Hidden way down in the depths of the authorize.service.ts line 113, the 
this.userManager.signinCallback(url); was throwing this error.  The usermanager was Observable which didn't help, neither was using fiddler to monitor the network.

The url and tokens were all as expected, even the routes were all good.  This is when I started to suspect the certificate - not sure what lead me to that, except somewhere in the back of my mind, years ago reading that IIS can sometimes decide refuse a call based on the certificate not being valid.

Certificates a plenty

I had a standard localhost certificate installed on my local box for iis testing, but as I also installed the wildcard certificate for pa2020 and set the hosts file to report to my local box, it mean I was ready to go.

I had published the to a local folder, again default settings, yet was getting the problem.  I decided to make the following changes.  However, only the combination of changes solved the isses.

1) consume the certificate at app startup
2) install the certificate outside of the iis system
3) Change App Pool identity, this bit was the missing glue;

Solution

This required changes to the code and to the IIS server

The certificate turned out to be partially the issue, so in the startup I added the following at the top of ConfigureServices
var cert = new X509Certificate2("my_private_key.pfx", Configuration["Authentication:Certificate:Pwd"]);

on the IIS Server I used certlm.msc to install the certificate

on the IIS Application Pool I changed the application pool identity from "ApplicationPool" to "NetworkService"

Now working as expected