I've created a 2FA for Umbraco back-office, using a custom OwinStartup, UserManager and UserStore. Everything works perfectly, except that when logged into the back office, the user session is terminated after exactly 60s every time. It doesn't matter if there is activity (clicking pages etc) it will kick the user out to the login page.
The standard Umbraco timeout settings are all fine (20mins), and additionally, if I use the default UmbracoDefaultOwinStartup, the timeout doesn't occur, it's only when using the code below. Also nothing in the logs.
Any ideas? Thanks in advance
public class MfaOwinStartup : UmbracoDefaultOwinStartup
{
protected override void ConfigureServices(IAppBuilder app)
{
app.SetUmbracoLoggerFactory();
var applicationContext = ApplicationContext.Current;
app.ConfigureUserManagerForUmbracoBackOffice<MfaUserManager, BackOfficeIdentityUser>(applicationContext, (options, context) => {
var membershipProvider = Umbraco.Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider().AsUmbracoMembershipProvider();
var userManager = MfaUserManager.Create(options,
applicationContext.Services.UserService,
applicationContext.Services.EntityService,
applicationContext.Services.ExternalLoginService,
membershipProvider,
UmbracoConfig.For.UmbracoSettings().Content);
return userManager;
});
app.UseTwoFactorSignInCookie(global::Umbraco.Core.Constants.Security.BackOfficeTwoFactorAuthenticationType, TimeSpan.FromMinutes(25));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
}
and
class MfaUserManager : BackOfficeUserManager, IUmbracoBackOfficeTwoFactorOptions
{
public override bool SupportsUserTwoFactor => true;
public MfaUserManager(IUserStore<BackOfficeIdentityUser, int> store)
: base(store)
{
}
public static MfaUserManager Create(
IdentityFactoryOptions<MfaUserManager> options,
IUserService userService,
IEntityService entitiyService,
IExternalLoginService externalLoginService,
MembershipProviderBase membershipProvider,
IContentSection content)
{
var manager = new MfaUserManager(new MfaUserStore(userService, entitiyService, externalLoginService, membershipProvider));
manager.InitUserManager(manager, membershipProvider, options.DataProtectionProvider, content);
var dataProtectionProvider = options.DataProtectionProvider;
manager.RegisterTwoFactorProvider("GoogleAuthenticator", new GoogleAuthenticatorProvider(dataProtectionProvider.Create("GoogleAuthenticator")));
return manager;
}
public string GetTwoFactorView(IOwinContext owinContext, UmbracoContext umbracoContext, string username)
{
var user = ApplicationContext.Current.Services.UserService.GetByUsername(username);
var u = MfaDb.GetUserMfa(user.Id);
return "/umbraco/Plugin/Login/Index";
}
}
and
public class MfaUserStore : BackOfficeUserStore
{
public MfaUserStore(IUserService userService, IEntityService entitiyService, IExternalLoginService externalLoginService,
MembershipProviderBase usersMembershipProvider)
: base(userService, entitiyService, externalLoginService, usersMembershipProvider)
{
}
public override Task SetTwoFactorEnabledAsync(BackOfficeIdentityUser user, bool enabled)
{
user.TwoFactorEnabled = enabled;
return Task.FromResult(0);
}
public override Task<bool> GetTwoFactorEnabledAsync(BackOfficeIdentityUser user)
{
var u = MfaDb.GetUserMfa(user.Id);
if (u != null && u.IsEnabled)
{
return Task.FromResult(true);
}
return Task.FromResult(false);
}
}
and
public class GoogleAuthenticatorProvider : DataProtectorTokenProvider<BackOfficeIdentityUser, int>, IUserTokenProvider<BackOfficeIdentityUser, int>
{
public GoogleAuthenticatorProvider(IDataProtector protector)
: base(protector)
{
}
Task<bool> IUserTokenProvider<BackOfficeIdentityUser, int>.IsValidProviderForUserAsync(UserManager<BackOfficeIdentityUser, int> manager,
BackOfficeIdentityUser user)
{
var u = MfaDb.GetUserMfa(user.Id);
return Task.FromResult(u != null && u.IsEnabled);
}
Task<bool> IUserTokenProvider<BackOfficeIdentityUser, int>.ValidateAsync(string purpose, string token, UserManager<BackOfficeIdentityUser, int> manager,
BackOfficeIdentityUser user)
{
var tfa = new TwoFactorAuthenticator();
var u = MfaDb.GetUserMfa(user.Id);
if (u == null) return Task.FromResult(false);
var r = tfa.ValidateTwoFactorPIN(u.Key, token);
return Task.FromResult(r);
}
}