private void CreateOrUpdateUserAndProfile(string username, bool authenticated, DateTime now, string blobName, int size)
        {
            SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username");

            providerRetry(() =>
                              {
                                  TableServiceContext context = CreateDataServiceContext();
                                  DataServiceQuery<MembershipRow> queryObj = context.CreateQuery<MembershipRow>(tableName);
                                  var query = (from user in queryObj
                                               where user.PartitionKey == SecUtility.CombineToKey(applicationName, username)
                                               select user).AsTableServiceQuery();
                                  IEnumerable<MembershipRow> users = query.Execute();

                                  // instantiate results
                                  List<MembershipRow> userList = null;
                                  if (users != null)
                                  {
                                      userList = new List<MembershipRow>(users);
                                  }

                                  if (userList != null && userList.Count > 0)
                                  {
                                      MembershipRow current = userList.First();
                                      if (current.IsAnonymous != !authenticated)
                                      {
                                          // this is an error because we would need to create a user with the same name
                                          // this should not happen
                                          throw new ProviderException(
                                              "A user with the same name but with a different authentication status already exists!");
                                      }

                                      current.LastActivityDateUtc = now;
                                      current.ProfileBlobName = blobName;
                                      current.ProfileSize = size;
                                      current.ProfileLastUpdatedUtc = now;
                                      context.UpdateObject(current);
                                  }
                                  else
                                  {
                                      if (authenticated)
                                      {
                                          Log.Write(EventKind.Warning, "The authenticated user does not exist in the database.");
                                      }

                                      var member = new MembershipRow(applicationName, username)
                                                       {
                                                           LastActivityDateUtc = now,
                                                           IsAnonymous = !authenticated,
                                                           ProfileBlobName = blobName,
                                                           ProfileSize = size,
                                                           ProfileLastUpdatedUtc = now,
                                                           ProfileIsCreatedByProfileProvider = true
                                                       };
                                      context.AddObject(tableName, member);
                                  }

                                  context.SaveChanges();
                              });
        }
        private bool DoesProfileExistAndUpdateUser(string username, out MembershipRow prof)
        {
            SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username");

            int curRetry = 0;
            do
            {
                try
                {
                    TableServiceContext context = CreateDataServiceContext();
                    DataServiceQuery<MembershipRow> queryObj = context.CreateQuery<MembershipRow>(tableName);
                    var query = (from profile in queryObj
                                 where profile.PartitionKey == SecUtility.CombineToKey(applicationName, username)
                                 select profile).AsTableServiceQuery();
                    IEnumerable<MembershipRow> profiles = query.Execute();
                    if (profiles == null)
                    {
                        prof = null;
                        return false;
                    }

                    // instantiate results
                    var profileList = new List<MembershipRow>(profiles);
                    if (profileList.Count > 1)
                    {
                        throw new ProviderException("Multiple profile rows for the same user!");
                    }

                    if (profileList.Count == 1)
                    {
                        prof = profileList.First();
                        if (!string.IsNullOrEmpty(prof.ProfileBlobName))
                        {
                            prof.LastActivityDateUtc = DateTime.UtcNow;
                            context.UpdateObject(prof);
                            context.SaveChangesWithRetries();
                            return true;
                        }

                        return false;
                    }

                    prof = null;
                    return false;
                }
                catch (InvalidOperationException e)
                {
                    if (e.InnerException is DataServiceClientException &&
                        (e.InnerException as DataServiceClientException).StatusCode == (int) HttpStatusCode.PreconditionFailed)
                    {
                        continue;
                    }

                    throw new ProviderException("Error accessing storage.", e);
                }
            } while (curRetry++ < NumRetries);

            prof = null;
            return false;
        }
        /// <summary>
        ///   Deletes the user from the membership table.
        ///   This implementation ignores the deleteAllRelatedData argument
        /// </summary>
        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username");

            try
            {
                TableServiceContext svc = CreateDataServiceContext();
                MembershipRow user = new MembershipRow(_applicationName, username);
                svc.AttachTo(_tableName, user, "*");
                svc.DeleteObject(user);
                svc.SaveChangesWithRetries();
                return true;
            }
            catch (InvalidOperationException e)
            {
                if (e.InnerException is DataServiceClientException)
                {
                    var dsce = e.InnerException as DataServiceClientException;

                    if (dsce.StatusCode == (int) HttpStatusCode.NotFound)
                    {
                        return false;
                    }
                    else
                    {
                        throw new ProviderException("Error accessing the data source.", e);
                    }
                }
                else
                {
                    throw;
                }
            }
        }
        /// <summary>
        ///   Creates a new user and stores it in the membership table. We do not use retry policies in this 
        ///   highly security-related function. All error conditions are directly exposed to the user.
        /// </summary>
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion,
                                                  string passwordAnswer, bool isApproved, object providerUserKey,
                                                  out MembershipCreateStatus status)
        {
            if (!SecUtility.ValidateParameter(ref password, true, true, false, MaxTablePasswordSize))
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }

            string salt = GenerateSalt();
            string pass = EncodePassword(password, (int) _passwordFormat, salt);
            if (pass.Length > MaxTablePasswordSize)
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }

            string encodedPasswordAnswer;
            if (passwordAnswer != null)
            {
                passwordAnswer = passwordAnswer.Trim();
            }

            if (!string.IsNullOrEmpty(passwordAnswer))
            {
                if (passwordAnswer.Length > MaxTablePasswordSize)
                {
                    status = MembershipCreateStatus.InvalidAnswer;
                    return null;
                }
                encodedPasswordAnswer = EncodePassword(passwordAnswer.ToLowerInvariant(), (int) _passwordFormat, salt);
            }
            else
            {
                encodedPasswordAnswer = passwordAnswer;
            }

            if (!SecUtility.ValidateParameter(ref encodedPasswordAnswer, RequiresQuestionAndAnswer, true, false, MaxTablePasswordSize))
            {
                status = MembershipCreateStatus.InvalidAnswer;
                return null;
            }

            if (!SecUtility.ValidateParameter(ref username, true, true, true, Constants.MaxTableUsernameLength))
            {
                status = MembershipCreateStatus.InvalidUserName;
                return null;
            }

            if (!SecUtility.ValidateParameter(ref email,
                                              RequiresUniqueEmail,
                                              RequiresUniqueEmail,
                                              false,
                                              Constants.MaxTableUsernameLength))
            {
                status = MembershipCreateStatus.InvalidEmail;
                return null;
            }

            if (!SecUtility.ValidateParameter(ref passwordQuestion, RequiresQuestionAndAnswer, true, false, Constants.MaxTableUsernameLength))
            {
                status = MembershipCreateStatus.InvalidQuestion;
                return null;
            }

            if (providerUserKey != null)
            {
                if (!(providerUserKey is Guid))
                {
                    status = MembershipCreateStatus.InvalidProviderUserKey;
                    return null;
                }
            }

            if (!EvaluatePasswordRequirements(password))
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }

            ValidatePasswordEventArgs e = new ValidatePasswordEventArgs(username, password, true);
            OnValidatingPassword(e);

            if (e.Cancel)
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }

            // Check whether a user with the same email address already exists.
            // The danger here is (as we don't have transaction support here) that
            // there are overlapping requests for creating two users with the same email
            // address at the same point in time.
            // A solution for this would be to have a separate table for email addresses.
            // At this point here in the code we would try to insert this user's email address into the
            // table and thus check whether the email is unique (the email would be the primary key of the
            // separate table). There are quite some problems
            // associated with that. For example, what happens if the user creation fails etc., stale data in the
            // email table etc.
            // Another solution is to already insert the user at this point and then check at the end of this
            // funcation whether the email is unique.
            if (RequiresUniqueEmail && !IsUniqueEmail(email))
            {
                status = MembershipCreateStatus.DuplicateEmail;
                return null;
            }

            try
            {
                TableServiceContext svc = CreateDataServiceContext();
                MembershipRow newUser = new MembershipRow(_applicationName, username);
                if (providerUserKey == null)
                {
                    providerUserKey = Guid.NewGuid();
                }
                newUser.UserId = (Guid) providerUserKey;
                newUser.Password = pass;
                newUser.PasswordSalt = salt;
                newUser.Email = (email == null) ? string.Empty : email;
                ;
                newUser.PasswordQuestion = (passwordQuestion == null) ? string.Empty : passwordQuestion;
                newUser.PasswordAnswer = (encodedPasswordAnswer == null) ? string.Empty : encodedPasswordAnswer;
                newUser.IsApproved = isApproved;
                newUser.PasswordFormat = (int) _passwordFormat;
                DateTime now = DateTime.UtcNow;
                newUser.CreateDateUtc = now;
                newUser.LastActivityDateUtc = now;
                newUser.LastPasswordChangedDateUtc = now;
                newUser.LastLoginDateUtc = now;
                newUser.IsLockedOut = false;

                svc.AddObject(_tableName, newUser);
                svc.SaveChanges();

                status = MembershipCreateStatus.Success;
                return new MembershipUser(Name,
                                          username,
                                          providerUserKey,
                                          email,
                                          passwordQuestion,
                                          null,
                                          isApproved,
                                          false,
                                          now.ToLocalTime(),
                                          now.ToLocalTime(),
                                          now.ToLocalTime(),
                                          now.ToLocalTime(),
                                          ProviderConfiguration.MinSupportedDateTime);
            }
            catch (InvalidOperationException ex)
            {
                if (ex.InnerException is DataServiceClientException && (ex.InnerException as DataServiceClientException).StatusCode == (int) HttpStatusCode.Conflict)
                {
                    // in this case, some membership providers update the last activity time of the user
                    // we don't do this in this implementation because it would add another roundtrip
                    status = MembershipCreateStatus.DuplicateUserName;
                    return null;
                }
                else if (ex.InnerException is DataServiceClientException)
                {
                    throw new ProviderException("Cannot add user to membership data store because of problems when accessing the data store.", ex);
                }
                else
                {
                    throw;
                }
            }
        }
        private bool IsUniqueEmail(string email, out MembershipRow member)
        {
            member = null;
            SecUtility.ValidateParameter(ref email, true, true, true, ProviderConfiguration.MaxStringPropertySizeInChars);

            TableServiceContext svc = CreateDataServiceContext();
            DataServiceQuery<MembershipRow> queryObj = svc.CreateQuery<MembershipRow>(_tableName);

            var query = (from user in queryObj
                         where user.PartitionKey.CompareTo(SecUtility.EscapedFirst(_applicationName)) > 0 &&
                               user.PartitionKey.CompareTo(SecUtility.NextComparisonString(SecUtility.EscapedFirst(_applicationName))) < 0 &&
                               user.Email == email &&
                               user.ProfileIsCreatedByProfileProvider == false
                         select user).AsTableServiceQuery();

            IEnumerable<MembershipRow> allUsers = query.Execute();
            if (allUsers == null)
            {
                return true;
            }
            IEnumerator<MembershipRow> e = allUsers.GetEnumerator();
            if (e == null)
            {
                return true;
            }
            // e.Reset() throws a not implemented exception
            // according to the spec, the enumerator is at the beginning of the collections after a call to GetEnumerator()

            if (!e.MoveNext())
            {
                return true;
            }
            else
            {
                member = e.Current;
            }
            return false;
        }
        private bool CheckPassword(DataServiceContext svc, string username, string password, bool updateLastLoginActivityDate, bool failIfNotApproved, out MembershipRow member)
        {
            bool createContextAndWriteState = false;
            try
            {
                if (svc == null)
                {
                    svc = CreateDataServiceContext();
                    createContextAndWriteState = true;
                }
                member = GetUserFromTable(svc, username);
                if (member == null)
                {
                    return false;
                }
                if (member.IsLockedOut)
                {
                    return false;
                }
                if (!member.IsApproved && failIfNotApproved)
                {
                    return false;
                }

                DateTime now = DateTime.UtcNow;
                string encodedPasswd = EncodePassword(password, member.PasswordFormat, member.PasswordSalt);

                bool isPasswordCorrect = member.Password.Equals(encodedPasswd);

                if (isPasswordCorrect && member.FailedPasswordAttemptCount == 0 && member.FailedPasswordAnswerAttemptCount == 0)
                {
                    if (createContextAndWriteState)
                    {
                        svc.UpdateObject(member);
                        svc.SaveChanges();
                    }
                    return true;
                }

                if (!isPasswordCorrect)
                {
                    if (now > member.FailedPasswordAttemptWindowStartUtc.Add(TimeSpan.FromMinutes(PasswordAttemptWindow)))
                    {
                        member.FailedPasswordAttemptWindowStartUtc = now;
                        member.FailedPasswordAttemptCount = 1;
                    }
                    else
                    {
                        member.FailedPasswordAttemptWindowStartUtc = now;
                        member.FailedPasswordAttemptCount++;
                    }
                    if (member.FailedPasswordAttemptCount >= MaxInvalidPasswordAttempts)
                    {
                        member.IsLockedOut = true;
                        member.LastLockoutDateUtc = now;
                    }
                }
                else
                {
                    if (member.FailedPasswordAttemptCount > 0 || member.FailedPasswordAnswerAttemptCount > 0)
                    {
                        member.FailedPasswordAnswerAttemptWindowStartUtc = ProviderConfiguration.MinSupportedDateTime;
                        member.FailedPasswordAnswerAttemptCount = 0;
                        member.FailedPasswordAttemptWindowStartUtc = ProviderConfiguration.MinSupportedDateTime;
                        member.FailedPasswordAttemptCount = 0;
                        member.LastLockoutDateUtc = ProviderConfiguration.MinSupportedDateTime;
                    }
                }
                if (isPasswordCorrect && updateLastLoginActivityDate)
                {
                    member.LastActivityDateUtc = now;
                    member.LastLoginDateUtc = now;
                }

                if (createContextAndWriteState)
                {
                    svc.UpdateObject(member);
                    svc.SaveChanges();
                }

                return isPasswordCorrect;
            }
            catch (Exception e)
            {
                if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int) HttpStatusCode.PreconditionFailed)
                {
                    // this element was changed between read and writes
                    Log.Write(EventKind.Warning, "A membership element has been changed between read and writes.");
                    member = null;
                    return false;
                }
                else
                {
                    throw new ProviderException("Error accessing the data store!", e);
                }
            }
        }
 private bool CheckPassword(string username, string password, bool updateLastLoginActivityDate, bool failIfNotApproved, out MembershipRow member)
 {
     return CheckPassword(null, username, password, updateLastLoginActivityDate, failIfNotApproved, out member);
 }