So I am writing a custom membership provider for Sitecore and my strategy was to download the source code to the SQLMembershipProvider (which sitecore already uses) and just add my custom logic to it.
One of the core functionalities we wanted was the ability to store a password history and I was working in the ChangePassword function to start.
The first few times I tried my code I had no issue, but now even after computer restarts, attempting to disconnect all users from the database, and refactoring my code so that it only uses a single SQLCommand and one connection I cannot get rid of this error.
I'm including the relevant code from the change password function (I demarked the custom code I added with //my code - start/end). Any ideas?
try
{
SqlConnectionHolder recentpw_holder = null;
SqlDataReader reader = null;
SqlCommand tempcmd = null;
try
{
recentpw_holder = SqlConnectionHelper.GetConnection(_sqlConnectionString, true);
CheckSchemaVersion(recentpw_holder.Connection);
//my code - Start
tempcmd = new SqlCommand("SELECT * FROM dbo.PasswordHistory WHERE username='" + username + "' ORDER BY date_created", recentpw_holder.Connection);
using (reader = tempcmd.ExecuteReader())
{
var passwordlist = new List<string>();
while (reader.Read())
{
//get the list of passwords
for (int i = 0; i < reader.FieldCount; i++)
{
passwordlist.Add(reader.GetValue(i).ToString());
}
}
//if there are more than 10 passwords stored in the database remove the oldest one
if (passwordlist.Count > 10)
{
tempcmd.CommandText = "DELETE * FROM dbo.PasswordHistory" +
"WHERE username='" + username + "'" +
"AND password='" + passwordlist.First() + "'";
tempcmd.ExecuteNonQuery();
passwordlist.RemoveAt(0);
}
//check and see if that password has already been used, if so throw an error
foreach (var p in passwordlist)
{
if (p == pass)
{
throw new ArgumentException("Unable to create password. Password does not meet the history requirements of the domain.");
}
}
}
//my code - end
tempcmd.CommandText = "dbo.aspnet_Membership_SetPassword";
tempcmd.CommandTimeout = CommandTimeout;
tempcmd.CommandType = CommandType.StoredProcedure;
tempcmd.Parameters.Add(CreateInputParam("@ApplicationName", SqlDbType.NVarChar, ApplicationName));
tempcmd.Parameters.Add(CreateInputParam("@UserName", SqlDbType.NVarChar, username));
tempcmd.Parameters.Add(CreateInputParam("@NewPassword", SqlDbType.NVarChar, pass));
tempcmd.Parameters.Add(CreateInputParam("@PasswordSalt", SqlDbType.NVarChar, salt));
tempcmd.Parameters.Add(CreateInputParam("@PasswordFormat", SqlDbType.Int, passwordFormat));
tempcmd.Parameters.Add(CreateInputParam("@CurrentTimeUtc", SqlDbType.DateTime, DateTime.UtcNow));
SqlParameter para = new SqlParameter("@ReturnValue", SqlDbType.Int);
para.Direction = ParameterDirection.ReturnValue;
tempcmd.Parameters.Add(para);
tempcmd.ExecuteNonQuery();
//my code pt 2 - start
tempcmd.Parameters.Clear();
tempcmd.CommandType = CommandType.Text;
tempcmd.CommandText = "INSERT INTO dbo.PasswordHistory "
+ "(username, password, date_created) "
+ "VALUES ('" +
username + "', '" +
pass + "', '" +
DateTime.UtcNow + "')";
tempcmd.ExecuteNonQuery();
//my code pt 2 - end
status = ( ( para.Value != null ) ? ( ( int )para.Value ) : -1 );
if ( status != 0 )
{
string errText = GetExceptionText( status );
if ( IsStatusDueToBadPassword( status ) )
{
throw new MembershipPasswordException( errText );
}
else
{
throw new ProviderException( errText );
}
}
return true;
}
finally
{
if (reader != null)
{
reader.Close();
reader = null;
}
if( recentpw_holder != null )
{
recentpw_holder.Close();
recentpw_holder = null;
}
}
} catch {
throw;
}