Closed marafiq closed 3 years ago
Hello @marafiq ... This might not be merely a won't fix but ultimately a scenario removal given the challenges involved in maintaining guidance to make it work. We did have sample apps for this at one time, but we yanked them ages ago.
@HaoK ... When we discussed this a long time ago ... years ago at this point I think ... we dropped the working samples for this scenario from the topic because this wasn't a common request and it can be rather tricky to pull off. I recall that the sample apps for this scenario were a pain to maintain because they broke a few times across releases.
@guardrex Since I struggled with it for days, I guess only good sleep fixed it. I will say its important to have docs updated & working samples. But apart for that, I think retiring/dropping the docs will not be beneficial especially for folks who are trying to migrate their apps. As migration efforts this is first piece one has to figure out if you can not upgrade everything to .NET 5 or Core which is not practical.
There are resource limitations, so management has to prioritize issues. Hao told me years ago that devs weren't asking for this scenario very often. That may have changed since then. He'll let us know how he wants to handle it. We can add the bit ur recommending, but I think adding and maintaining samples would be difficult.
Right its tricky and not commonly asked for, its easier to just help people via issues rather than trying to publish specific documentation at this point. But yeah everything has match exactly or it won't work.
Thanks @HaoK.
rather than trying to publish specific documentation at this point
In that case, @Rick-Anderson, I can craft the section to link to this issue and inject the original content of the section here. It wouldn't take long to handle this issue that way. Devs would still have access to the content and to what @marafiq has provided. Shall I proceed with a draft PR to see how that would compose? Otherwise if not, either it will take me very long time to reach this issue under the current workload (for major section updates + new sample code tested and placed here), or you'll have to re-assign the issue. 🏃
In that case, @Rick-Anderson, I can craft the section to link to this issue and inject the original content of the section here.
Perfect, I think that's the best approach. This issues has details we can't add to a doc, such as "Right its tricky and not commonly asked for".
I propose we edit @Haok comment to something like using SO so we don't elicit too many support requests.
Cool ... I'll take care of this by EOW and ping u for review.
Original content
ASP.NET 4.x apps that use Katana Cookie Authentication Middleware can be configured to generate authentication cookies that are compatible with the ASP.NET Core Cookie Authentication Middleware. This allows upgrading a large site's individual apps in several steps while providing a smooth SSO experience across the site.
When an app uses Katana Cookie Authentication Middleware, it calls UseCookieAuthentication
in the project's Startup.Auth.cs file. ASP.NET 4.x web app projects created with Visual Studio 2013 and later use the Katana Cookie Authentication Middleware by default. Although UseCookieAuthentication
is obsolete and unsupported for ASP.NET Core apps, calling UseCookieAuthentication
in an ASP.NET 4.x app that uses Katana Cookie Authentication Middleware is valid.
An ASP.NET 4.x app must target .NET Framework 4.5.1 or later. Otherwise, the necessary NuGet packages fail to install.
To share authentication cookies between an ASP.NET 4.x app and an ASP.NET Core app, configure the ASP.NET Core app as stated in the Share authentication cookies among ASP.NET Core apps section, then configure the ASP.NET 4.x app as follows.
Confirm that the app's packages are updated to the latest releases. Install the Microsoft.Owin.Security.Interop package into each ASP.NET 4.x app.
Locate and modify the call to UseCookieAuthentication
:
.AspNet.SharedCookie
in the example).Identity.Application
.DataProtectionProvider
initialized to the common data protection key storage location.SharedCookieApp
in the example).If not setting http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
and http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider
, set
App_Start/Startup.Auth.cs:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Identity.Application",
CookieName = ".AspNet.SharedCookie",
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity =
SecurityStampValidator
.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) =>
user.GenerateUserIdentityAsync(manager))
},
TicketDataFormat = new AspNetTicketDataFormat(
new DataProtectorShim(
DataProtectionProvider.Create("{PATH TO COMMON KEY RING FOLDER}",
(builder) => { builder.SetApplicationName("SharedCookieApp"); })
.CreateProtector(
"Microsoft.AspNetCore.Authentication.Cookies." +
"CookieAuthenticationMiddleware",
"Identity.Application",
"v2"))),
CookieManager = new ChunkingCookieManager()
});
System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier =
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name";
When generating a user identity, the authentication type (Identity.Application
) must match the type defined in AuthenticationType
set with UseCookieAuthentication
in App_Start/Startup.Auth.cs.
Models/IdentityModels.cs:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
UserManager<ApplicationUser> manager)
{
// The authenticationType must match the one defined in
// CookieAuthenticationOptions.AuthenticationType
var userIdentity =
await manager.CreateIdentityAsync(this, "Identity.Application");
// Add custom user claims here
return userIdentity;
}
}
@guardrex @marafiq
i tried & get it worked as it was described in the original doc
Core: `services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(Configuration["Identity:DataProtectionDir"])) .SetApplicationName(Configuration["Identity:ApplicationName"]);
services.ConfigureApplicationCookie(options =>
{
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.Name = Configuration["Identity:CookieName"];
options.Cookie.Path = Configuration["Identity:CookiePath"];
options.Cookie.Domain = Configuration["Identity:CookieDomain"];
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(Int32.Parse(Configuration["Identity:CookieExpirationMinutes"]));
options.LoginPath = "/Identity/Account/Login";
options.LogoutPath = "/Identity/Account/Logout";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
//options.CookieManager = new ChunkingCookieManager();
//options.TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(new TicketSerializer(),
// DataProtectionProvider.Create(new DirectoryInfo(Configuration["Identity:DataProtectionDir"]),
// (builder) => { builder.SetApplicationName(Configuration["Identity:ApplicationName"]); })
// .CreateProtector(
// "Microsoft.AspNetCore.Authentication.Cookies." +
// "CookieAuthenticationMiddleware",
// "Identity.Application",
// "v2"));
});`
.net 4.6.1
`app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = "Identity.Application", CookieName = "Identity:CookieName", CookiePath = "/", CookieDomain = "localhost", LoginPath = new PathString("/1"), Provider = new CookieAuthenticationProvider { OnException = ex => { AppLogger.LogExceptionRecursively(ex.Exception.Message, ex.Exception, MethodBase.GetCurrentMethod()); } }, TicketDataFormat = new AspNetTicketDataFormat( new DataProtectorShim( DataProtectionProvider.Create(new DirectoryInfo("d:/dataprotection"), (builder) => { builder.SetApplicationName("Identity:ApplicationName"); }) .CreateProtector( "Microsoft.AspNetCore.Authentication.Cookies." + "CookieAuthenticationMiddleware", "Identity.Application", "v2"))), CookieManager = new ChunkingCookieManager() });
System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name";`
importan to have same app name
Thanks for the previous contributions! For the ones that did manage to make it work the sharing of cookies between .NET and Core because of this thread like me, here follows the configuration that worked for me. I'm posting because it was the combination of the several comments that made my application work, and like me, maybe someone will make its application work reading my example too.
Core 5.0 Web Api project Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo("C:\\keyDirectory"))
.SetApplicationName("iis-app-name");
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = ".AspNet.SharedCookie";
options.Cookie.SameSite = SameSiteMode.Lax;
options.Cookie.Path = "/";
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(120);
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Framework 4.8
public static void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
CookieName = ".AspNet.SharedCookie",
CookieSameSite = SameSiteMode.Lax,
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes(120),
TicketDataFormat = new AspNetTicketDataFormat(
new DataProtectorShim(
DataProtectionProvider.Create(new DirectoryInfo("C:\\keyDirectory"),
(builder) =>
{
builder.SetApplicationName("iis-app-name");
})
.CreateProtector(
"Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
"Cookies",
"v2"))),
CookieManager = new ChunkingCookieManager()
});
}
The directory where the key is stored, could this also be a storage account? And more to the point can MSI be used for this storage account? I think that I could provide the container url with SAS token, but that is a last resort that I would really like to avoid if possible.
Hi everyone ... we aren't really a discussion forum-type of repo. This is a working repo for the docs, so general discussions are somewhat distracting, especially on closed issues and PRs. It's best to discuss things on a public forum, such as ...
After many attempts to share authentication cookies without identity between ASP.NET 4.7.1 and .NET 5 hosted under IIS. Documentation is not clear, and lack key details with reference to configuring data protector for authentication cookie.
.NET Framework docs says that configure CookieAuthenticationOptions by setting TicketDataFormat where data protector has to be configured seen below. Docs should note that .NET 5 should also configure in exactly same way. See below
Note: Make sure purpose & sub purpose strings are same for .NET framework & .NET 5 set on Ticket Data Format.
Every other variation I tried did not worked. It would be nice to update the docs with explicit instructions or link to working sample which provides both .NET framework 4.5.x app & .NET 5 app, which can be downloaded & hosted on IIS to see how its working. Randomly pointing to sample which has multiple startup's leaves so much to hunt for.
Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.