internal UmbracoMembershipUser GetUmbracoUser(IGroupUnit<ISecurityStore> uow, HiveId id, bool userIsOnline)
        {
            return AppContext.FrameworkContext.ScopedCache.GetOrCreateTyped<UmbracoMembershipUser>(GetUmbracoUserCacheKeyForId(id), () =>
            {
                // TODO: Enable type of extension method GetEntityByRelationType to be passed all the way to the provider
                // so that it can use the typemappers collection to map back to a User

                // APN: I changed SingleOrDefault to FirstOrDefault to guard against YSODs if somehow a duplicate user gets into the store [31/Jan]
                //var userEntity = uow.Repositories
                //    .GetEntityByRelationType<UmbracoMembershipUser>(FixedRelationTypes.DefaultRelationType, _virtualRootId)
                //    .SingleOrDefault(x => x.EntitySchema.Alias == MembershipUserSchema.SchemaAlias && x.Username == username);

                // Get a list of all member relations
                var memberRelations = uow.Repositories.GetChildRelations(VirtualRootId, FixedRelationTypes.DefaultRelationType)
                    .Select(x => x.DestinationId)
                    .ToList();

                // Get a list of all users / members with a matching id
                var userEntities =
                    uow.Repositories.Where(
                        x => x.EntitySchema.Alias == MembershipUserSchema.SchemaAlias
                            && x.Id == id).ToList();

                // Get the first matching user with a member relation
                var userEntity = userEntities.FirstOrDefault(x => memberRelations.Any(y => y.Value == x.Id.Value));

                if (userEntity == null) return null;

                var user = new UmbracoMembershipUser();
                user.SetupFromEntity(userEntity);

                //if (userIsOnline)
                //{
                //    user.LastActivityDate = DateTime.UtcNow;

                //    uow.Repositories.AddOrUpdate(user);
                //    uow.Complete();
                //}

                return user;
            });
        }
        internal UmbracoMembershipUser GetUmbracoUser(IGroupUnit<ISecurityStore> uow, string username, bool userIsOnline)
        {
            return AppContext.FrameworkContext.ScopedCache.GetOrCreateTyped<UmbracoMembershipUser>(GetUmbracoUserCacheKeyForUsername(username), () =>
            {
                // Use FirstOrDefault in case somehow a duplicate user got into the system
                var matchingUsers = uow.Repositories
                    .WithParentIds(FixedRelationTypes.DefaultRelationType, VirtualRootId)
                    .Where(
                        x =>
                        x.EntitySchema.Alias == MembershipUserSchema.SchemaAlias &&
                        x.Attribute<string>(MembershipUserSchema.UsernameAlias) == username)
                    .OrderByDescending(x => x.UtcCreated)
                    .FirstOrDefault();

                if (matchingUsers == null) return null;

                var user = new UmbracoMembershipUser();
                user.SetupFromEntity(matchingUsers);

                //if (userIsOnline)
                //{
                //    user.LastActivityDate = DateTime.UtcNow;

                //    uow.Repositories.AddOrUpdate(user);
                //    uow.Complete();
                //}

                return user;
            });
        }
 private void UpdateScopedCache(string username, UmbracoMembershipUser user, object newValue)
 {
     AppContext.FrameworkContext.ScopedCache.AddOrChange(GetUmbracoUserCacheKeyForUsername(username), s => newValue);
     AppContext.FrameworkContext.ScopedCache.AddOrChange(GetUmbracoUserCacheKeyForId(user.Id), s => newValue);
 }
        /// <summary>
        /// Adds a new membership user to the data source.
        /// </summary>
        /// <param name="username">The user name for the new user.</param>
        /// <param name="password">The password for the new user.</param>
        /// <param name="email">The e-mail address for the new user.</param>
        /// <param name="passwordQuestion">The password question for the new user.</param>
        /// <param name="passwordAnswer">The password answer for the new user</param>
        /// <param name="isApproved">Whether or not the new user is approved to be validated.</param>
        /// <param name="providerUserKey">The unique identifier from the membership data source for the user.</param>
        /// <param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"/> enumeration value indicating whether the user was created successfully.</param>
        /// <returns>
        /// A <see cref="T:System.Web.Security.MembershipUser"/> object populated with the information for the newly created user.
        /// </returns>
        public override MembershipUser CreateUser(string username, string password, string email,
            string passwordQuestion, string passwordAnswer, bool isApproved,
            object providerUserKey, out MembershipCreateStatus status)
        {
            try
            {
                // Validate the username
                if (UserNameExists(username))
                {
                    status = MembershipCreateStatus.DuplicateUserName;
                    return null;
                }

                // Validate the email address
                if (RequiresUniqueEmail && !ValidateEmail(email, HiveId.Empty))
                {
                    status = MembershipCreateStatus.DuplicateEmail;
                    return null;
                }

                // Validate the password
                var e = new ValidatePasswordEventArgs(username, password, true);

                base.OnValidatingPassword(e);

                if (e.Cancel || !ValidatePassword(password))
                {
                    status = MembershipCreateStatus.InvalidPassword;
                    return null;
                }

                using (var uow = Hive.Create())
                {
                    var salt = "";
                    var transformedPassword = TransformPassword(password, ref salt);

                    var user = new UmbracoMembershipUser
                    {
                        Username = username,
                        Password = transformedPassword,
                        PasswordSalt = salt,
                        Email = email,
                        PasswordQuestion = passwordQuestion,
                        PasswordAnswer = passwordAnswer,
                        IsApproved = isApproved,
                        LastActivityDate = DateTime.UtcNow,
                        LastPasswordChangeDate = DateTime.UtcNow,
                        LastLoginDate = DateTime.UtcNow
                    };

                    user.RelationProxies.EnlistParentById(VirtualRootId, FixedRelationTypes.DefaultRelationType);

                    uow.Repositories.AddOrUpdate(user);
                    uow.Complete();

                    status = MembershipCreateStatus.Success;

                    return ConvertUserToMembershipUser(user);
                }
            }
            catch (Exception e)
            {
                status = MembershipCreateStatus.ProviderError;
            }

            return null;
        }
 /// <summary>
 /// Converts the user to membership user.
 /// </summary>
 /// <param name="user">The user.</param>
 /// <param name="providerUserKey">The provider user key.</param>
 /// <returns></returns>
 private MembershipUser ConvertUserToMembershipUser(UmbracoMembershipUser user)
 {
     return new MembershipUser(Name, user.Username, user.Id, user.Email, user.PasswordQuestion,
                               user.Id.ToString(), user.IsApproved, false, user.UtcCreated.UtcDateTime, user.LastLoginDate.UtcDateTime,
                               user.LastActivityDate.UtcDateTime, user.LastPasswordChangeDate.UtcDateTime, DateTimeOffset.MaxValue.UtcDateTime);
 }
        /// <summary>
        /// Validates the user internal.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="password">The password.</param>
        /// <returns></returns>
        private bool ValidateUserInternal(UmbracoMembershipUser user, string password)
        {
            if (user != null && user.IsApproved)
            {
                var salt = user.PasswordSalt;
                // Check if there was a salt used last time, and if not and the passwords match, go for it
                if (salt == null && user.Password == password) return true;
                var transformedPassword = TransformPassword(password, ref salt);
                if (string.Compare(transformedPassword, user.Password) == 0)
                {
                    return true;
                }
            }

            return false;
        }