Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swapping Azure Web App deployment slots logs out all users in ASP.NET Core RC2

Whenever I updated my ASP.NET Core RC2 website running on as an Azure Web App, it logs out all users. It seems to be related to swapping a staging deployment slot to production (I use web deploy from VS to staging, and have it set to auto-swap to production). If I do a direct update of the production slot it's fine, but I don't want to do that. I am at a loss as to how to configure this, help would be appreciated!

Here is how I have it configured right now, my site only allows logging in directly (no facebook login etc.):

In ConfigureServices in Startup

// found some post that said this would help... doesn't seem to work...
services.AddDataProtection()
        .SetApplicationName("myweb");

services.AddIdentity<MyUser, MyRole>(options =>
{
    options.Cookies.ApplicationCookie.CookieDomain = settings.CookieDomain; // cookie domain lets us share cookies across subdomains
    options.Cookies.ApplicationCookie.LoginPath = new PathString("/account/login");
    options.Cookies.ApplicationCookie.ReturnUrlParameter = "ret";
    options.Cookies.ApplicationCookie.CookieSecure = CookieSecureOption.Never; // TODO: revisit site-wide https

    // allow login cookies to last for 30 days from last use
    options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(60);
    options.Cookies.ApplicationCookie.SlidingExpiration = true;

    // I think this needs to at least be longer than cookie expiration to prevent security stamp from becoming invalid before the cookie?
    options.SecurityStampValidationInterval = TimeSpan.FromDays(90);
})
.AddUserStore<MyUserStore>() // custom stores to hook up our old databases to new identity system
.AddRoleStore<MyRoleStore>()
.AddDefaultTokenProviders();

And in Configure in Startup

app.UseIdentity();
like image 304
Yellowfive Avatar asked Jun 16 '16 04:06

Yellowfive


People also ask

What is the default routing rule applied to new deployment slots in Azure?

By default, Traffic % is set to 0 for the new slot, with all customer traffic routed to the production slot. Select the new deployment slot to open that slot's resource page. The staging slot has a management page just like any other App Service app. You can change the slot's configuration.

How many maximum deployment slots can be there in one app service plan?

I should mention that the total number of slots you can use depends on the pricing tier of the App Service Plan you're using. Deployment slots are only supported in the Standard, Premium, and Isolated tiers. The Standard tier supports up to 5 slots, but the Premium and Isolated tiers support up to 20.

How do Azure deployment slots work?

Azure Functions deployment slots allow your function app to run different instances called "slots". Slots are different environments exposed via a publicly available endpoint. One app instance is always mapped to the production slot, and you can swap instances assigned to a slot on demand.

How many deployment slots are available in app Services Azure?

Deployment slots are a feature of Azure App Service Plans. As a result, every App Service resource (Web App, Web API, Mobile App) in Microsoft Azure has the ability to create up to 4 additional deployment slots with the Standard tiers, and up to 20 deployment slots with the Premium tiers.


1 Answers

After much research... I think that I have this working.

So for anyone who wants an ASP.NET Core RC2 website that uses the Identity stuff for login, and wants to host it on an Azure Web App, and wants to use the Deployment Slots to do updates via swapping, and doesn't want every user to get logged out every time the website is updated... read on!

** Usually, Azure gives you some magical default configuration that makes all of the instances in a single Web App work together. The issue with deployment slots is that it essentially acts like two completely separate Web Apps, so all the magic is gone.

You need to configure Data Protection correctly to make this work. It is a bit confusing because the documentation for .NET Core Identity makes no explicit mention of depending on or requiring that you configure Data Protection correctly, but it does. Data Protection is what it uses under the hood to encrypt the application login cookie.

The following code is needed in ConfigureServices:

services.AddDataProtection()
    .SetApplicationName("myweb")
    .ProtectKeysWithCertificate("thumbprint");

services.AddSingleton<IXmlRepository, CustomDataProtectionRepository>();

Explanation of each piece:

  1. Setting the application name lets you share the protected data across multiple applications that use this same application name. May not be required for all scenarios, but doesn't hurt for ours.
  2. You need to use a custom key encryption method that is consistent across both deployment slots. The default is specific to each deployment slot and can only be used within that slot. If you look at key encryption at rest, Azure uses Windows DPAPI by default. Not gonna work for our purposes. So I chose to use a certificate, just enter the thumbprint as seen in the Azure portal. NOTE: for those who hate certificates and all the jargon around it, the .NET Core documentation says you need a X.509 certificate that supports CAPI private keys or it won't work. blah blah blah blah use the SSL certificate you got for your website, it should work just fine.
  3. An aside: you have to do some extra googling to actually make using the certificate work. The Data Protection documentation kind of leaves you hanging in the case of Azure... just using the code above, you will likely get a 500 error when you deploy to Azure. Firstly, make sure you have uploaded your certificate in the "Custom domains and SSL" section of your Web App. Secondly, you need to add the WEBSITE_LOAD_CERTIFICATES Application Setting and add the thumbprint of your certificate to that in order to use it. See using certificates in azure websites.
  4. Once you set a certificate to encrypt the data... it blows away any default configuration about where to store the data -- Azure stores it in a shared folder that all of your instances can access by default (defaults described here data protection defaults). But different deployment slots are separate... so the built-in file system and registry options are no help. You have to write a custom implementation as described here: key storage providers. But oh wait... the section at the bottom on custom key repositories is a 1-liner with no link or explanation about how to hook it up... you really need to read here: key management, go to the IXmlRepository section. Unfortunately the IDataProtectionBuilder has handy extensions for everything except what you need to do here, thus the line where we register this custom IXmlRepository with the service provider. Despite the alarmingly generic name of that interface, it only impacts Data Protection and won't mess with your other stuff.
  5. Not shown is the implementation of CustomDataProtectionRepository. I used Azure blob storage. It is a pretty simple interface, make a comment if you need help with that though.

And OMG finally we have it working. Enjoy the 500% decrease in lost password customer service requests ;)

like image 164
Yellowfive Avatar answered Nov 03 '22 00:11

Yellowfive