private void UpdateFailureCount(string username, string failureType)
{
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand("SELECT FailedPasswordAttemptCount, " +
" FailedPasswordAttemptWindowStart, " +
" FailedPasswordAnswerAttemptCount, " +
" FailedPasswordAnswerAttemptWindowStart " +
" FROM Users " +
" WHERE Username = @Username AND ApplicationName = @ApplicationName", conn);
cmd.Parameters.AddWithValue("@Username", username);
cmd.Parameters.AddWithValue("@ApplicationName", pApplicationName);
SqlDataReader reader = null;
DateTime windowStart = new DateTime();
int failureCount = 0;
try
{
conn.Open();
reader = cmd.ExecuteReader(CommandBehavior.SingleRow);
if (reader.HasRows)
{
reader.Read();
if (failureType == "password")
{
failureCount = reader.GetInt32(0);
windowStart = reader.GetDateTime(1);
}
if (failureType == "passwordAnswer")
{
failureCount = reader.GetInt32(2);
windowStart = reader.GetDateTime(3);
}
}
reader.Close();
DateTime windowEnd = windowStart.AddMinutes(PasswordAttemptWindow);
if (failureCount == 0 || DateTime.Now > windowEnd)
{
// First password failure or outside of PasswordAttemptWindow.
// Start a new password failure count from 1 and a new window starting now.
if (failureType == "password")
cmd.CommandText = "UPDATE Users " +
" SET FailedPasswordAttemptCount = @Count, " +
" FailedPasswordAttemptWindowStart = @WindowStart " +
" WHERE Username = @Username AND ApplicationName = @ApplicationName";
if (failureType == "passwordAnswer")
cmd.CommandText = "UPDATE Users " +
" SET FailedPasswordAnswerAttemptCount = @Count, " +
" FailedPasswordAnswerAttemptWindowStart = @WindowStart " +
" WHERE Username = @Username AND ApplicationName = @ApplicationName";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@Count", 1);
cmd.Parameters.AddWithValue("@WindowStart", DateTime.Now);
cmd.Parameters.AddWithValue("@Username", username);
cmd.Parameters.AddWithValue("@ApplicationName", pApplicationName);
if (cmd.ExecuteNonQuery() < 0)
throw new ProviderException("Unable to update failure count and window start.");
}
else
{
if (failureCount++ >= MaxInvalidPasswordAttempts)
{
// Password attempts have exceeded the failure threshold. Lock out
// the user.
cmd.CommandText = "UPDATE Users " +
" SET IsLockedOut = @IsLockedOut, LastLockedOutDate = @LastLockedOutDate " +
" WHERE Username = @Username AND ApplicationName = @ApplicationName";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@IsLockedOut", true);
cmd.Parameters.AddWithValue("@LastLockedOutDate", DateTime.Now);
cmd.Parameters.AddWithValue("@Username", username);
cmd.Parameters.AddWithValue("@ApplicationName", pApplicationName);
if (cmd.ExecuteNonQuery() < 0)
throw new ProviderException("Unable to lock out user.");
}
else
{
// Password attempts have not exceeded the failure threshold. Update
// the failure counts. Leave the window the same.
if (failureType == "password")
cmd.CommandText = "UPDATE Users " +
" SET FailedPasswordAttemptCount = @Count" +
" WHERE Username = @Username AND ApplicationName = @ApplicationName";
if (failureType == "passwordAnswer")
cmd.CommandText = "UPDATE Users " +
" SET FailedPasswordAnswerAttemptCount = @Count" +
" WHERE Username = @Username AND ApplicationName = @ApplicationName";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("@Count", failureCount);
cmd.Parameters.AddWithValue("@Username", username);
cmd.Parameters.AddWithValue("@ApplicationName", pApplicationName);
if (cmd.ExecuteNonQuery() < 0)
throw new ProviderException("Unable to update failure count.");
}
}
}
catch (SqlException e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "UpdateFailureCount");
throw new ProviderException(exceptionMessage);
}
else
{
throw e;
}
}
finally
{
if (reader != null) { reader.Close(); }
conn.Close();
}
}