public void SubtractInPlace()
        {
            DecayingDouble d = new DecayingDouble(4, FirstDayOfCentury);

            d.SubtractInPlace(OneDay, 1, OneDayLater);
            Assert.InRange(d.ValueAtTimeOfLastUpdate, .99999, 1.000001);
        }
Ejemplo n.º 2
0
        //public DecayingDouble AllFailures(TimeSpan halfLife) => AccountFailures.Add(halfLife, PasswordFailures);

        //public DecayingDouble AccountFailuresSubsetWithInfrequentPassword(TimeSpan halfLife) => AccountFailures.Subtract(halfLife, AccountFailuresSubsetWithFrequentPassword);
        //public DecayingDouble PasswordFailuresSubsetWithInfrequentPassword(TimeSpan halfLife) => PasswordFailures.Subtract(halfLife, PasswordFailuresSubsetWithFrequentPassword);
        //public DecayingDouble PasswordFailuresSubsetWithoutTypo(TimeSpan halfLife) => PasswordFailures.Subtract(halfLife, PasswordFailuresSubsetWithTypo);
        //public DecayingDouble PasswordFailuresSubsetWithoutEitherFrequentPasswordOrTypo(TimeSpan halfLife) => PasswordFailures.Subtract(halfLife, PasswordFailuresSubsetWithTypoAndFrequentPassword);

        /// <summary>
        /// This analysis will examine the client IP's previous failed attempts to login to this account
        /// to determine if any failed attempts were due to typos.
        /// </summary>
        /// <param name="account">The account that the client is currently trying to login to.</param>
        /// <param name="whenUtc"></param>
        /// <param name="correctPassword">The correct password for this account.  (We can only know it because
        /// the client must have provided the correct one this loginAttempt.)</param>
        /// <returns></returns>
        public void AdjustBlockingScoreForPastTyposTreatedAsFullFailures(
            Simulator simulator,
            SimulatedUserAccount account,
            DateTime whenUtc,
            string correctPassword)
        {
            SimLoginAttemptSummaryForTypoAnalysis[] recentPotentialTypos =
                RecentPotentialTypos.MostRecentFirst.ToArray();
            foreach (SimLoginAttemptSummaryForTypoAnalysis potentialTypo in recentPotentialTypos)
            {
                if (account == null || potentialTypo.UsernameOrAccountId != account.UsernameOrAccountId)
                {
                    continue;
                }

                // Use an edit distance calculation to determine if it was a likely typo
                bool likelyTypo =
                    EditDistance.Calculate(potentialTypo.Password, correctPassword) <=
                    simulator._experimentalConfiguration.BlockingOptions.MaxEditDistanceConsideredATypo;

                TimeSpan       halfLife = simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife;
                DecayingDouble value    = new DecayingDouble(1d, potentialTypo.WhenUtc);
                // Add this to the list of changed attempts
                if (potentialTypo.WasPasswordFrequent)
                {
                    PasswordFailuresNoTypoFrequentPassword.SubtractInPlace(halfLife, value);
                    PasswordFailuresTypoFrequentPassword.AddInPlace(halfLife, value);
                }
                RecentPotentialTypos.Remove(potentialTypo);
            }
        }
Ejemplo n.º 3
0
        public void SubtractInPlace()
        {
            DecayingDouble d = new DecayingDouble(4, FirstDayOfCentury);

            // One day later the double should be 2, so subtracting 1 should yield 1
            d.SubtractInPlace(OneDay, 1, OneDayLater);
            Assert.InRange(d.ValueAtTimeOfLastUpdate, .99999, 1.000001);
        }
Ejemplo n.º 4
0
 public IpHistory(
     IPAddress address,
     BlockingAlgorithmOptions options)
 {
     Address              = address;
     CurrentBlockScore    = new DecayingDouble();
     RecentPotentialTypos =
         new SmallCapacityConstrainedSet <LoginAttemptSummaryForTypoAnalysis>(options.NumberOfFailuresToTrackForGoingBackInTimeToIdentifyTypos);
 }
        public void AddInPlace()
        {
            DecayingDouble d = new DecayingDouble(4, FirstDayOfCentury);

            d.AddInPlace(OneDay, 3, TwoDaysLater);
            Assert.InRange(d.ValueAtTimeOfLastUpdate, 3.99999, 4.000001);
            double shouldBeVeryCloseTo1 = d.GetValue(OneDay, FourDaysLater);

            Assert.InRange(shouldBeVeryCloseTo1, .99999, 1.000001);
        }
        public void UpdateSimulatorState(Simulator simulator, SimIpHistory ipHistory)
        {
            IsRepeatFailure = !IsPasswordValid && (
                (SimAccount == null)
                    ? simulator._recentIncorrectPasswords.AddMember(UserNameOrAccountId + "\n" + Password)
                    : simulator._userAccountController.AddIncorrectPhaseTwoHash(SimAccount, Password, TimeOfAttemptUtc)
                );

            int passwordsHeightOnBinomialLadder = (IsPasswordValid || IsRepeatFailure)
                ? simulator._binomialLadderFilter.GetHeight(Password)
                : simulator._binomialLadderFilter.Step(Password);

            IsFrequentlyGuessedPassword = passwordsHeightOnBinomialLadder >=
                                          simulator._experimentalConfiguration.BlockingOptions.BinomialLadderFrequencyThreshdold_T;

            DeviceCookieHadPriorSuccessfulLoginForThisAccount = SimAccount != null &&
                                                                simulator._userAccountController.HasClientWithThisHashedCookieSuccessfullyLoggedInBefore(SimAccount, CookieProvidedByBrowser);

            if (SimAccount != null && IsPasswordValid)
            {
                ipHistory.AdjustBlockingScoreForPastTyposTreatedAsFullFailures(simulator, SimAccount, TimeOfAttemptUtc,
                                                                               Password);
                simulator._userAccountController.RecordHashOfDeviceCookieUsedDuringSuccessfulLoginBackground(
                    SimAccount, CookieProvidedByBrowser, TimeOfAttemptUtc);
                SimAccount.ConsecutiveIncorrectAttempts.SetValue(0, this.TimeOfAttemptUtc);
            }
            else if (SimAccount != null && !IsRepeatFailure)
            {
                SimAccount.ConsecutiveIncorrectAttempts.AddInPlace(
                    simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, 1d,
                    this.TimeOfAttemptUtc);
                if (SimAccount.ConsecutiveIncorrectAttempts.GetValue(
                        simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife)
                    >
                    SimAccount.MaxConsecutiveIncorrectAttempts.GetValue(
                        simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife))
                {
                    SimAccount.MaxConsecutiveIncorrectAttempts.SetValue(SimAccount.ConsecutiveIncorrectAttempts);
                }
            }

            if (!IsPasswordValid && !IsRepeatFailure && SimAccount != null)
            {
                ipHistory.RecentPotentialTypos.Add(new SimLoginAttemptSummaryForTypoAnalysis()
                {
                    WhenUtc             = TimeOfAttemptUtc,
                    Password            = Password,
                    UsernameOrAccountId = UserNameOrAccountId,
                    WasPasswordFrequent = IsFrequentlyGuessedPassword
                });
            }


            DecayingDouble decayingOneFromThisInstant = new DecayingDouble(1, TimeOfAttemptUtc);
            TimeSpan       halfLife = simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife;

            if (IsPasswordValid)
            {
                ipHistory.SuccessfulLogins.AddInPlace(halfLife, decayingOneFromThisInstant);
            }
            else if (SimAccount == null)
            {
                if (IsRepeatFailure)
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.RepeatAccountFailuresFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.RepeatAccountFailuresInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
                else
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.AccountFailuresFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.AccountFailuresInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
            }
            else
            {
                if (IsRepeatFailure)
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.RepeatPasswordFailuresNoTypoFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.RepeatPasswordFailuresNoTypoInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
                else
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.PasswordFailuresNoTypoFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.PasswordFailuresNoTypoInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
            }
        }
Ejemplo n.º 7
0
        public void UpdateSimulatorState(Simulator simulator, SimIpHistory ipHistory)
        {
            IsRepeatFailure = (SimAccount == null)
                ? simulator._recentIncorrectPasswords.AddMember(UserNameOrAccountId + "\n" + Password)
                : simulator._userAccountController.AddIncorrectPhaseTwoHashAsync(SimAccount, Password, TimeOfAttemptUtc).Result;

            int passwordsHeightOnBinomialLadder = IsPasswordValid
                ? simulator._binomialLadderFilter.GetHeight(Password)
                : simulator._binomialLadderFilter.Step(Password);

            IsFrequentlyGuessedPassword = passwordsHeightOnBinomialLadder + 1 >=
                                          simulator._binomialLadderFilter.MaxHeight;


            if (SimAccount != null)
            {
                DeviceCookieHadPriorSuccessfulLoginForThisAccount =
                    simulator._userAccountController.HasClientWithThisHashedCookieSuccessfullyLoggedInBeforeAsync(
                        SimAccount, CookieProvidedByBrowser).Result;
            }

            if (IsPasswordValid)
            {
                // Determine if any of the outcomes for login attempts from the client IP for this request were the result of typos,
                // as this might impact our decision about whether or not to block this client IP in response to its past behaviors.
                ipHistory.AdjustBlockingScoreForPastTyposTreatedAsFullFailures(simulator, SimAccount, TimeOfAttemptUtc,
                                                                               Password);
                if (SimAccount != null)
                {
                    simulator._userAccountController.RecordHashOfDeviceCookieUsedDuringSuccessfulLoginBackground(
                        SimAccount, CookieProvidedByBrowser, TimeOfAttemptUtc);
                }
            }

            if (!IsPasswordValid && !IsRepeatFailure && SimAccount != null)
            {
                ipHistory.RecentPotentialTypos.Add(new SimLoginAttemptSummaryForTypoAnalysis()
                {
                    WhenUtc             = TimeOfAttemptUtc,
                    Password            = Password,
                    UsernameOrAccountId = UserNameOrAccountId,
                    WasPasswordFrequent = IsFrequentlyGuessedPassword
                });
            }

            DecayingDouble decayingOneFromThisInstant = new DecayingDouble(1, TimeOfAttemptUtc);
            TimeSpan       halfLife = simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife;

            if (IsPasswordValid)
            {
                ipHistory.SuccessfulLogins.AddInPlace(halfLife, decayingOneFromThisInstant);
            }
            else if (SimAccount == null)
            {
                if (IsRepeatFailure)
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.RepeatAccountFailuresFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.RepeatAccountFailuresInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
                else
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.AccountFailuresFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.AccountFailuresInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
            }
            else
            {
                if (IsRepeatFailure)
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.RepeatPasswordFailuresNoTypoFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.RepeatPasswordFailuresNoTypoInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
                else
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.PasswordFailuresNoTypoFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.PasswordFailuresNoTypoInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
            }
        }
Ejemplo n.º 8
0
        public override async Task <double> TryGetCreditAsync(
            DbUserAccount userAccount,
            double amountRequested,
            DateTime?timeOfRequestUtc           = null,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (Double.IsNaN(amountRequested) || amountRequested <= 0)
            {
                // You can't request a negative amount and requesting nothing is free
                return(0);
            }

            DateTime timeOfRequestOrNowUtc = timeOfRequestUtc ?? DateTime.Now;

            double creditRetrieved = 0;

            using (var context = new DbUserAccountContext(DbOptions))
            {
                using (var dbContextTransaction = await context.Database.BeginTransactionAsync(cancellationToken))
                {
                    bool rolledBackDueToConcurrencyException = false;
                    do
                    {
                        try
                        {
                            DbUserAccountCreditBalance balance = await
                                                                 context.DbUserAccountCreditBalances.Where(b => b.DbUserAccountId == userAccount.DbUserAccountId)
                                                                 .FirstOrDefaultAsync(cancellationToken: cancellationToken);

                            if (balance == null)
                            {
                                creditRetrieved = Math.Min(amountRequested, userAccount.CreditLimit);
                                double amountRemaining = userAccount.CreditLimit - creditRetrieved;
                                context.DbUserAccountCreditBalances.Add(
                                    new DbUserAccountCreditBalance()
                                {
                                    DbUserAccountId = userAccount.DbUserAccountId,
                                    ConsumedCreditsLastUpdatedUtc = timeOfRequestOrNowUtc,
                                    ConsumedCreditsLastValue      = amountRemaining
                                });
                            }
                            else
                            {
                                double amountAvailable = Math.Max(0, userAccount.CreditLimit -
                                                                  DecayingDouble.Decay(balance.ConsumedCreditsLastValue, userAccount.CreditHalfLife,
                                                                                       balance.ConsumedCreditsLastUpdatedUtc, timeOfRequestOrNowUtc));
                                if (amountAvailable > 0)
                                {
                                    creditRetrieved = Math.Min(amountRequested, amountAvailable);
                                }
                                double amountRemaining = amountAvailable - creditRetrieved;
                                balance.ConsumedCreditsLastValue      = amountRemaining;
                                balance.ConsumedCreditsLastUpdatedUtc = timeOfRequestOrNowUtc;
                            }

                            await context.SaveChangesAsync(cancellationToken);

                            dbContextTransaction.Commit();
                        }
                        catch (DbUpdateConcurrencyException)
                        {
                            dbContextTransaction.Rollback();
                            rolledBackDueToConcurrencyException = true;
                        }
                    } while (rolledBackDueToConcurrencyException);
                }
            }

            return(creditRetrieved);
        }
Ejemplo n.º 9
0
        public void DecayOverTwoHalfLives()
        {
            double shouldBeVeryCloseTo1 = DecayingDouble.Decay(4, OneDay, FirstDayOfCentury, TwoDaysLater);

            Assert.InRange(shouldBeVeryCloseTo1, .99999, 1.000001);
        }
Ejemplo n.º 10
0
        public void UpdateSimulatorState(Simulator simulator, SimIpHistory ipHistory)
        {
            IsRepeatFailure = !IsPasswordValid && (
                (SimAccount == null)
                    ? simulator._recentIncorrectPasswords.AddMember(UserNameOrAccountId + "\n" + Password)
                    : simulator._userAccountController.AddIncorrectPhaseTwoHash(SimAccount, Password, TimeOfAttemptUtc)
                );

            int passwordsHeightOnBinomialLadder = (IsPasswordValid || IsRepeatFailure)
                ? simulator._binomialLadderFilter.GetHeight(Password)
                : simulator._binomialLadderFilter.Step(Password);

            IsFrequentlyGuessedPassword = passwordsHeightOnBinomialLadder >=
                                          simulator._experimentalConfiguration.BlockingOptions.BinomialLadderFrequencyThreshdold_T;

            DeviceCookieHadPriorSuccessfulLoginForThisAccount = SimAccount != null &&
                                                                simulator._userAccountController.HasClientWithThisHashedCookieSuccessfullyLoggedInBefore(SimAccount, CookieProvidedByBrowser);

            if (SimAccount != null && IsPasswordValid)
            {
                // Determine if any of the outcomes for login attempts from the client IP for this request were the result of typos,
                // as this might impact our decision about whether or not to block this client IP in response to its past behaviors.
                ipHistory.AdjustBlockingScoreForPastTyposTreatedAsFullFailures(simulator, SimAccount, TimeOfAttemptUtc,
                                                                               Password);
                simulator._userAccountController.RecordHashOfDeviceCookieUsedDuringSuccessfulLoginBackground(
                    SimAccount, CookieProvidedByBrowser, TimeOfAttemptUtc);
                // Clear the count of consecutive failures
                SimAccount.ConsecutiveIncorrectAttempts.SetValue(0, this.TimeOfAttemptUtc);
            }
            else if (SimAccount != null && !IsRepeatFailure)
            {
                // Add the the account's consecutive failure count
                SimAccount.ConsecutiveIncorrectAttempts.AddInPlace(
                    simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife, 1d,
                    this.TimeOfAttemptUtc);
                // Increase the max consecutive faiulre count if the current consecutive failure count exceeds it
                if (SimAccount.ConsecutiveIncorrectAttempts.GetValue(
                        simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife)
                    >
                    SimAccount.MaxConsecutiveIncorrectAttempts.GetValue(
                        simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife))
                {
                    SimAccount.MaxConsecutiveIncorrectAttempts.SetValue(SimAccount.ConsecutiveIncorrectAttempts);
                }
            }

            if (!IsPasswordValid && !IsRepeatFailure && SimAccount != null)
            {
                // This attempt is a non-repeat failure and could be a typo.  Store it in the ste of potential typos.
                ipHistory.RecentPotentialTypos.Add(new SimLoginAttemptSummaryForTypoAnalysis()
                {
                    WhenUtc             = TimeOfAttemptUtc,
                    Password            = Password,
                    UsernameOrAccountId = UserNameOrAccountId,
                    WasPasswordFrequent = IsFrequentlyGuessedPassword
                });
            }


            DecayingDouble decayingOneFromThisInstant = new DecayingDouble(1, TimeOfAttemptUtc);
            TimeSpan       halfLife = simulator._experimentalConfiguration.BlockingOptions.BlockScoreHalfLife;

            if (IsPasswordValid)
            {
                ipHistory.SuccessfulLogins.AddInPlace(halfLife, decayingOneFromThisInstant);
            }
            else if (SimAccount == null)
            {
                if (IsRepeatFailure)
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.RepeatAccountFailuresFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.RepeatAccountFailuresInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
                else
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.AccountFailuresFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.AccountFailuresInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
            }
            else
            {
                if (IsRepeatFailure)
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.RepeatPasswordFailuresNoTypoFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.RepeatPasswordFailuresNoTypoInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
                else
                {
                    if (IsFrequentlyGuessedPassword)
                    {
                        ipHistory.PasswordFailuresNoTypoFrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                    else
                    {
                        ipHistory.PasswordFailuresNoTypoInfrequentPassword.AddInPlace(halfLife, decayingOneFromThisInstant);
                    }
                }
            }
        }