Implements IUserSecurityStore and ensures there is a security stamp token in place, have updated the repository layer to manual update this if ASPNet Identity APIs are not used to update users.

This commit is contained in:
Shannon
2015-03-25 10:57:10 +11:00
parent 90b562a0a1
commit 4dcc4807ed
14 changed files with 258 additions and 118 deletions

View File

@@ -2,11 +2,24 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Umbraco.Core.Security;
namespace Umbraco.Core.Models.Identity
{
public class BackOfficeIdentityUser : IdentityUser<int, IIdentityUserLogin, IdentityUserRole<string>, IdentityUserClaim<int>>
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager manager)
{
// NOTE the authenticationType must match the umbraco one
// defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, Constants.Security.BackOfficeAuthenticationType);
return userIdentity;
}
/// <summary>
/// Gets/sets the user's real name
/// </summary>

View File

@@ -38,5 +38,10 @@ namespace Umbraco.Core.Models.Membership
/// Exposes the basic profile data
/// </summary>
IProfile ProfileData { get; }
/// <summary>
/// The security stamp used by ASP.Net identity
/// </summary>
string SecurityStamp { get; set; }
}
}

View File

@@ -58,6 +58,7 @@ namespace Umbraco.Core.Models.Membership
private IUserType _userType;
private string _name;
private string _securityStamp;
private List<string> _addedSections;
private List<string> _removedSections;
private ObservableCollection<string> _sectionCollection;
@@ -76,6 +77,7 @@ namespace Umbraco.Core.Models.Membership
private bool _defaultToLiveEditing;
private static readonly PropertyInfo SecurityStampSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.SecurityStamp);
private static readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.SessionTimeout);
private static readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartContentId);
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
@@ -232,6 +234,22 @@ namespace Umbraco.Core.Models.Membership
get { return new UserProfile(this); }
}
/// <summary>
/// The security stamp used by ASP.Net identity
/// </summary>
public string SecurityStamp
{
get { return _securityStamp; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_securityStamp = value;
return _securityStamp;
}, _securityStamp, SecurityStampSelector);
}
}
/// <summary>
/// Used internally to check if we need to add a section in the repository to the db
/// </summary>

View File

@@ -51,6 +51,11 @@ namespace Umbraco.Core.Models.Rdbms
[NullSetting(NullSetting = NullSettings.Null)]
[Length(10)]
public string UserLanguage { get; set; }
[Column("securityStampToken")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(255)]
public string SecurityStampToken { get; set; }
[ResultColumn]
public List<User2AppDto> User2AppDtos { get; set; }

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Umbraco.Core.Models.Membership;
@@ -32,7 +33,9 @@ namespace Umbraco.Core.Persistence.Factories
IsLockedOut = dto.NoConsole,
IsApproved = dto.Disabled == false,
Email = dto.Email,
Language = dto.UserLanguage
Language = dto.UserLanguage,
//make it a GUID if it's empty
SecurityStamp = dto.SecurityStampToken.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString() : dto.SecurityStampToken
};
foreach (var app in dto.User2AppDtos)
@@ -61,7 +64,8 @@ namespace Umbraco.Core.Persistence.Factories
UserLanguage = entity.Language,
UserName = entity.Name,
Type = short.Parse(entity.UserType.Id.ToString(CultureInfo.InvariantCulture)),
User2AppDtos = new List<User2AppDto>()
User2AppDtos = new List<User2AppDto>(),
SecurityStampToken = entity.SecurityStamp
};
foreach (var app in entity.AllowedSections)

View File

@@ -98,6 +98,12 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
return new Version(7, 0, 0);
}
//if the error is for umbracoAccess it must be the previous version to 7.3 since that is when it is added
if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoAccess"))))
{
return new Version(7, 2, 5);
}
return UmbracoVersion.Current;
}

View File

@@ -0,0 +1,22 @@
using System.Linq;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZero
{
[Migration("7.3.0", 10, GlobalSettings.UmbracoMigrationName)]
public class AddUserSecurityStampColumn : MigrationBase
{
public override void Up()
{
//Don't exeucte if the column is already there
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("securityStampToken"))) return;
Create.Column("securityStampToken").OnTable("umbracoUser").AsString(255).Nullable();
}
public override void Down()
{
}
}
}

View File

@@ -170,7 +170,8 @@ namespace Umbraco.Core.Persistence.Repositories
{"userName", "Name"},
{"userLogin", "Username"},
{"userEmail", "Email"},
{"userLanguage", "Language"}
{"userLanguage", "Language"},
{"securityStampToken", "SecurityStamp"}
};
//create list of properties that have changed
@@ -183,6 +184,15 @@ namespace Umbraco.Core.Persistence.Repositories
if (dirtyEntity.IsPropertyDirty("RawPasswordValue") && entity.RawPasswordValue.IsNullOrWhiteSpace() == false)
{
changedCols.Add("userPassword");
//special case - when using ASP.Net identity the user manager will take care of updating the security stamp, however
// when not using ASP.Net identity (i.e. old membership providers), we'll need to take care of updating this manually
// so we can just detect if that property is dirty, if it's not we'll set it manually
if (dirtyEntity.IsPropertyDirty("SecurityStamp") == false)
{
userDto.SecurityStampToken = entity.SecurityStamp = Guid.NewGuid().ToString();
changedCols.Add("securityStampToken");
}
}
//only update the changed cols

View File

@@ -21,7 +21,7 @@ namespace Umbraco.Core.Security
: base(store)
{
}
#region What we support do not currently
//NOTE: Not sure if we really want/need to ever support this
@@ -42,12 +42,6 @@ namespace Umbraco.Core.Security
get { return false; }
}
//TODO: Support this
public override bool SupportsUserSecurityStamp
{
get { return false; }
}
//TODO: Support this
public override bool SupportsUserTwoFactor
{

View File

@@ -16,20 +16,22 @@ namespace Umbraco.Core.Security
IUserPasswordStore<BackOfficeIdentityUser, int>,
IUserEmailStore<BackOfficeIdentityUser, int>,
IUserLoginStore<BackOfficeIdentityUser, int>,
IUserRoleStore<BackOfficeIdentityUser, int>
IUserRoleStore<BackOfficeIdentityUser, int>,
IUserSecurityStampStore<BackOfficeIdentityUser, int>
//TODO: This would require additional columns/tables for now people will need to implement this on their own
//IUserPhoneNumberStore<BackOfficeIdentityUser, int>,
//IUserTwoFactorStore<BackOfficeIdentityUser, int>,
//TODO: This will require additional columns/tables
//IUserLockoutStore<BackOfficeIdentityUser, int>
//TODO: Implement this - might need to add a new column for this
// http://stackoverflow.com/questions/19487322/what-is-asp-net-identitys-iusersecuritystampstoretuser-interface
//IUserSecurityStampStore<BackOfficeIdentityUser, int>
//TODO: To do this we need to implement IQueryable - seems pretty overkill?
//TODO: To do this we need to implement IQueryable - we'll have an IQuerable implementation soon with the UmbracoLinqPadDriver implementation
//IQueryableUserStore<BackOfficeIdentityUser, int>
{
private readonly IUserService _userService;
private readonly IExternalLoginService _externalLoginService;
private bool _disposed = false;
public BackOfficeUserStore(IUserService userService, IExternalLoginService externalLoginService, MembershipProviderBase usersMembershipProvider)
{
@@ -53,6 +55,7 @@ namespace Umbraco.Core.Security
/// </summary>
protected override void DisposeResources()
{
_disposed = true;
}
/// <summary>
@@ -62,6 +65,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task CreateAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
var userType = _userService.GetUserTypeByAlias(
@@ -108,6 +112,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public async Task UpdateAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
var asInt = user.Id.TryConvertTo<int>();
@@ -139,6 +144,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task DeleteAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
var asInt = user.Id.TryConvertTo<int>();
@@ -164,6 +170,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task<BackOfficeIdentityUser> FindByIdAsync(int userId)
{
ThrowIfDisposed();
var user = _userService.GetUserById(userId);
if (user == null)
{
@@ -179,6 +186,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task<BackOfficeIdentityUser> FindByNameAsync(string userName)
{
ThrowIfDisposed();
var user = _userService.GetByUsername(userName);
if (user == null)
{
@@ -197,6 +205,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task SetPasswordHashAsync(BackOfficeIdentityUser user, string passwordHash)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
if (passwordHash.IsNullOrWhiteSpace()) throw new ArgumentNullException("passwordHash");
@@ -212,6 +221,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task<string> GetPasswordHashAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
return Task.FromResult(user.PasswordHash);
@@ -224,6 +234,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task<bool> HasPasswordAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
return Task.FromResult(user.PasswordHash.IsNullOrWhiteSpace() == false);
@@ -236,6 +247,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task SetEmailAsync(BackOfficeIdentityUser user, string email)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
if (email.IsNullOrWhiteSpace()) throw new ArgumentNullException("email");
@@ -251,6 +263,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task<string> GetEmailAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
return Task.FromResult(user.Email);
@@ -263,6 +276,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task<bool> GetEmailConfirmedAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
throw new NotImplementedException();
}
@@ -273,6 +287,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task SetEmailConfirmedAsync(BackOfficeIdentityUser user, bool confirmed)
{
ThrowIfDisposed();
throw new NotImplementedException();
}
@@ -283,6 +298,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task<BackOfficeIdentityUser> FindByEmailAsync(string email)
{
ThrowIfDisposed();
var user = _userService.GetByEmail(email);
var result = user == null
? null
@@ -298,6 +314,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task AddLoginAsync(BackOfficeIdentityUser user, UserLoginInfo login)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
if (login == null) throw new ArgumentNullException("login");
@@ -316,6 +333,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task RemoveLoginAsync(BackOfficeIdentityUser user, UserLoginInfo login)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
if (login == null) throw new ArgumentNullException("login");
@@ -335,6 +353,7 @@ namespace Umbraco.Core.Security
/// <returns/>
public Task<IList<UserLoginInfo>> GetLoginsAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
return Task.FromResult((IList<UserLoginInfo>)
user.Logins.Select(l => new UserLoginInfo(l.LoginProvider, l.ProviderKey)).ToList());
@@ -345,7 +364,10 @@ namespace Umbraco.Core.Security
/// </summary>
/// <returns/>
public Task<BackOfficeIdentityUser> FindAsync(UserLoginInfo login)
{
{
ThrowIfDisposed();
if (login == null) throw new ArgumentNullException("login");
//get all logins associated with the login id
var result = _externalLoginService.Find(login).ToArray();
if (result.Any())
@@ -363,6 +385,117 @@ namespace Umbraco.Core.Security
return Task.FromResult<BackOfficeIdentityUser>(null);
}
/// <summary>
/// Adds a user to a role (section)
/// </summary>
/// <param name="user"/><param name="roleName"/>
/// <returns/>
public Task AddToRoleAsync(BackOfficeIdentityUser user, string roleName)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
if (user.AllowedSections.InvariantContains(roleName)) return Task.FromResult(0);
var asInt = user.Id.TryConvertTo<int>();
if (asInt == false)
{
throw new InvalidOperationException("The user id must be an integer to work with the Umbraco");
}
var found = _userService.GetUserById(asInt.Result);
if (found != null)
{
found.AddAllowedSection(roleName);
}
return Task.FromResult(0);
}
/// <summary>
/// Removes the role (allowed section) for the user
/// </summary>
/// <param name="user"/><param name="roleName"/>
/// <returns/>
public Task RemoveFromRoleAsync(BackOfficeIdentityUser user, string roleName)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
if (user.AllowedSections.InvariantContains(roleName) == false) return Task.FromResult(0);
var asInt = user.Id.TryConvertTo<int>();
if (asInt == false)
{
throw new InvalidOperationException("The user id must be an integer to work with the Umbraco");
}
var found = _userService.GetUserById(asInt.Result);
if (found != null)
{
found.RemoveAllowedSection(roleName);
}
return Task.FromResult(0);
}
/// <summary>
/// Returns the roles for this user
/// </summary>
/// <param name="user"/>
/// <returns/>
public Task<IList<string>> GetRolesAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
return Task.FromResult((IList<string>)user.AllowedSections.ToList());
}
/// <summary>
/// Returns true if a user is in the role
/// </summary>
/// <param name="user"/><param name="roleName"/>
/// <returns/>
public Task<bool> IsInRoleAsync(BackOfficeIdentityUser user, string roleName)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
return Task.FromResult(user.AllowedSections.InvariantContains(roleName));
}
/// <summary>
/// Set the security stamp for the user
/// </summary>
/// <param name="user"/><param name="stamp"/>
/// <returns/>
public Task SetSecurityStampAsync(BackOfficeIdentityUser user, string stamp)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
/// <summary>
/// Get the user security stamp
/// </summary>
/// <param name="user"/>
/// <returns/>
public Task<string> GetSecurityStampAsync(BackOfficeIdentityUser user)
{
ThrowIfDisposed();
if (user == null) throw new ArgumentNullException("user");
//the stamp cannot be null, so if it is currently null then we'll just return a hash of the password
return Task.FromResult(user.SecurityStamp.IsNullOrWhiteSpace()
? user.PasswordHash.ToMd5()
: user.SecurityStamp);
}
private BackOfficeIdentityUser AssignLoginsCallback(BackOfficeIdentityUser user)
{
if (user != null)
@@ -424,6 +557,11 @@ namespace Umbraco.Core.Security
anythingChanged = true;
user.StartContentId = identityUser.StartContentId;
}
if (user.SecurityStamp != identityUser.SecurityStamp)
{
anythingChanged = true;
user.SecurityStamp = identityUser.SecurityStamp;
}
if (user.AllowedSections.ContainsAll(identityUser.AllowedSections) == false
|| identityUser.AllowedSections.ContainsAll(user.AllowedSections) == false)
{
@@ -441,76 +579,10 @@ namespace Umbraco.Core.Security
return anythingChanged;
}
/// <summary>
/// Adds a user to a role (section)
/// </summary>
/// <param name="user"/><param name="roleName"/>
/// <returns/>
public Task AddToRoleAsync(BackOfficeIdentityUser user, string roleName)
private void ThrowIfDisposed()
{
if (user.AllowedSections.InvariantContains(roleName)) return Task.FromResult(0);
var asInt = user.Id.TryConvertTo<int>();
if (asInt == false)
{
throw new InvalidOperationException("The user id must be an integer to work with the Umbraco");
}
var found = _userService.GetUserById(asInt.Result);
if (found != null)
{
found.AddAllowedSection(roleName);
_userService.Save(found);
}
return Task.FromResult(0);
}
/// <summary>
/// Removes the role (allowed section) for the user
/// </summary>
/// <param name="user"/><param name="roleName"/>
/// <returns/>
public Task RemoveFromRoleAsync(BackOfficeIdentityUser user, string roleName)
{
if (user.AllowedSections.InvariantContains(roleName) == false) return Task.FromResult(0);
var asInt = user.Id.TryConvertTo<int>();
if (asInt == false)
{
throw new InvalidOperationException("The user id must be an integer to work with the Umbraco");
}
var found = _userService.GetUserById(asInt.Result);
if (found != null)
{
found.RemoveAllowedSection(roleName);
_userService.Save(found);
}
return Task.FromResult(0);
}
/// <summary>
/// Returns the roles for this user
/// </summary>
/// <param name="user"/>
/// <returns/>
public Task<IList<string>> GetRolesAsync(BackOfficeIdentityUser user)
{
return Task.FromResult((IList<string>)user.AllowedSections.ToList());
}
/// <summary>
/// Returns true if a user is in the role
/// </summary>
/// <param name="user"/><param name="roleName"/>
/// <returns/>
public Task<bool> IsInRoleAsync(BackOfficeIdentityUser user, string roleName)
{
return Task.FromResult(user.AllowedSections.InvariantContains(roleName));
if (_disposed)
throw new ObjectDisposedException(GetType().Name);
}
}
}

View File

@@ -381,6 +381,7 @@
<Compile Include="Persistence\Mappers\DomainMapper.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddExternalLoginsTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddPublicAccessTables.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddUserSecurityStampColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\MovePublicAccessXmlDataToDb.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\RemoveHelpTextColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\RemoveLanguageLocaleColumn.cs" />

View File

@@ -30,6 +30,7 @@ using umbraco.providers;
using Microsoft.AspNet.Identity.Owin;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Models.Identity;
using IUser = Umbraco.Core.Models.Membership.IUser;
namespace Umbraco.Web.Editors
{
@@ -146,7 +147,7 @@ namespace Umbraco.Web.Editors
/// </summary>
/// <returns></returns>
[SetAngularAntiForgeryTokens]
public HttpResponseMessage PostLogin(LoginModel loginModel)
public async Task<HttpResponseMessage> PostLogin(LoginModel loginModel)
{
if (UmbracoContext.Security.ValidateBackOfficeCredentials(loginModel.Username, loginModel.Password))
{
@@ -161,6 +162,10 @@ namespace Umbraco.Web.Editors
// we cannot mix HttpContext.Response.Cookies and the way WebApi/Owin work)
var ticket = response.UmbracoLoginWebApi(user);
//Identity does some of it's own checks as well so we need to use it's sign in process too... this will essentially re-create the
// ticket/cookie above but we need to create the ticket now so we can assign the Current Thread User/IPrinciple below
await SignInAsync(Mapper.Map<IUser, BackOfficeIdentityUser>(user), isPersistent: true);
var http = this.TryGetHttpContext();
if (http.Success == false)
{
@@ -211,15 +216,8 @@ namespace Umbraco.Web.Editors
owinContext.Authentication.SignIn(
new AuthenticationProperties() { IsPersistent = isPersistent },
await GenerateUserIdentityAsync(user));
await user.GenerateUserIdentityAsync(UserManager));
}
private async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeIdentityUser user)
{
// NOTE the authenticationType must match the umbraco one
// defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await UserManager.CreateIdentityAsync(user, global::Umbraco.Core.Constants.Security.BackOfficeAuthenticationType);
return userIdentity;
}
}
}

View File

@@ -493,23 +493,14 @@ namespace Umbraco.Web.Editors
OwinContext.Authentication.SignOut(Core.Constants.Security.BackOfficeExternalAuthenticationType);
OwinContext.Authentication.SignIn(
new AuthenticationProperties() {IsPersistent = isPersistent},
await GenerateUserIdentityAsync(user));
}
private async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeIdentityUser user)
{
// NOTE the authenticationType must match the umbraco one
// defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await UserManager.CreateIdentityAsync(user, global::Umbraco.Core.Constants.Security.BackOfficeAuthenticationType);
return userIdentity;
new AuthenticationProperties() {IsPersistent = isPersistent},
await user.GenerateUserIdentityAsync(UserManager));
}
private IAuthenticationManager AuthenticationManager
{
get { return OwinContext.Authentication; }
}
}
/// <summary>
/// Returns the server variables regarding the application state

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Web;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Extensions;
using Microsoft.Owin.Security;
@@ -11,6 +13,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Security;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Security.Identity
{
@@ -84,16 +87,14 @@ namespace Umbraco.Web.Security.Identity
{
Provider = new CookieAuthenticationProvider
{
//TODO: Need to implement IUserSecurityStampStore on BackOfficeUserStore!
//// 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<UmbracoMembersUserManager<UmbracoApplicationUser>, UmbracoApplicationUser, int>(
// TimeSpan.FromMinutes(30),
// (manager, user) => user.GenerateUserIdentityAsync(manager),
// identity => identity.GetUserId<int>())
// 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<BackOfficeUserManager, BackOfficeIdentityUser, int>(
TimeSpan.FromMinutes(30),
(manager, user) => user.GenerateUserIdentityAsync(manager),
identity => identity.GetUserId<int>())
}
});