As it's only a few years old that code would have been built around a fairly new version of the platform so is valid for pre CMS 12 solutions. So I would give it a go
Thanks Scott,
So I am trying to work my way through the guide, I am unsure about:
public static IAppBuilder AddCmsTwoFactorAspNetIdentity<TUser>(this IAppBuilder app) where TUser : IdentityUser, IUIUser, new()
{
var applicationOptions = new ApplicationOptions
{
DataProtectionProvider = app.GetDataProtectionProvider()
};
// Configure the db context, user manager and signin manager to use a single instance per request by using
// the default create delegates
app.CreatePerOwinContext(() => applicationOptions); app.CreatePerOwinContext<ApplicationDbContext<TUser>>(ApplicationDbContext<TUser>.Create); app.CreatePerOwinContext<ApplicationRoleManager<TUser>>(ApplicationRoleManager<TUser>.Create); app.CreatePerOwinContext<ApplicationUserManager<TUser>>(CreateApplicationUserManager);
// 2 Factor Auto Registration app.CreatePerOwinContext<ApplicationSignInManager<TUser>>(ApplicationSignInManager<TUser>.Create);
// Configure the application
app.CreatePerOwinContext<UIUserProvider>(ApplicationUserProvider<TUser>.Create); app.CreatePerOwinContext<UIRoleProvider>(ApplicationRoleProvider<TUser>.Create); app.CreatePerOwinContext<UIUserManager>(ApplicationUIUserManager<TUser>.Create); app.CreatePerOwinContext<UISignInManager>(ApplicationUISignInManager<TUser>.Create);
// Saving the connection string in the case dbcontext be requested from none web context
ConnectionStringNameResolver.ConnectionStringNameFromOptions = applicationOptions.ConnectionStringName;
return app;
}
public static ApplicationUserManager<TUser> CreateApplicationUserManager<TUser>(IdentityFactoryOptions<ApplicationUserManager<TUser>> options, IOwinContext context) where TUser : IdentityUser, IUIUser, new()
{
var manager = new ApplicationUserManager<TUser>(new UserStore<TUser>(context.Get<ApplicationDbContext<TUser>>()))
{
UserLockoutEnabledByDefault = true,
DefaultAccountLockoutTimeSpan = TimeSpan.FromMilliseconds(5),
MaxFailedAccessAttemptsBeforeLockout = 5,
PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = false,
RequireUppercase = false
}
};
manager.UserValidator = new UserValidator<TUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
manager.RegisterTwoFactorProvider("TwoFactor Authenticator", (IUserTokenProvider<TUser, string>)new TwoFactorAuthenticatorTokenProvider());
var provider = context.Get<ApplicationOptions>().DataProtectionProvider.Create("EPiServerAspNetIdentity");
manager.UserTokenProvider = new DataProtectorTokenProvider<TUser>(provider);
return manager;
}
Is this supposed to go into Business\AdministratorRegistrationPage.cs? Anyone know?
Maybe these 2 issues are glaringly obvious to others and I'm missing them.
1. So in Startup.cs I have added the three lines as per the blog post:
// Register our two factor auth into the site.
app.AddCmsTwoFactorAspNetIdentity<SiteApplicationUser>();
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
But in Visual Studio <SiteApplicationUser> is being red-underlined with the following message:
The type or namespace name 'SiteApplicationUser' could not be found (are you missing a using directive or an assembly reference?)
Now as far as I understood from the blog post, we are setting up a new user store here. But there is no mention of any other steps required for this user store in the blog post. Any idea what the issue here is?
2. Again, as per the blog post, I have added the following:
public static IAppBuilder AddCmsTwoFactorAspNetIdentity<TUser>(this IAppBuilder app) where TUser : IdentityUser, IUIUser, new()
{
var applicationOptions = new ApplicationOptions
{
DataProtectionProvider = app.GetDataProtectionProvider()
};
// Configure the db context, user manager and signin manager to use a single instance per request by using
// the default create delegates
app.CreatePerOwinContext(() => applicationOptions); app.CreatePerOwinContext<ApplicationDbContext<TUser>>(ApplicationDbContext<TUser>.Create); app.CreatePerOwinContext<ApplicationRoleManager<TUser>>(ApplicationRoleManager<TUser>.Create); app.CreatePerOwinContext<ApplicationUserManager<TUser>>(CreateApplicationUserManager);
// 2 Factor Auto Registration app.CreatePerOwinContext<ApplicationSignInManager<TUser>>(ApplicationSignInManager<TUser>.Create);
// Configure the application
app.CreatePerOwinContext<UIUserProvider>(ApplicationUserProvider<TUser>.Create); app.CreatePerOwinContext<UIRoleProvider>(ApplicationRoleProvider<TUser>.Create); app.CreatePerOwinContext<UIUserManager>(ApplicationUIUserManager<TUser>.Create); app.CreatePerOwinContext<UISignInManager>(ApplicationUISignInManager<TUser>.Create);
// Saving the connection string in the case dbcontext be requested from none web context
ConnectionStringNameResolver.ConnectionStringNameFromOptions = applicationOptions.ConnectionStringName;
return app;
}
public static ApplicationUserManager<TUser> CreateApplicationUserManager<TUser>(IdentityFactoryOptions<ApplicationUserManager<TUser>> options, IOwinContext context) where TUser : IdentityUser, IUIUser, new()
{
var manager = new ApplicationUserManager<TUser>(new UserStore<TUser>(context.Get<ApplicationDbContext<TUser>>()))
{
UserLockoutEnabledByDefault = true,
DefaultAccountLockoutTimeSpan = TimeSpan.FromMilliseconds(5),
MaxFailedAccessAttemptsBeforeLockout = 5,
PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = false,
RequireUppercase = false
}
};
manager.UserValidator = new UserValidator<TUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
manager.RegisterTwoFactorProvider("TwoFactor Authenticator", (IUserTokenProvider<TUser, string>)new TwoFactorAuthenticatorTokenProvider());
var provider = context.Get<ApplicationOptions>().DataProtectionProvider.Create("EPiServerAspNetIdentity");
manager.UserTokenProvider = new DataProtectorTokenProvider<TUser>(provider);
return manager;
}
I have added this into an existing file called AdministratorRegistrationPage.cs (perhaps this is the wrong file and I am supposed to add the above snippet into a different file or new file altogether?).
And here in this line:
manager.RegisterTwoFactorProvider("TwoFactor Authenticator", (IUserTokenProvider<TUser, string>)new TwoFactorAuthenticatorTokenProvider());
The TwoFactorAuthenticatorTokenProvider is being red-underlined with the following message:
The type or namespace name 'TwoFactorAuthenticatorTokenProvider' could not be found (are you missing a using directive or an assembly reference?)
Again, no mention of any related steps in the blog post, any idea what the issue here is?
Has anyone set up 2FA with EpiServer? For example Google Authenticator or something similar?
How simple/complicated would this be and are there any guides on setting this up?
We are using the standard authentication in EpiServer.
I found this here: https://world.optimizely.com/blogs/Joshua-Folkerts/Dates/2019/2/2-factor-authentication-in-episerver/ is it still valid? Seems there isn't much on this topic available.