From: Date: February 25 2008 10:15pm Subject: Connector/NET commit: r1193 - in branches/5.2: . MySql.Web/Providers/Properties MySql.Web/Providers/Source MySql.Web/Tests List-Archive: http://lists.mysql.com/commits/42959 X-Bug: 34792 Message-Id: <200802252115.m1PLFtSt002163@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: branches/5.2/CHANGES branches/5.2/MySql.Web/Providers/Properties/Resources.resx branches/5.2/MySql.Web/Providers/Source/MembershipProvider.cs branches/5.2/MySql.Web/Tests/UserManagement.cs Log: - Fixed password validation logic for creating users and changing passwords. It actually works now. (bug #34792) Before this patch we actually didn't have any logic to check the length, non-alpha-ness, and regex complexity of the new passwords. We do now. Modified: branches/5.2/CHANGES =================================================================== --- branches/5.2/CHANGES 2008-02-22 20:54:05 UTC (rev 1192) +++ branches/5.2/CHANGES 2008-02-25 21:15:55 UTC (rev 1193) @@ -8,6 +8,8 @@ their application id if the connection string has not been set. (bug #34451) - Fixed installer that did not install the DDEX provider binary if the Visual Studio 2005 component was not selected. (bug #34674) +- Fixed password validation logic for creating users and changing passwords. + It actually works now. (bug #34792) Version 5.2 - 2/11/2008 . Added ClearPool and ClearAllPools features Modified: branches/5.2/MySql.Web/Providers/Properties/Resources.resx =================================================================== --- branches/5.2/MySql.Web/Providers/Properties/Resources.resx 2008-02-22 20:54:05 UTC (rev 1192) +++ branches/5.2/MySql.Web/Providers/Properties/Resources.resx 2008-02-25 21:15:55 UTC (rev 1193) @@ -211,4 +211,16 @@ Unable to create user. + + Change password operation was canceled. + + + Non alpha numeric characters in '{0}' needs to be greater than or equal to '{1}'. + + + The length of parameter '{0}' needs to be greater or equal to '{1}'. + + + The validate password operation was canceled. + \ No newline at end of file Modified: branches/5.2/MySql.Web/Providers/Source/MembershipProvider.cs =================================================================== --- branches/5.2/MySql.Web/Providers/Source/MembershipProvider.cs 2008-02-22 20:54:05 UTC (rev 1192) +++ branches/5.2/MySql.Web/Providers/Source/MembershipProvider.cs 2008-02-25 21:15:55 UTC (rev 1193) @@ -38,6 +38,7 @@ using MySql.Web.Profile; using MySql.Web.Common; using System.Transactions; +using System.Text.RegularExpressions; namespace MySql.Web.Security { @@ -379,26 +380,30 @@ /// Changes the password. /// /// The username. - /// The old password. - /// The new password. + /// The old password. + /// The new password. /// true if the password was updated successfully, false if the supplied old password /// is invalid, the user is locked out, or the user does not exist in the database. - public override bool ChangePassword(string username, string oldPwd, string newPwd) + public override bool ChangePassword(string username, string oldPassword, string newPassword) { // this will return false if the username doesn't exist - if (!(ValidateUser(username, oldPwd))) + if (!(ValidateUser(username, oldPassword))) return false; - ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPwd, true); + ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true); OnValidatingPassword(args); if (args.Cancel) { if (!(args.FailureInformation == null)) throw args.FailureInformation; else - throw new ProviderException(Resources.NewPasswordValidationFailed); + throw new ProviderException(Resources.ChangePasswordCanceled); } + // validate the password according to current guidelines + if (!ValidatePassword(newPassword, "newPassword", true)) + return false; + try { using (MySqlConnection connection = new MySqlConnection(connectionString)) @@ -416,8 +421,8 @@ @"UPDATE my_aspnet_Membership SET Password = @pass, LastPasswordChangedDate = @lastPasswordChangedDate WHERE userId=@userId", connection); - cmd.Parameters.AddWithValue("@pass", - EncodePassword(newPwd, passwordKey, passwordFormat)); + cmd.Parameters.AddWithValue("@pass", + EncodePassword(newPassword, passwordKey, passwordFormat)); cmd.Parameters.AddWithValue("@lastPasswordChangedDate", DateTime.Now); cmd.Parameters.AddWithValue("@userId", userId); return cmd.ExecuteNonQuery() > 0; @@ -511,6 +516,13 @@ return null; } + // now try to validate the password + if (!ValidatePassword(password, "password", false)) + { + status = MembershipCreateStatus.InvalidPassword; + return null; + } + // now check to see if we already have a member by this name MembershipUser u = GetUser(username, false); if (u != null) @@ -1415,7 +1427,41 @@ } } + private bool ValidatePassword(string password, string argumentName, bool throwExceptions) + { + string exceptionString = null; + object correctValue = MinRequiredPasswordLength; + if (password.Length < MinRequiredPasswordLength) + exceptionString = Resources.PasswordNotLongEnough; + else + { + int count = 0; + foreach (char c in password) + if (!char.IsLetterOrDigit(c)) + count++; + if (count < MinRequiredNonAlphanumericCharacters) + exceptionString = Resources.NotEnoughNonAlphaNumericInPwd; + correctValue = MinRequiredNonAlphanumericCharacters; + } + + if (exceptionString != null) + { + if (throwExceptions) + throw new ArgumentException( + string.Format(exceptionString, argumentName, correctValue), + argumentName); + else + return false; + } + + if (PasswordStrengthRegularExpression.Length > 0) + if (!Regex.IsMatch(password, PasswordStrengthRegularExpression)) + return false; + + return true; + } + #endregion } } Modified: branches/5.2/MySql.Web/Tests/UserManagement.cs =================================================================== --- branches/5.2/MySql.Web/Tests/UserManagement.cs 2008-02-22 20:54:05 UTC (rev 1192) +++ branches/5.2/MySql.Web/Tests/UserManagement.cs 2008-02-25 21:15:55 UTC (rev 1193) @@ -50,12 +50,13 @@ NameValueCollection config = new NameValueCollection(); config.Add("connectionStringName", "LocalMySqlServer"); config.Add("applicationName", "/"); + config.Add("passwordStrengthRegularExpression", "bar.*"); config.Add("passwordFormat", format.ToString()); provider.Initialize(null, config); // create the user MembershipCreateStatus status; - provider.CreateUser("foo", "bar", "foo@stripped", null, null, true, null, out status); + provider.CreateUser("foo", "barbar!", "foo@stripped", null, null, true, null, out status); Assert.AreEqual(MembershipCreateStatus.Success, status); // verify that the password format is hashed. @@ -65,7 +66,7 @@ Assert.AreEqual(format, rowFormat); // then attempt to verify the user - Assert.IsTrue(provider.ValidateUser("foo", "bar")); + Assert.IsTrue(provider.ValidateUser("foo", "barbar!")); } [Test] @@ -92,15 +93,87 @@ CreateUserWithFormat(MembershipPasswordFormat.Clear); } + /// + /// Bug #34792 New User/Changing Password Validation Not working. + /// [Test] public void ChangePassword() { CreateUserWithHashedPassword(); - provider.ChangePassword("foo", "bar", "bar2"); - provider.ValidateUser("foo", "bar2"); + try + { + provider.ChangePassword("foo", "barbar!", "bar2"); + Assert.Fail(); + } + catch (ArgumentException ae1) + { + Assert.AreEqual("newPassword", ae1.ParamName); + Assert.IsTrue(ae1.Message.Contains("length of parameter")); + } + + try + { + provider.ChangePassword("foo", "barbar!", "barbar2"); + Assert.Fail(); + } + catch (ArgumentException ae1) + { + Assert.AreEqual("newPassword", ae1.ParamName); + Assert.IsTrue(ae1.Message.Contains("alpha numeric")); + } + + // now test regex strength testing + bool result = provider.ChangePassword("foo", "barbar!", "zzzxxx!"); + Assert.IsFalse(result); + + // now do one that should work + result = provider.ChangePassword("foo", "barbar!", "barfoo!"); + Assert.IsTrue(result); + + provider.ValidateUser("foo", "barfoo!"); } + /// + /// Bug #34792 New User/Changing Password Validation Not working. + /// [Test] + public void CreateUserWithErrors() + { + provider = new MySQLMembershipProvider(); + NameValueCollection config = new NameValueCollection(); + config.Add("connectionStringName", "LocalMySqlServer"); + config.Add("applicationName", "/"); + config.Add("passwordStrengthRegularExpression", "bar.*"); + config.Add("passwordFormat", "Hashed"); + provider.Initialize(null, config); + + // first try to create a user with a password not long enough + MembershipCreateStatus status; + MembershipUser user = provider.CreateUser("foo", "xyz", + "foo@stripped", null, null, true, null, out status); + Assert.IsNull(user); + Assert.AreEqual(MembershipCreateStatus.InvalidPassword, status); + + // now with not enough non-alphas + user = provider.CreateUser("foo", "xyz1234", + "foo@stripped", null, null, true, null, out status); + Assert.IsNull(user); + Assert.AreEqual(MembershipCreateStatus.InvalidPassword, status); + + // now one that doesn't pass the regex test + user = provider.CreateUser("foo", "xyzxyz!", + "foo@stripped", null, null, true, null, out status); + Assert.IsNull(user); + Assert.AreEqual(MembershipCreateStatus.InvalidPassword, status); + + // now one that works + user = provider.CreateUser("foo", "barbar!", + "foo@stripped", null, null, true, null, out status); + Assert.IsNotNull(user); + Assert.AreEqual(MembershipCreateStatus.Success, status); + } + + [Test] public void DeleteUser() { CreateUserWithHashedPassword();