London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!
AI OnAI Off
London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!
Worked it out: Commerce needs to use Asp.NET Identity only
For consistency, I've used the Commerce DB for all users created via Asp NET identity
We're trying to implement a mixed mode authemtication scenario where CMS Editors/Admins login using Azure AD, but Commerce Customers log in using the Commerce database.
Our Startup.cs for the EPiServer CMS is as follows:
{ public class Startup { private const string LogoutUrl = "/util/logout.aspx"; public void Configuration(IAppBuilder app) { app.AddCmsAspNetIdentity<SiteUser>(new ApplicationOptions { }); //// This will configure cookie authentication at the following urls. //// In those pages you are responsible for authentication and calling the OwinContext.Authentication.SignIn method to properly sign in the user //// and OwinContext.Authentication.SignOut to logout a user app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/login"), LogoutPath = new PathString("/logout"), Provider = new CookieAuthenticationProvider { // Enables the application to validate the security stamp when the user logs in. // This is a security feature which is used when you change a password or add an external login to your account. OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager<SiteUser>, SiteUser>( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentity: (manager, user) => manager.GenerateUserIdentityAsync(user)), OnApplyRedirect = context => context.Response.Redirect(context.RedirectUri), OnResponseSignOut = context => context.Response.Redirect(UrlResolver.Current.GetUrl(ContentReference.StartPage)) } }); // Enable cookie authentication, used to store the claims between requests app.SetDefaultSignInAsAuthenticationType( WsFederationAuthenticationDefaults.AuthenticationType); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType }); // Enable federated authentication app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions { // Trusted URL to federation server meta data MetadataAddress = ConfigurationManager.AppSettings["MetadataAddress"], // Value of Wtreal must *exactly* match what is configured in the federation server Wtrealm = ConfigurationManager.AppSettings["Wtrealm"], Notifications = new WsFederationAuthenticationNotifications { RedirectToIdentityProvider = ctx => { // To avoid a redirect loop to the federation server send 403 when user is authenticated but does not have access if (ctx.OwinContext.Response.StatusCode == 401 && ctx.OwinContext.Authentication.User.Identity.IsAuthenticated) { ctx.OwinContext.Response.StatusCode = 403; ctx.HandleResponse(); } return Task.FromResult(0); }, SecurityTokenValidated = async ctx => { // Ignore scheme/host name in redirect Uri to make sure a redirect to HTTPS does not redirect back to HTTP var redirectUri = new Uri( ctx.AuthenticationTicket.Properties.RedirectUri, UriKind.RelativeOrAbsolute); if (redirectUri.IsAbsoluteUri) { ctx.AuthenticationTicket.Properties.RedirectUri = redirectUri.PathAndQuery; } // Create claims for roles await ServiceLocator.Current.GetInstance<AzureGraphService>() .CreateRoleClaimsAsync(ctx.AuthenticationTicket.Identity); try { // Sync user and add the roles to EPiServer in the background await ServiceLocator.Current.GetInstance<ISynchronizingUserService>() .SynchronizeAsync(ctx.AuthenticationTicket.Identity); } catch (Exception ex) { throw new Exception( "Name Claim Type: " + ctx.AuthenticationTicket.Identity.NameClaimType, ex); } } } }); // Add stage marker to make sure WsFederation runs on Authenticate (before URL Authorization and virtual roles) app.UseStageMarker(PipelineStage.Authenticate); // Remap logout to a federated logout app.Map( LogoutUrl, map => { map.Run(ctx => { ctx.Authentication.SignOut(); return Task.FromResult(0); }); }); // Tell antiforgery to use the name claim AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier; } } }
In the CMS site's web.config, we've set the authentication mode to "none" and disabled the membership and rolemanager settings.
This works fine when browsing to /episerver - the user is redirected to the authenticaiton provider and once logged in successfully is redirected to the episerver back-end.
Similarly, if a customer logs in to the site at the /Login page, they are prompted for their username and password and can log in OK.
However, when I click the Commerce Manager link in the back-end, I'm prompted to log in using the standard Commerce Admin login page even though my user is a member of the virtual role Commerce Admins - is this correct?
I assume that for Commerce Customers to log in, the Commerce Manager site needs to retain the SQL Server membership and role provider settings, but is it possible to disable authentication for the Commerce Manager site so we don't need to log in to the Commerce Manager back-end?
If so, do I need to provide the same/similar Startup.cs for the Commerce Manager site?
There seems to be some interaction between the MediaChase assemblies and the login porcess that I need to override, but it's not clear what...