0

I've lost at least 2 full working days on this and have tried numerous ways to achieve this without success.

The scenario is like this: I have 2 applications deployed to Azure, let's say they are backoffice.website.com and frontoffice.website.com. Both are 2 separate Azure web apps. A user who logs in to backoffice.website.com should be able to go to a list of users that have logins at frontoffice.website.com and select a user to impersonate, which would redirect them to frontoffice.website.com, logged in as the selected user.

Both websites use the same database in Azure and share the same DbContext (both projects live in the same solutions in Visual Studio and both reference the same data access layer, which points to the database for both applications (both applications use the same .Net Core Identity setup and tables)

Now, according to the article here.

You should be able to set up Startup.ConfigureServices method to look something like this:

app.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
   options.Cookies.ApplicationCookie.AuthenticationScheme = "ApplicationCookie";
   var protectionProvider = DataProtectionProvider.Create(new DirectoryInfo(@"c:\shared-auth-ticket-keys\"));
   options.Cookies.ApplicationCookie.DataProtectionProvider = protectionProvider;
   options.Cookies.ApplicationCookie.TicketDataFormat = new TicketDataFormat(protectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", "Cookies", "v2"));
});

And this works, locally using IIS Express, but in Azure, there is no directory access outside of the application that all applications in an Azure account can share (that I know of, and yes, I know they have other options for file sharing, but we'll get to that now).

Since we can't use a directory to place the file that has the shared key needed between 2 applications in a directory in Azure,

We refer to this article here, which leads to creating a Blob container in Azure to store the key in so that any and all apps I desire to create and host in Azure can access the key from the store.

Using bits from the first referenced article and the 2nd, the code now looks something like this (set all in the Startup.ConfigureServices method for readability):

var storageAccount = new CloudStorageAccount(
            new StorageCredentials("blob", "SASKeyHere"),
            new StorageUri(new Uri("https://endpoint.blob.core.windows.net/")),
            null,
            null,
            null
        );

var client = storageAccount.CreateCloudBlobClient();
var container = client.GetContainerReference("container");
container.CreateIfNotExistsAsync().GetAwaiter().GetResult();

var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection().PersistKeysToAzureBlobStorage(container, "fileName.xml");
 var service2 = serviceCollection.BuildServiceProvider();

 var dataProtector = service2.GetRequiredService<IDataProtectionProvider>();

 // Add framework services.
 services.AddDbContext<DbContext>(options => options
            .UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

 services.AddIdentity<ApplicationUser, IdentityRole>(options =>
            {
                options.Cookies.ApplicationCookie.AuthenticationScheme = "ApplicationCookie";
                var protectionProvider = dataProtector;
                options.Cookies.ApplicationCookie.DataProtectionProvider = protectionProvider;

                options.Cookies.ApplicationCookie.TicketDataFormat = new TicketDataFormat(protectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", "Cookies", "v2"));
            })
            .AddEntityFrameworkStores<DbContext>()
            .AddDefaultTokenProviders();

This ALSO works locally! This code is in the ConfigureServices method for both applications and lets the cookies be read across both applications, But once deployed, does not work!

Has anyone been able to achieve this or something similar?!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
AJ Soto
  • 133
  • 1
  • 11

1 Answers1

0

It's likely because cookies are not cross subdomain by default.

Can you try adding your root domain as the cookie domain (This will likely need to be a configuration setting so it works locally too!)

app.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.Cookies.ApplicationCookie.CookieDomain = ".mydomain.com";
}
MindingData
  • 11,924
  • 6
  • 49
  • 68
  • Incredible! This seems to work, thank you very much! Of note, for some reason, the individual who is going to impersonate the user has to check the tick box when signing in "remember me", otherwise the impersonation doesn't work for that user. If you can help me understand the reasoning behind this too that would be nice. It can definitely just be my code though. – AJ Soto Sep 28 '17 at 16:10
  • Probably best for another question. What I would suggest is that for big questions like yours try and create a simple POC on Github and share the link in your question. I just took a stab in the dark with this one, but for impersonation etc, it's too big to really guess the answer. – MindingData Sep 28 '17 at 20:08