2015-02-09 17:37:21 +11:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2016-01-05 11:36:52 +01:00
|
|
|
using System.Data;
|
|
|
|
|
using System.Data.Common;
|
2015-02-09 17:37:21 +11:00
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Web.Security;
|
2015-02-19 16:06:07 +01:00
|
|
|
using AutoMapper;
|
2015-02-09 17:37:21 +11:00
|
|
|
using Microsoft.AspNet.Identity;
|
2015-07-01 17:07:29 +02:00
|
|
|
using Microsoft.Owin;
|
2017-07-20 22:02:32 +10:00
|
|
|
using Umbraco.Core.Models;
|
2017-07-18 19:53:34 +10:00
|
|
|
using Umbraco.Core.Models.EntityBase;
|
2015-02-09 17:37:21 +11:00
|
|
|
using Umbraco.Core.Models.Identity;
|
2015-02-19 16:06:07 +01:00
|
|
|
using Umbraco.Core.Models.Membership;
|
2015-02-09 17:37:21 +11:00
|
|
|
using Umbraco.Core.Services;
|
2017-07-18 19:53:34 +10:00
|
|
|
using IUser = Umbraco.Core.Models.Membership.IUser;
|
2017-07-20 22:02:32 +10:00
|
|
|
using Task = System.Threading.Tasks.Task;
|
2015-02-09 17:37:21 +11:00
|
|
|
|
|
|
|
|
namespace Umbraco.Core.Security
|
|
|
|
|
{
|
2015-02-22 15:10:14 +01:00
|
|
|
public class BackOfficeUserStore : DisposableObject,
|
|
|
|
|
IUserStore<BackOfficeIdentityUser, int>,
|
|
|
|
|
IUserPasswordStore<BackOfficeIdentityUser, int>,
|
|
|
|
|
IUserEmailStore<BackOfficeIdentityUser, int>,
|
2015-03-24 13:13:06 +11:00
|
|
|
IUserLoginStore<BackOfficeIdentityUser, int>,
|
2015-03-25 10:57:10 +11:00
|
|
|
IUserRoleStore<BackOfficeIdentityUser, int>,
|
2015-07-01 17:07:29 +02:00
|
|
|
IUserSecurityStampStore<BackOfficeIdentityUser, int>,
|
|
|
|
|
IUserLockoutStore<BackOfficeIdentityUser, int>,
|
|
|
|
|
IUserTwoFactorStore<BackOfficeIdentityUser, int>
|
|
|
|
|
|
2015-03-25 10:57:10 +11:00
|
|
|
//TODO: This would require additional columns/tables for now people will need to implement this on their own
|
|
|
|
|
//IUserPhoneNumberStore<BackOfficeIdentityUser, int>,
|
|
|
|
|
//TODO: To do this we need to implement IQueryable - we'll have an IQuerable implementation soon with the UmbracoLinqPadDriver implementation
|
2015-02-22 15:10:14 +01:00
|
|
|
//IQueryableUserStore<BackOfficeIdentityUser, int>
|
2015-02-09 17:37:21 +11:00
|
|
|
{
|
|
|
|
|
private readonly IUserService _userService;
|
2017-07-20 22:02:32 +10:00
|
|
|
private readonly IEntityService _entityService;
|
2015-02-09 17:37:21 +11:00
|
|
|
private readonly IExternalLoginService _externalLoginService;
|
2015-03-25 10:57:10 +11:00
|
|
|
private bool _disposed = false;
|
2015-02-09 17:37:21 +11:00
|
|
|
|
2017-07-20 22:02:32 +10:00
|
|
|
public BackOfficeUserStore(IUserService userService, IEntityService entityService, IExternalLoginService externalLoginService, MembershipProviderBase usersMembershipProvider)
|
2015-02-09 17:37:21 +11:00
|
|
|
{
|
|
|
|
|
_userService = userService;
|
2017-07-20 22:02:32 +10:00
|
|
|
_entityService = entityService;
|
2015-02-09 17:37:21 +11:00
|
|
|
_externalLoginService = externalLoginService;
|
|
|
|
|
if (userService == null) throw new ArgumentNullException("userService");
|
|
|
|
|
if (usersMembershipProvider == null) throw new ArgumentNullException("usersMembershipProvider");
|
|
|
|
|
if (externalLoginService == null) throw new ArgumentNullException("externalLoginService");
|
|
|
|
|
|
|
|
|
|
_userService = userService;
|
|
|
|
|
_externalLoginService = externalLoginService;
|
|
|
|
|
|
2015-02-19 16:06:07 +01:00
|
|
|
if (usersMembershipProvider.PasswordFormat != MembershipPasswordFormat.Hashed)
|
2015-02-09 17:37:21 +11:00
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Cannot use ASP.Net Identity with UmbracoMembersUserStore when the password format is not Hashed");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObject"/> which handles common required locking logic.
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override void DisposeResources()
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
_disposed = true;
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Insert a new user
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task CreateAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
|
2017-06-15 00:46:23 +02:00
|
|
|
//the password must be 'something' it could be empty if authenticating
|
|
|
|
|
// with an external provider so we'll just generate one and prefix it, the
|
|
|
|
|
// prefix will help us determine if the password hasn't actually been specified yet.
|
|
|
|
|
//this will hash the guid with a salt so should be nicely random
|
|
|
|
|
var aspHasher = new PasswordHasher();
|
|
|
|
|
var emptyPasswordValue = Constants.Security.EmptyPasswordPrefix +
|
|
|
|
|
aspHasher.HashPassword(Guid.NewGuid().ToString("N"));
|
|
|
|
|
|
2017-07-19 14:13:42 +10:00
|
|
|
var userEntity = new User(user.Name, user.Email, user.UserName, emptyPasswordValue)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
DefaultToLiveEditing = false,
|
2015-06-26 16:59:40 +02:00
|
|
|
Language = user.Culture ?? Configuration.GlobalSettings.DefaultUILanguage,
|
2017-05-25 02:03:41 +10:00
|
|
|
StartContentIds = user.StartContentIds ?? new int[] { },
|
|
|
|
|
StartMediaIds = user.StartMediaIds ?? new int[] { },
|
2015-07-01 18:02:58 +02:00
|
|
|
IsLockedOut = user.IsLockedOut,
|
2015-02-19 16:06:07 +01:00
|
|
|
};
|
|
|
|
|
|
2017-07-19 14:13:42 +10:00
|
|
|
UpdateMemberProperties(userEntity, user);
|
2017-06-15 00:46:23 +02:00
|
|
|
|
2017-07-28 14:27:32 +10:00
|
|
|
//TODO: We should deal with Roles --> User Groups here which we currently are not doing
|
|
|
|
|
|
2017-07-19 14:13:42 +10:00
|
|
|
_userService.Save(userEntity);
|
2015-02-19 16:06:07 +01:00
|
|
|
|
2017-07-19 14:13:42 +10:00
|
|
|
if (userEntity.Id == 0) throw new DataException("Could not create the user, check logs for details");
|
2016-01-05 11:36:52 +01:00
|
|
|
|
2015-02-19 16:06:07 +01:00
|
|
|
//re-assign id
|
2017-07-19 14:13:42 +10:00
|
|
|
user.Id = userEntity.Id;
|
2015-02-19 16:06:07 +01:00
|
|
|
|
|
|
|
|
return Task.FromResult(0);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Update a user
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
2015-02-19 16:06:07 +01:00
|
|
|
public async Task UpdateAsync(BackOfficeIdentityUser user)
|
2015-02-09 17:37:21 +11:00
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2017-09-22 13:55:15 +10:00
|
|
|
// we have to remember whether Logins property is dirty, since the UpdateMemberProperties will reset it.
|
|
|
|
|
var isLoginsPropertyDirty = user.IsPropertyDirty("Logins");
|
|
|
|
|
|
2015-02-19 16:06:07 +01:00
|
|
|
if (UpdateMemberProperties(found, user))
|
|
|
|
|
{
|
|
|
|
|
_userService.Save(found);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-22 13:55:15 +10:00
|
|
|
if (isLoginsPropertyDirty)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
var logins = await GetLoginsAsync(user);
|
|
|
|
|
_externalLoginService.SaveUserLogins(found.Id, logins);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Delete a user
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task DeleteAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
_userService.Delete(found);
|
|
|
|
|
}
|
|
|
|
|
_externalLoginService.DeleteUserLogins(asInt.Result);
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(0);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Finds a user
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="userId"/>
|
|
|
|
|
/// <returns/>
|
2015-06-26 16:59:40 +02:00
|
|
|
public async Task<BackOfficeIdentityUser> FindByIdAsync(int userId)
|
2015-02-09 17:37:21 +11:00
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
var user = _userService.GetUserById(userId);
|
|
|
|
|
if (user == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2015-06-26 16:59:40 +02:00
|
|
|
return await Task.FromResult(AssignLoginsCallback(Mapper.Map<BackOfficeIdentityUser>(user)));
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Find a user by name
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="userName"/>
|
|
|
|
|
/// <returns/>
|
2015-06-26 16:59:40 +02:00
|
|
|
public async Task<BackOfficeIdentityUser> FindByNameAsync(string userName)
|
2015-02-09 17:37:21 +11:00
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
var user = _userService.GetByUsername(userName);
|
|
|
|
|
if (user == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var result = AssignLoginsCallback(Mapper.Map<BackOfficeIdentityUser>(user));
|
|
|
|
|
|
2015-06-26 16:59:40 +02:00
|
|
|
return await Task.FromResult(result);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
2017-07-20 22:02:32 +10:00
|
|
|
|
2015-02-09 17:37:21 +11:00
|
|
|
/// <summary>
|
|
|
|
|
/// Set the user password hash
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="passwordHash"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task SetPasswordHashAsync(BackOfficeIdentityUser user, string passwordHash)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
2017-06-15 00:46:23 +02:00
|
|
|
if (string.IsNullOrEmpty(passwordHash)) throw new ArgumentException("Value cannot be null or empty.", "passwordHash");
|
2015-02-19 16:06:07 +01:00
|
|
|
|
|
|
|
|
user.PasswordHash = passwordHash;
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(0);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get the user password hash
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<string> GetPasswordHashAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
2017-06-15 00:46:23 +02:00
|
|
|
|
2015-02-19 16:06:07 +01:00
|
|
|
return Task.FromResult(user.PasswordHash);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns true if a user has a password set
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<bool> HasPasswordAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
|
2017-06-15 00:46:23 +02:00
|
|
|
return Task.FromResult(string.IsNullOrEmpty(user.PasswordHash) == false);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set the user email
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="email"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task SetEmailAsync(BackOfficeIdentityUser user, string email)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
if (email.IsNullOrWhiteSpace()) throw new ArgumentNullException("email");
|
|
|
|
|
|
|
|
|
|
user.Email = email;
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(0);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get the user email
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<string> GetEmailAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(user.Email);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns true if the user email is confirmed
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<bool> GetEmailConfirmedAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2017-06-13 18:38:16 +02:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(user.EmailConfirmed);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets whether the user email is confirmed
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="confirmed"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task SetEmailConfirmedAsync(BackOfficeIdentityUser user, bool confirmed)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2017-06-13 18:38:16 +02:00
|
|
|
user.EmailConfirmed = confirmed;
|
|
|
|
|
return Task.FromResult(0);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the user associated with this email
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="email"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<BackOfficeIdentityUser> FindByEmailAsync(string email)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
var user = _userService.GetByEmail(email);
|
|
|
|
|
var result = user == null
|
|
|
|
|
? null
|
|
|
|
|
: Mapper.Map<BackOfficeIdentityUser>(user);
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(AssignLoginsCallback(result));
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a user login with the specified provider and key
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="login"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task AddLoginAsync(BackOfficeIdentityUser user, UserLoginInfo login)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
if (login == null) throw new ArgumentNullException("login");
|
|
|
|
|
|
|
|
|
|
var logins = user.Logins;
|
|
|
|
|
var instance = new IdentityUserLogin(login.LoginProvider, login.ProviderKey, user.Id);
|
|
|
|
|
var userLogin = instance;
|
|
|
|
|
logins.Add(userLogin);
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(0);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Removes the user login with the specified combination if it exists
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="login"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task RemoveLoginAsync(BackOfficeIdentityUser user, UserLoginInfo login)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
if (login == null) throw new ArgumentNullException("login");
|
|
|
|
|
|
|
|
|
|
var provider = login.LoginProvider;
|
|
|
|
|
var key = login.ProviderKey;
|
|
|
|
|
var userLogin = user.Logins.SingleOrDefault((l => l.LoginProvider == provider && l.ProviderKey == key));
|
|
|
|
|
if (userLogin != null)
|
|
|
|
|
user.Logins.Remove(userLogin);
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(0);
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the linked accounts for this user
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<IList<UserLoginInfo>> GetLoginsAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
2015-02-19 16:06:07 +01:00
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
return Task.FromResult((IList<UserLoginInfo>)
|
|
|
|
|
user.Logins.Select(l => new UserLoginInfo(l.LoginProvider, l.ProviderKey)).ToList());
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the user associated with this login
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<BackOfficeIdentityUser> FindAsync(UserLoginInfo login)
|
2015-03-25 10:57:10 +11:00
|
|
|
{
|
|
|
|
|
ThrowIfDisposed();
|
|
|
|
|
if (login == null) throw new ArgumentNullException("login");
|
|
|
|
|
|
2015-02-09 17:37:21 +11:00
|
|
|
//get all logins associated with the login id
|
|
|
|
|
var result = _externalLoginService.Find(login).ToArray();
|
|
|
|
|
if (result.Any())
|
|
|
|
|
{
|
2017-07-18 19:53:34 +10:00
|
|
|
//return the first user that matches the result
|
|
|
|
|
BackOfficeIdentityUser output = null;
|
|
|
|
|
foreach (var l in result)
|
|
|
|
|
{
|
|
|
|
|
var user = _userService.GetUserById(l.UserId);
|
|
|
|
|
if (user != null)
|
|
|
|
|
{
|
|
|
|
|
output = Mapper.Map<BackOfficeIdentityUser>(user);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-09 17:37:21 +11:00
|
|
|
|
2015-02-19 16:06:07 +01:00
|
|
|
return Task.FromResult(AssignLoginsCallback(output));
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Task.FromResult<BackOfficeIdentityUser>(null);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-25 10:57:10 +11:00
|
|
|
|
|
|
|
|
/// <summary>
|
2016-10-27 18:11:46 +02:00
|
|
|
/// Adds a user to a role (user group)
|
2015-03-25 10:57:10 +11:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="roleName"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task AddToRoleAsync(BackOfficeIdentityUser user, string roleName)
|
2017-07-20 22:12:13 +10:00
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
2017-07-20 22:12:13 +10:00
|
|
|
if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("Value cannot be null or whitespace.", "roleName");
|
2015-03-25 10:57:10 +11:00
|
|
|
|
2017-07-20 22:12:13 +10:00
|
|
|
var userRole = user.Roles.SingleOrDefault(r => r.RoleId == roleName);
|
2017-07-19 14:13:42 +10:00
|
|
|
|
2017-07-20 22:12:13 +10:00
|
|
|
if (userRole == null)
|
2015-03-25 10:57:10 +11:00
|
|
|
{
|
2017-07-20 22:12:13 +10:00
|
|
|
user.AddRole(roleName);
|
2015-03-25 10:57:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-10-27 18:11:46 +02:00
|
|
|
/// Removes the role (user group) for the user
|
2015-03-25 10:57:10 +11:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="roleName"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task RemoveFromRoleAsync(BackOfficeIdentityUser user, string roleName)
|
2017-07-20 22:12:13 +10:00
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
ThrowIfDisposed();
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
2017-07-20 22:12:13 +10:00
|
|
|
if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("Value cannot be null or whitespace.", "roleName");
|
2015-03-25 10:57:10 +11:00
|
|
|
|
2017-07-20 22:12:13 +10:00
|
|
|
var userRole = user.Roles.SingleOrDefault(r => r.RoleId == roleName);
|
2017-07-19 14:13:42 +10:00
|
|
|
|
2017-07-20 22:12:13 +10:00
|
|
|
if (userRole != null)
|
2015-03-25 10:57:10 +11:00
|
|
|
{
|
2017-07-20 22:12:13 +10:00
|
|
|
user.Roles.Remove(userRole);
|
2015-03-25 10:57:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Task.FromResult(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-10-27 18:11:46 +02:00
|
|
|
/// Returns the roles (user groups) for this user
|
2015-03-25 10:57:10 +11:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<IList<string>> GetRolesAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
ThrowIfDisposed();
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
2017-07-20 22:02:32 +10:00
|
|
|
return Task.FromResult((IList<string>)user.Roles.Select(x => x.RoleId).ToList());
|
2015-03-25 10:57:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <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");
|
2017-07-20 22:02:32 +10:00
|
|
|
return Task.FromResult(user.Roles.Select(x => x.RoleId).InvariantContains(roleName));
|
2015-03-25 10:57:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <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()
|
2017-05-10 13:35:28 -07:00
|
|
|
? user.PasswordHash.GenerateHash()
|
2015-03-25 10:57:10 +11:00
|
|
|
: user.SecurityStamp);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-09 17:37:21 +11:00
|
|
|
private BackOfficeIdentityUser AssignLoginsCallback(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
if (user != null)
|
|
|
|
|
{
|
|
|
|
|
user.SetLoginsCallback(new Lazy<IEnumerable<IIdentityUserLogin>>(() =>
|
|
|
|
|
_externalLoginService.GetAll(user.Id)));
|
|
|
|
|
}
|
|
|
|
|
return user;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 17:07:29 +02:00
|
|
|
/// <summary>
|
|
|
|
|
/// Sets whether two factor authentication is enabled for the user
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="enabled"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public virtual Task SetTwoFactorEnabledAsync(BackOfficeIdentityUser user, bool enabled)
|
|
|
|
|
{
|
|
|
|
|
user.TwoFactorEnabled = false;
|
|
|
|
|
return Task.FromResult(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns whether two factor authentication is enabled for the user
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public virtual Task<bool> GetTwoFactorEnabledAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
return Task.FromResult(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region IUserLockoutStore
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the DateTimeOffset that represents the end of a user's lockout, any time in the past should be considered not locked out.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Currently we do not suport a timed lock out, when they are locked out, an admin will have to reset the status
|
|
|
|
|
/// </remarks>
|
|
|
|
|
public Task<DateTimeOffset> GetLockoutEndDateAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
|
|
|
|
|
return user.LockoutEndDateUtc.HasValue
|
2015-07-01 18:02:58 +02:00
|
|
|
? Task.FromResult(DateTimeOffset.MaxValue)
|
|
|
|
|
: Task.FromResult(DateTimeOffset.MinValue);
|
2015-07-01 17:07:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Locks a user out until the specified end date (set to a past date, to unlock a user)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="lockoutEnd"/>
|
|
|
|
|
/// <returns/>
|
2017-08-15 12:31:32 +10:00
|
|
|
/// <remarks>
|
|
|
|
|
/// Currently we do not suport a timed lock out, when they are locked out, an admin will have to reset the status
|
|
|
|
|
/// </remarks>
|
2015-07-01 17:07:29 +02:00
|
|
|
public Task SetLockoutEndDateAsync(BackOfficeIdentityUser user, DateTimeOffset lockoutEnd)
|
|
|
|
|
{
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
user.LockoutEndDateUtc = lockoutEnd.UtcDateTime;
|
|
|
|
|
return Task.FromResult(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to record when an attempt to access the user has failed
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<int> IncrementAccessFailedCountAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
user.AccessFailedCount++;
|
|
|
|
|
return Task.FromResult(user.AccessFailedCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to reset the access failed count, typically after the account is successfully accessed
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task ResetAccessFailedCountAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
2015-07-01 18:02:58 +02:00
|
|
|
user.AccessFailedCount = 0;
|
|
|
|
|
return Task.FromResult(0);
|
2015-07-01 17:07:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the current number of failed access attempts. This number usually will be reset whenever the password is
|
|
|
|
|
/// verified or the account is locked out.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<int> GetAccessFailedCountAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
return Task.FromResult(user.AccessFailedCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2015-07-01 18:02:58 +02:00
|
|
|
/// Returns true
|
2015-07-01 17:07:29 +02:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task<bool> GetLockoutEnabledAsync(BackOfficeIdentityUser user)
|
|
|
|
|
{
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
return Task.FromResult(user.LockoutEnabled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2015-07-01 18:02:58 +02:00
|
|
|
/// Doesn't actually perform any function, users can always be locked out
|
2015-07-01 17:07:29 +02:00
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="user"/><param name="enabled"/>
|
|
|
|
|
/// <returns/>
|
|
|
|
|
public Task SetLockoutEnabledAsync(BackOfficeIdentityUser user, bool enabled)
|
|
|
|
|
{
|
|
|
|
|
if (user == null) throw new ArgumentNullException("user");
|
|
|
|
|
user.LockoutEnabled = enabled;
|
|
|
|
|
return Task.FromResult(0);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2017-07-19 14:13:42 +10:00
|
|
|
private bool UpdateMemberProperties(IUser user, BackOfficeIdentityUser identityUser)
|
2015-02-09 17:37:21 +11:00
|
|
|
{
|
2015-02-19 16:06:07 +01:00
|
|
|
var anythingChanged = false;
|
2017-07-19 14:13:42 +10:00
|
|
|
|
|
|
|
|
//don't assign anything if nothing has changed as this will trigger the track changes of the model
|
|
|
|
|
|
|
|
|
|
if (identityUser.IsPropertyDirty("LastLoginDateUtc")
|
|
|
|
|
|| (user.LastLoginDate != default(DateTime) && identityUser.LastLoginDateUtc.HasValue == false)
|
2017-02-13 16:47:04 +11:00
|
|
|
|| identityUser.LastLoginDateUtc.HasValue && user.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)
|
|
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.LastLoginDate = identityUser.LastLoginDateUtc.Value.ToLocalTime();
|
|
|
|
|
}
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("EmailConfirmed")
|
|
|
|
|
|| (user.EmailConfirmedDate.HasValue && user.EmailConfirmedDate.Value != default(DateTime) && identityUser.EmailConfirmed == false)
|
2017-06-13 18:38:16 +02:00
|
|
|
|| ((user.EmailConfirmedDate.HasValue == false || user.EmailConfirmedDate.Value == default(DateTime)) && identityUser.EmailConfirmed))
|
|
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.EmailConfirmedDate = identityUser.EmailConfirmed ? (DateTime?)DateTime.Now : null;
|
|
|
|
|
}
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("Name")
|
|
|
|
|
&& user.Name != identityUser.Name && identityUser.Name.IsNullOrWhiteSpace() == false)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.Name = identityUser.Name;
|
|
|
|
|
}
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("Email")
|
|
|
|
|
&& user.Email != identityUser.Email && identityUser.Email.IsNullOrWhiteSpace() == false)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.Email = identityUser.Email;
|
|
|
|
|
}
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("AccessFailedCount")
|
|
|
|
|
&& user.FailedPasswordAttempts != identityUser.AccessFailedCount)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.FailedPasswordAttempts = identityUser.AccessFailedCount;
|
|
|
|
|
}
|
2015-07-01 18:02:58 +02:00
|
|
|
if (user.IsLockedOut != identityUser.IsLockedOut)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
2015-07-01 18:02:58 +02:00
|
|
|
user.IsLockedOut = identityUser.IsLockedOut;
|
2016-11-17 16:46:06 +01:00
|
|
|
|
|
|
|
|
if (user.IsLockedOut)
|
|
|
|
|
{
|
|
|
|
|
//need to set the last lockout date
|
|
|
|
|
user.LastLockoutDate = DateTime.Now;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-19 16:06:07 +01:00
|
|
|
}
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("UserName")
|
|
|
|
|
&& user.Username != identityUser.UserName && identityUser.UserName.IsNullOrWhiteSpace() == false)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.Username = identityUser.UserName;
|
|
|
|
|
}
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("PasswordHash")
|
|
|
|
|
&& user.RawPasswordValue != identityUser.PasswordHash && identityUser.PasswordHash.IsNullOrWhiteSpace() == false)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.RawPasswordValue = identityUser.PasswordHash;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("Culture")
|
|
|
|
|
&& user.Language != identityUser.Culture && identityUser.Culture.IsNullOrWhiteSpace() == false)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.Language = identityUser.Culture;
|
|
|
|
|
}
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("StartMediaIds")
|
|
|
|
|
&& user.StartMediaIds.UnsortedSequenceEqual(identityUser.StartMediaIds) == false)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
2017-05-25 02:03:41 +10:00
|
|
|
user.StartMediaIds = identityUser.StartMediaIds;
|
2015-02-19 16:06:07 +01:00
|
|
|
}
|
2017-07-19 14:13:42 +10:00
|
|
|
if (identityUser.IsPropertyDirty("StartContentIds")
|
|
|
|
|
&& user.StartContentIds.UnsortedSequenceEqual(identityUser.StartContentIds) == false)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
2017-05-25 02:03:41 +10:00
|
|
|
user.StartContentIds = identityUser.StartContentIds;
|
2015-02-19 16:06:07 +01:00
|
|
|
}
|
2015-03-25 10:57:10 +11:00
|
|
|
if (user.SecurityStamp != identityUser.SecurityStamp)
|
|
|
|
|
{
|
|
|
|
|
anythingChanged = true;
|
|
|
|
|
user.SecurityStamp = identityUser.SecurityStamp;
|
|
|
|
|
}
|
2017-05-26 11:17:06 +10:00
|
|
|
|
2017-07-20 22:02:32 +10:00
|
|
|
//TODO: Fix this for Groups too
|
|
|
|
|
if (identityUser.IsPropertyDirty("Roles") || identityUser.IsPropertyDirty("Groups"))
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
2017-07-19 14:13:42 +10:00
|
|
|
var userGroupAliases = user.Groups.Select(x => x.Alias).ToArray();
|
2017-05-26 11:17:06 +10:00
|
|
|
|
2017-07-20 22:02:32 +10:00
|
|
|
var identityUserRoles = identityUser.Roles.Select(x => x.RoleId).ToArray();
|
|
|
|
|
var identityUserGroups = identityUser.Groups.Select(x => x.Alias).ToArray();
|
|
|
|
|
|
|
|
|
|
var combinedAliases = identityUserRoles.Union(identityUserGroups).ToArray();
|
|
|
|
|
|
|
|
|
|
if (userGroupAliases.ContainsAll(combinedAliases) == false
|
|
|
|
|
|| combinedAliases.ContainsAll(userGroupAliases) == false)
|
2015-02-19 16:06:07 +01:00
|
|
|
{
|
2017-07-19 14:13:42 +10:00
|
|
|
anythingChanged = true;
|
|
|
|
|
|
|
|
|
|
//clear out the current groups (need to ToArray since we are modifying the iterator)
|
|
|
|
|
user.ClearGroups();
|
|
|
|
|
|
2017-07-20 22:02:32 +10:00
|
|
|
//go lookup all these groups
|
|
|
|
|
var groups = _userService.GetUserGroupsByAlias(combinedAliases).Select(x => x.ToReadOnlyGroup()).ToArray();
|
|
|
|
|
|
2017-07-19 14:13:42 +10:00
|
|
|
//use all of the ones assigned and add them
|
2017-07-20 22:02:32 +10:00
|
|
|
foreach (var group in groups)
|
2017-07-19 14:13:42 +10:00
|
|
|
{
|
|
|
|
|
user.AddGroup(group);
|
|
|
|
|
}
|
2017-07-20 22:02:32 +10:00
|
|
|
|
|
|
|
|
//re-assign
|
|
|
|
|
identityUser.Groups = groups;
|
2015-02-19 16:06:07 +01:00
|
|
|
}
|
|
|
|
|
}
|
2017-07-20 22:02:32 +10:00
|
|
|
|
|
|
|
|
//we should re-set the calculated start nodes
|
|
|
|
|
identityUser.CalculatedMediaStartNodeIds = user.CalculateMediaStartNodeIds(_entityService);
|
|
|
|
|
identityUser.CalculatedContentStartNodeIds = user.CalculateContentStartNodeIds(_entityService);
|
2015-02-19 16:06:07 +01:00
|
|
|
|
2017-07-18 19:53:34 +10:00
|
|
|
//reset all changes
|
2017-07-19 14:13:42 +10:00
|
|
|
identityUser.ResetDirtyProperties(false);
|
2017-07-18 19:53:34 +10:00
|
|
|
|
2015-02-19 16:06:07 +01:00
|
|
|
return anythingChanged;
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
2015-02-19 16:06:07 +01:00
|
|
|
|
2015-07-01 17:07:29 +02:00
|
|
|
|
2015-03-25 10:57:10 +11:00
|
|
|
private void ThrowIfDisposed()
|
2015-03-24 13:13:06 +11:00
|
|
|
{
|
2015-03-25 10:57:10 +11:00
|
|
|
if (_disposed)
|
|
|
|
|
throw new ObjectDisposedException(GetType().Name);
|
2015-03-24 13:13:06 +11:00
|
|
|
}
|
2017-07-18 19:53:34 +10:00
|
|
|
|
2015-02-09 17:37:21 +11:00
|
|
|
}
|
|
|
|
|
}
|