2 // System.Web.Security.SqlMembershipProvider
5 // Ben Maurer (bmaurer@users.sourceforge.net)
6 // Lluis Sanchez Gual (lluis@novell.com)
7 // Chris Toshok (toshok@ximian.com)
10 // Copyright (c) 2005,2006 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.Configuration;
36 using System.Configuration.Provider;
38 using System.Data.Common;
40 using System.Web.Configuration;
41 using System.Security.Cryptography;
43 namespace System.Web.Security {
44 public class SqlMembershipProvider : MembershipProvider {
46 const int SALT_BYTES = 16;
48 /* can this be done just by setting the datetime fields to 0? */
49 DateTime DefaultDateTime = new DateTime (1754,1,1).ToUniversalTime();
51 bool enablePasswordReset;
52 bool enablePasswordRetrieval;
53 int maxInvalidPasswordAttempts;
54 MembershipPasswordFormat passwordFormat;
55 bool requiresQuestionAndAnswer;
56 bool requiresUniqueEmail;
57 int minRequiredNonAlphanumericCharacters;
58 int minRequiredPasswordLength;
59 int passwordAttemptWindow;
60 string passwordStrengthRegularExpression;
61 TimeSpan userIsOnlineTimeWindow;
63 ConnectionStringSettings connectionString;
64 DbProviderFactory factory;
65 DbConnection connection;
67 string applicationName;
69 static object lockobj = new object();
71 void InitConnection ()
73 if (connection == null) {
75 if (connection != null)
78 factory = ProvidersHelper.GetDbProviderFactory (connectionString.ProviderName);
79 connection = factory.CreateConnection();
80 connection.ConnectionString = connectionString.ConnectionString;
87 void AddParameter (DbCommand command, string parameterName, string parameterValue)
89 DbParameter dbp = command.CreateParameter ();
90 dbp.ParameterName = parameterName;
91 dbp.Value = parameterValue;
92 dbp.Direction = ParameterDirection.Input;
93 command.Parameters.Add (dbp);
96 void CheckParam (string pName, string p, int length)
99 throw new ArgumentNullException (pName);
100 if (p.Length == 0 || p.Length > length || p.IndexOf (",") != -1)
101 throw new ArgumentException (String.Format ("invalid format for {0}", pName));
104 SymmetricAlgorithm GetAlg (out byte[] decryptionKey)
106 MachineKeySection section = (MachineKeySection)WebConfigurationManager.GetSection ("system.web/machineKey");
108 if (section.DecryptionKey.StartsWith ("AutoGenerate"))
109 throw new ProviderException ("You must explicitly specify a decryption key in the <machineKey> section when using encrypted passwords.");
111 string alg_type = section.Decryption;
112 if (alg_type == "Auto")
115 SymmetricAlgorithm alg = null;
116 if (alg_type == "AES")
117 alg = Rijndael.Create ();
118 else if (alg_type == "3DES")
119 alg = TripleDES.Create ();
121 throw new ProviderException (String.Format ("Unsupported decryption attribute '{0}' in <machineKey> configuration section", alg_type));
123 decryptionKey = section.DecryptionKey192Bits;
127 protected override byte[] DecryptPassword (byte[] encodedPassword)
129 byte[] decryptionKey;
131 using (SymmetricAlgorithm alg = GetAlg (out decryptionKey)) {
132 alg.Key = decryptionKey;
134 using (ICryptoTransform decryptor = alg.CreateDecryptor ()) {
136 byte[] buf = decryptor.TransformFinalBlock (encodedPassword, 0, encodedPassword.Length);
137 byte[] rv = new byte[buf.Length - SALT_BYTES];
139 Array.Copy (buf, 16, rv, 0, buf.Length - 16);
145 protected override byte[] EncryptPassword (byte[] password)
147 byte[] decryptionKey;
148 byte[] iv = new byte[SALT_BYTES];
150 Array.Copy (password, 0, iv, 0, SALT_BYTES);
151 Array.Clear (password, 0, SALT_BYTES);
153 using (SymmetricAlgorithm alg = GetAlg (out decryptionKey)) {
154 using (ICryptoTransform encryptor = alg.CreateEncryptor (decryptionKey, iv)) {
155 return encryptor.TransformFinalBlock (password, 0, password.Length);
160 public override bool ChangePassword (string username, string oldPwd, string newPwd)
162 if (username != null) username = username.Trim ();
163 if (oldPwd != null) oldPwd = oldPwd.Trim ();
164 if (newPwd != null) newPwd = newPwd.Trim ();
166 CheckParam ("username", username, 256);
167 CheckParam ("oldPwd", oldPwd, 128);
168 CheckParam ("newPwd", newPwd, 128);
170 MembershipUser user = GetUser (username, false);
171 if (user == null) throw new ProviderException ("could not find user in membership database");
172 if (user.IsLockedOut) throw new MembershipPasswordException ("user is currently locked out");
176 DbTransaction trans = connection.BeginTransaction ();
182 MembershipPasswordFormat passwordFormat;
185 bool valid = ValidateUsingPassword (trans, username, oldPwd, out passwordFormat, out db_salt);
188 EmitValidatingPassword (username, newPwd, false);
190 string db_password = EncodePassword (newPwd, passwordFormat, db_salt);
192 DateTime now = DateTime.Now.ToUniversalTime ();
196 SET Password = @Password,
197 FailedPasswordAttemptCount = 0,
198 FailedPasswordAttemptWindowStart = @DefaultDateTime,
199 LastPasswordChangedDate = @Now
200 FROM dbo.aspnet_Membership m, dbo.aspnet_Users u, dbo.aspnet_Applications a
201 WHERE m.ApplicationId = a.ApplicationId
202 AND u.ApplicationId = a.ApplicationId
203 AND m.UserId = u.UserId
204 AND u.LoweredUserName = LOWER(@UserName)
205 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
207 command = factory.CreateCommand ();
208 command.Transaction = trans;
209 command.CommandText = commandText;
210 command.Connection = connection;
211 command.CommandType = CommandType.Text;
212 AddParameter (command, "UserName", user.UserName);
213 AddParameter (command, "Now", now.ToString ());
214 AddParameter (command, "Password", db_password);
215 AddParameter (command, "ApplicationName", ApplicationName);
216 AddParameter (command, "DefaultDateTime", DefaultDateTime.ToString());
218 if (1 != (int)command.ExecuteNonQuery ())
219 throw new ProviderException ("failed to update Membership table");
225 catch (ProviderException) {
229 catch (Exception e) {
231 throw new ProviderException ("error changing password", e);
235 public override bool ChangePasswordQuestionAndAnswer (string username, string password, string newPwdQuestion, string newPwdAnswer)
237 if (username != null) username = username.Trim ();
238 if (newPwdQuestion != null) newPwdQuestion = newPwdQuestion.Trim ();
239 if (newPwdAnswer != null) newPwdAnswer = newPwdAnswer.Trim ();
241 CheckParam ("username", username, 256);
242 if (RequiresQuestionAndAnswer)
243 CheckParam ("newPwdQuestion", newPwdQuestion, 128);
244 if (RequiresQuestionAndAnswer)
245 CheckParam ("newPwdAnswer", newPwdAnswer, 128);
247 MembershipUser user = GetUser (username, false);
248 if (user == null) throw new ProviderException ("could not find user in membership database");
249 if (user.IsLockedOut) throw new MembershipPasswordException ("user is currently locked out");
253 DbTransaction trans = connection.BeginTransaction ();
259 MembershipPasswordFormat passwordFormat;
262 bool valid = ValidateUsingPassword (trans, username, password, out passwordFormat, out db_salt);
265 string db_passwordAnswer = EncodePassword (newPwdAnswer, passwordFormat, db_salt);
269 SET PasswordQuestion = @PasswordQuestion,
270 PasswordAnswer = @PasswordAnswer,
271 FailedPasswordAttemptCount = 0,
272 FailedPasswordAttemptWindowStart = @DefaultDateTime,
273 FailedPasswordAnswerAttemptCount = 0,
274 FailedPasswordAnswerAttemptWindowStart = @DefaultDateTime
275 FROM dbo.aspnet_Membership m, dbo.aspnet_Users u, dbo.aspnet_Applications a
276 WHERE m.ApplicationId = a.ApplicationId
277 AND u.ApplicationId = a.ApplicationId
278 AND m.UserId = u.UserId
279 AND u.LoweredUserName = LOWER(@UserName)
280 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
282 command = factory.CreateCommand ();
283 command.Transaction = trans;
284 command.CommandText = commandText;
285 command.Connection = connection;
286 command.CommandType = CommandType.Text;
287 AddParameter (command, "UserName", user.UserName);
288 AddParameter (command, "PasswordQuestion", newPwdQuestion);
289 AddParameter (command, "PasswordAnswer", db_passwordAnswer);
290 AddParameter (command, "ApplicationName", ApplicationName);
291 AddParameter (command, "DefaultDateTime", DefaultDateTime.ToString());
293 if (1 != (int)command.ExecuteNonQuery ())
294 throw new ProviderException ("failed to update Membership table");
301 catch (ProviderException) {
305 catch (Exception e) {
307 throw new ProviderException ("error changing password question and answer", e);
311 public override MembershipUser CreateUser (string username,
317 object providerUserKey,
318 out MembershipCreateStatus status)
320 if (username != null) username = username.Trim ();
321 if (password != null) password = password.Trim ();
322 if (email != null) email = email.Trim ();
323 if (pwdQuestion != null) pwdQuestion = pwdQuestion.Trim ();
324 if (pwdAnswer != null) pwdAnswer = pwdAnswer.Trim ();
326 /* some initial validation */
327 if (username == null || username.Length == 0 || username.Length > 256 || username.IndexOf (",") != -1) {
328 status = MembershipCreateStatus.InvalidUserName;
331 if (password == null || password.Length == 0 || password.Length > 128) {
332 status = MembershipCreateStatus.InvalidPassword;
335 if (RequiresUniqueEmail && (email == null || email.Length == 0)) {
336 status = MembershipCreateStatus.InvalidEmail;
339 if (RequiresQuestionAndAnswer &&
340 (pwdQuestion == null ||
341 pwdQuestion.Length == 0 || pwdQuestion.Length > 256)) {
342 status = MembershipCreateStatus.InvalidQuestion;
345 if (RequiresQuestionAndAnswer &&
346 (pwdAnswer == null ||
347 pwdAnswer.Length == 0 || pwdAnswer.Length > 128)) {
348 status = MembershipCreateStatus.InvalidAnswer;
351 if (providerUserKey != null && ! (providerUserKey is Guid)) {
352 status = MembershipCreateStatus.InvalidProviderUserKey;
356 /* encode our password/answer using the
357 * "passwordFormat" configuration option */
358 string passwordSalt = "";
360 RandomNumberGenerator rng = RandomNumberGenerator.Create ();
361 byte[] salt = new byte[SALT_BYTES];
363 passwordSalt = Convert.ToBase64String (salt);
365 password = EncodePassword (password, PasswordFormat, passwordSalt);
366 if (RequiresQuestionAndAnswer)
367 pwdAnswer = EncodePassword (pwdAnswer, PasswordFormat, passwordSalt);
369 /* make sure the hashed/encrypted password and
370 * answer are still under 128 characters. */
371 if (password.Length > 128) {
372 status = MembershipCreateStatus.InvalidPassword;
376 if (RequiresQuestionAndAnswer) {
377 if (pwdAnswer.Length > 128) {
378 status = MembershipCreateStatus.InvalidAnswer;
385 DbTransaction trans = connection.BeginTransaction ();
395 /* get the application id since it seems that inside transactions we
396 can't insert using subqueries.. */
400 FROM dbo.aspnet_Applications
401 WHERE dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
403 command = factory.CreateCommand ();
404 command.Transaction = trans;
405 command.CommandText = commandText;
406 command.Connection = connection;
407 command.CommandType = CommandType.Text;
408 AddParameter (command, "ApplicationName", ApplicationName);
410 DbDataReader reader = command.ExecuteReader ();
412 applicationId = reader.GetGuid (0);
415 /* check for unique username, email and
416 * provider user key, if applicable */
420 FROM dbo.aspnet_Users u, dbo.aspnet_Applications a
421 WHERE u.LoweredUserName = LOWER(@UserName)
422 AND u.ApplicationId = a.ApplicationId
423 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
425 command = factory.CreateCommand ();
426 command.Transaction = trans;
427 command.CommandText = commandText;
428 command.Connection = connection;
429 command.CommandType = CommandType.Text;
430 AddParameter (command, "UserName", username);
431 AddParameter (command, "ApplicationName", ApplicationName);
433 if (0 != (int)command.ExecuteScalar()) {
434 status = MembershipCreateStatus.DuplicateUserName;
440 if (requiresUniqueEmail) {
443 FROM dbo.aspnet_Membership, dbo.aspnet_Applications
444 WHERE dbo.aspnet_Membership.Email = @Email
445 AND dbo.aspnet_Membership.ApplicationId = dbo.aspnet_Applications.ApplicationId
446 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)";
448 command = factory.CreateCommand ();
449 command.Transaction = trans;
450 command.CommandText = commandText;
451 command.Connection = connection;
452 command.CommandType = CommandType.Text;
453 AddParameter (command, "Email", email);
454 AddParameter (command, "ApplicationName", ApplicationName);
456 if (0 != (int)command.ExecuteScalar()) {
457 status = MembershipCreateStatus.DuplicateEmail;
463 if (providerUserKey != null) {
466 FROM dbo.aspnet_Membership, dbo.aspnet_Applications
467 WHERE dbo.aspnet_Membership.UserId = @ProviderUserKey
468 AND dbo.aspnet_Membership.ApplicationId = dbo.aspnet_Applications.ApplicationId
469 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)";
471 command = factory.CreateCommand ();
472 command.Transaction = trans;
473 command.CommandText = commandText;
474 command.Connection = connection;
475 command.CommandType = CommandType.Text;
476 AddParameter (command, "Email", email);
477 AddParameter (command, "ApplicationName", ApplicationName);
479 if (0 != (int)command.ExecuteScalar()) {
480 status = MembershipCreateStatus.DuplicateProviderUserKey;
486 /* first into the Users table */
488 INSERT into dbo.aspnet_Users (ApplicationId, UserId, UserName, LoweredUserName, LastActivityDate)
489 VALUES (@ApplicationId, NEWID(), @UserName, LOWER(@UserName), GETDATE())
492 command = factory.CreateCommand ();
493 command.Transaction = trans;
494 command.CommandText = commandText;
495 command.Connection = connection;
496 command.CommandType = CommandType.Text;
497 AddParameter (command, "UserName", username);
498 AddParameter (command, "ApplicationId", applicationId.ToString());
500 if (command.ExecuteNonQuery() != 1) {
501 status = MembershipCreateStatus.UserRejected; /* XXX */
506 /* then get the newly created userid */
510 FROM dbo.aspnet_Users
511 WHERE dbo.aspnet_Users.LoweredUserName = LOWER(@UserName)
513 command = factory.CreateCommand ();
514 command.Transaction = trans;
515 command.CommandText = commandText;
516 command.Connection = connection;
517 command.CommandType = CommandType.Text;
518 AddParameter (command, "UserName", username);
520 reader = command.ExecuteReader ();
522 userId = reader.GetGuid (0);
525 /* then insert into the Membership table */
526 commandText = String.Format (@"
527 INSERT into dbo.aspnet_Membership
528 VALUES (@ApplicationId,
530 @Password, @PasswordFormat, @PasswordSalt,
535 GETDATE(), GETDATE(), @DefaultDateTime,
537 0, @DefaultDateTime, 0, @DefaultDateTime, NULL)",
538 email == null ? "NULL" : "@Email",
539 email == null ? "NULL" : "LOWER(@Email)",
540 pwdQuestion == null ? "NULL" : "@PasswordQuestion",
541 pwdAnswer == null ? "NULL" : "@PasswordAnswer");
543 command = factory.CreateCommand ();
544 command.Transaction = trans;
545 command.CommandText = commandText;
546 command.Connection = connection;
547 command.CommandType = CommandType.Text;
548 AddParameter (command, "ApplicationId", applicationId.ToString());
549 AddParameter (command, "UserId", userId.ToString());
551 AddParameter (command, "Email", email);
552 AddParameter (command, "Password", password);
553 AddParameter (command, "PasswordFormat", ((int)PasswordFormat).ToString());
554 AddParameter (command, "PasswordSalt", passwordSalt);
555 if (pwdQuestion != null)
556 AddParameter (command, "PasswordQuestion", pwdQuestion);
557 if (pwdAnswer != null)
558 AddParameter (command, "PasswordAnswer", pwdAnswer);
559 AddParameter (command, "DefaultDateTime", DefaultDateTime.ToString());
561 if (command.ExecuteNonQuery() != 1) {
562 status = MembershipCreateStatus.UserRejected; /* XXX */
568 status = MembershipCreateStatus.Success;
570 return GetUser (username, false);
573 status = MembershipCreateStatus.ProviderError;
580 public override bool DeleteUser (string username, bool deleteAllRelatedData)
582 CheckParam ("username", username, 256);
584 if (deleteAllRelatedData) {
585 /* delete everything from the
586 * following features as well:
590 * WebParts Personalization
594 DbTransaction trans = connection.BeginTransaction ();
602 /* delete from the Membership table */
604 DELETE dbo.aspnet_Membership
605 FROM dbo.aspnet_Membership, dbo.aspnet_Users, dbo.aspnet_Applications
606 WHERE dbo.aspnet_Membership.UserId = dbo.aspnet_Users.UserId
607 AND dbo.aspnet_Membership.ApplicationId = dbo.aspnet_Applications.ApplicationId
608 AND dbo.aspnet_Users.LoweredUserName = LOWER (@UserName)
609 AND dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
610 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)";
612 command = factory.CreateCommand ();
613 command.Transaction = trans;
614 command.CommandText = commandText;
615 command.Connection = connection;
616 command.CommandType = CommandType.Text;
617 AddParameter (command, "UserName", username);
618 AddParameter (command, "ApplicationName", ApplicationName);
620 if (1 != command.ExecuteNonQuery())
621 throw new ProviderException ("failed to delete from Membership table");
623 /* delete from the User table */
625 DELETE dbo.aspnet_Users
626 FROM dbo.aspnet_Users, dbo.aspnet_Applications
627 WHERE dbo.aspnet_Users.LoweredUserName = LOWER (@UserName)
628 AND dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
629 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)";
631 command = factory.CreateCommand ();
632 command.Transaction = trans;
633 command.CommandText = commandText;
634 command.Connection = connection;
635 command.CommandType = CommandType.Text;
636 AddParameter (command, "UserName", username);
637 AddParameter (command, "ApplicationName", ApplicationName);
639 if (1 != command.ExecuteNonQuery())
640 throw new ProviderException ("failed to delete from User table");
652 public virtual string GeneratePassword ()
654 return Membership.GeneratePassword (minRequiredPasswordLength, minRequiredNonAlphanumericCharacters);
657 public override MembershipUserCollection FindUsersByEmail (string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
659 CheckParam ("emailToMatch", emailToMatch, 256);
662 throw new ArgumentException ("pageIndex must be >= 0");
664 throw new ArgumentException ("pageSize must be >= 0");
665 if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
666 throw new ArgumentException ("pageIndex and pageSize are too large");
673 SELECT u.UserName, m.UserId, m.Email, m.PasswordQuestion, m.Comment, m.IsApproved,
674 m.IsLockedOut, m.CreateDate, m.LastLoginDate, u.LastActivityDate,
675 m.LastPasswordChangedDate, m.LastLockoutDate
676 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
677 WHERE m.ApplicationId = a.ApplicationId
678 AND u.ApplicationId = a.ApplicationId
679 AND m.UserId = u.UserId
680 AND m.Email LIKE @Email
681 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
683 DbCommand command = factory.CreateCommand ();
684 command.CommandText = commandText;
685 command.Connection = connection;
686 command.CommandType = CommandType.Text;
687 AddParameter (command, "Email", emailToMatch);
688 AddParameter (command, "ApplicationName", ApplicationName);
690 MembershipUserCollection c = BuildMembershipUserCollection (command, pageIndex, pageSize, out totalRecords);
695 public override MembershipUserCollection FindUsersByName (string nameToMatch, int pageIndex, int pageSize, out int totalRecords)
697 CheckParam ("nameToMatch", nameToMatch, 256);
700 throw new ArgumentException ("pageIndex must be >= 0");
702 throw new ArgumentException ("pageSize must be >= 0");
703 if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
704 throw new ArgumentException ("pageIndex and pageSize are too large");
711 SELECT u.UserName, m.UserId, m.Email, m.PasswordQuestion, m.Comment, m.IsApproved,
712 m.IsLockedOut, m.CreateDate, m.LastLoginDate, u.LastActivityDate,
713 m.LastPasswordChangedDate, m.LastLockoutDate
714 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
715 WHERE m.ApplicationId = a.ApplicationId
716 AND u.ApplicationId = a.ApplicationId
717 AND m.UserId = u.UserId
718 AND u.UserName LIKE @UserName
719 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
721 DbCommand command = factory.CreateCommand ();
722 command.CommandText = commandText;
723 command.Connection = connection;
724 command.CommandType = CommandType.Text;
725 AddParameter (command, "UserName", nameToMatch);
726 AddParameter (command, "ApplicationName", ApplicationName);
728 MembershipUserCollection c = BuildMembershipUserCollection (command, pageIndex, pageSize, out totalRecords);
733 public override MembershipUserCollection GetAllUsers (int pageIndex, int pageSize, out int totalRecords)
736 throw new ArgumentException ("pageIndex must be >= 0");
738 throw new ArgumentException ("pageSize must be >= 0");
739 if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
740 throw new ArgumentException ("pageIndex and pageSize are too large");
747 SELECT u.UserName, m.UserId, m.Email, m.PasswordQuestion, m.Comment, m.IsApproved,
748 m.IsLockedOut, m.CreateDate, m.LastLoginDate, u.LastActivityDate,
749 m.LastPasswordChangedDate, m.LastLockoutDate
750 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
751 WHERE m.ApplicationId = a.ApplicationId
752 AND u.ApplicationId = a.ApplicationId
753 AND m.UserId = u.UserId
754 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
756 DbCommand command = factory.CreateCommand ();
757 command.CommandText = commandText;
758 command.Connection = connection;
759 command.CommandType = CommandType.Text;
760 AddParameter (command, "ApplicationName", ApplicationName);
762 MembershipUserCollection c = BuildMembershipUserCollection (command, pageIndex, pageSize, out totalRecords);
767 MembershipUserCollection BuildMembershipUserCollection (DbCommand command, int pageIndex, int pageSize, out int totalRecords)
769 DbDataReader reader = null;
773 int num_to_skip = pageIndex * pageSize;
774 MembershipUserCollection users = new MembershipUserCollection ();
775 reader = command.ExecuteReader ();
776 while (reader.Read()) {
777 if (num_read >= num_to_skip) {
778 if (num_added < pageSize) {
779 users.Add (GetUserFromReader (reader));
785 totalRecords = num_read;
790 return null; /* should we let the exception through? */
799 public override int GetNumberOfUsersOnline ()
805 DateTime now = DateTime.Now.ToUniversalTime ();
807 commandText = String.Format (@"
809 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
810 WHERE m.ApplicationId = a.ApplicationId
811 AND u.ApplicationId = a.ApplicationId
812 AND m.UserId = u.UserId
813 AND DATEADD(minute,{0},u.LastActivityDate) >= @Now
814 AND a.LoweredApplicationName = LOWER(@ApplicationName)",
815 userIsOnlineTimeWindow.Minutes);
817 DbCommand command = factory.CreateCommand ();
818 command.CommandText = commandText;
819 command.Connection = connection;
820 command.CommandType = CommandType.Text;
821 AddParameter (command, "Now", now.ToString ());
822 AddParameter (command, "ApplicationName", ApplicationName);
824 return (int)command.ExecuteScalar ();
827 public override string GetPassword (string username, string answer)
829 if (!enablePasswordRetrieval)
830 throw new NotSupportedException ("this provider has not been configured to allow the retrieval of passwords");
832 CheckParam ("username", username, 256);
833 if (RequiresQuestionAndAnswer)
834 CheckParam ("answer", answer, 128);
836 MembershipUser user = GetUser (username, false);
837 if (user == null) throw new ProviderException ("could not find user in membership database");
838 if (user.IsLockedOut) throw new MembershipPasswordException ("user is currently locked out");
842 DbTransaction trans = connection.BeginTransaction ();
845 MembershipPasswordFormat passwordFormat;
847 string password = null;
849 if (ValidateUsingPasswordAnswer (trans, username, answer,
850 out passwordFormat, out salt)) {
853 /* if the validation succeeds:
855 set LastLoginDate to DateTime.Now
856 set FailedPasswordAnswerAttemptCount to 0
857 set FailedPasswordAnswerAttemptWindowStart to DefaultDateTime
860 string commandText = @"
862 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
863 WHERE m.ApplicationId = a.ApplicationId
864 AND u.ApplicationId = a.ApplicationId
865 AND m.UserId = u.UserId
866 AND u.LoweredUserName = LOWER(@UserName)
867 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
869 DbCommand command = factory.CreateCommand ();
870 command.Transaction = trans;
871 command.CommandText = commandText;
872 command.Connection = connection;
873 command.CommandType = CommandType.Text;
874 AddParameter (command, "UserName", username);
875 AddParameter (command, "ApplicationName", ApplicationName);
877 DbDataReader reader = command.ExecuteReader ();
879 password = reader.GetString (0);
882 password = DecodePassword (password, passwordFormat);
885 throw new MembershipPasswordException ("The password-answer supplied is wrong.");
891 catch (MembershipPasswordException) {
901 MembershipUser GetUserFromReader (DbDataReader reader)
903 return new MembershipUser (this.Name, /* XXX is this right? */
904 reader.GetString (0), /* name */
905 reader.GetGuid (1), /* providerUserKey */
906 reader.IsDBNull (2) ? null : reader.GetString (2), /* email */
907 reader.IsDBNull (3) ? null : reader.GetString (3), /* passwordQuestion */
908 reader.IsDBNull (4) ? null : reader.GetString (4), /* comment */
909 reader.GetBoolean (5), /* isApproved */
910 reader.GetBoolean (6), /* isLockedOut */
911 reader.GetDateTime (7).ToLocalTime (), /* creationDate */
912 reader.GetDateTime (8).ToLocalTime (), /* lastLoginDate */
913 reader.GetDateTime (9).ToLocalTime (), /* lastActivityDate */
914 reader.GetDateTime (10).ToLocalTime (), /* lastPasswordChangedDate */
915 reader.GetDateTime (11).ToLocalTime () /* lastLockoutDate */);
918 MembershipUser BuildMembershipUser (DbCommand query, bool userIsOnline)
920 DbDataReader reader = null;
922 reader = query.ExecuteReader ();
926 MembershipUser user = GetUserFromReader (reader);
928 if (user != null && userIsOnline) {
934 UPDATE dbo.aspnet_Users u, dbo.aspnet_Application a
935 SET u.LastActivityDate = GETDATE()
936 WHERE u.ApplicationId = a.ApplicationId
937 AND u.UserName = @UserName
938 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
940 command = factory.CreateCommand ();
941 command.CommandText = commandText;
942 command.Connection = connection;
943 command.CommandType = CommandType.Text;
944 AddParameter (command, "UserName", user.UserName);
945 AddParameter (command, "ApplicationName", ApplicationName);
947 command.ExecuteNonQuery();
953 return null; /* should we let the exception through? */
962 public override MembershipUser GetUser (string username, bool userIsOnline)
964 CheckParam ("username", username, 256);
972 SELECT u.UserName, m.UserId, m.Email, m.PasswordQuestion, m.Comment, m.IsApproved,
973 m.IsLockedOut, m.CreateDate, m.LastLoginDate, u.LastActivityDate,
974 m.LastPasswordChangedDate, m.LastLockoutDate
975 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
976 WHERE m.ApplicationId = a.ApplicationId
977 AND u.ApplicationId = a.ApplicationId
978 AND m.UserId = u.UserId
979 AND u.UserName = @UserName
980 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
982 command = factory.CreateCommand ();
983 command.CommandText = commandText;
984 command.Connection = connection;
985 command.CommandType = CommandType.Text;
986 AddParameter (command, "UserName", username);
987 AddParameter (command, "ApplicationName", ApplicationName);
989 MembershipUser u = BuildMembershipUser (command, userIsOnline);
995 public override MembershipUser GetUser (object providerUserKey, bool userIsOnline)
1003 SELECT u.UserName, m.UserId, m.Email, m.PasswordQuestion, m.Comment, m.IsApproved,
1004 m.IsLockedOut, m.CreateDate, m.LastLoginDate, u.LastActivityDate,
1005 m.LastPasswordChangedDate, m.LastLockoutDate
1006 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
1007 WHERE m.ApplicationId = a.ApplicationId
1008 AND u.ApplicationId = a.ApplicationId
1009 AND m.UserId = u.UserId
1010 AND u.UserId = @UserKey
1011 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1013 command = factory.CreateCommand ();
1014 command.CommandText = commandText;
1015 command.Connection = connection;
1016 command.CommandType = CommandType.Text;
1017 AddParameter (command, "UserKey", providerUserKey.ToString());
1018 AddParameter (command, "ApplicationName", ApplicationName);
1020 MembershipUser u = BuildMembershipUser (command, userIsOnline);
1026 public override string GetUserNameByEmail (string email)
1028 CheckParam ("email", email, 256);
1037 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
1038 WHERE m.ApplicationId = a.ApplicationId
1039 AND u.ApplicationId = a.ApplicationId
1040 AND m.UserId = u.UserId
1041 AND m.Email = @Email
1042 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1044 command = factory.CreateCommand ();
1045 command.CommandText = commandText;
1046 command.Connection = connection;
1047 command.CommandType = CommandType.Text;
1048 AddParameter (command, "Email", email);
1049 AddParameter (command, "ApplicationName", ApplicationName);
1052 DbDataReader reader = command.ExecuteReader ();
1054 while (reader.Read())
1055 rv = reader.GetString(0);
1060 return null; /* should we allow the exception through? */
1064 bool GetBoolConfigValue (NameValueCollection config, string name, bool def)
1067 string val = config[name];
1069 try { rv = Boolean.Parse (val); }
1070 catch (Exception e) {
1071 throw new ProviderException (String.Format ("{0} must be true or false", name), e); }
1076 int GetIntConfigValue (NameValueCollection config, string name, int def)
1079 string val = config[name];
1081 try { rv = Int32.Parse (val); }
1082 catch (Exception e) {
1083 throw new ProviderException (String.Format ("{0} must be an integer", name), e); }
1088 int GetEnumConfigValue (NameValueCollection config, string name, Type enumType, int def)
1091 string val = config[name];
1093 try { rv = (int)Enum.Parse (enumType, val); }
1094 catch (Exception e) {
1095 throw new ProviderException (String.Format ("{0} must be one of the following values: {1}", name, String.Join (",", Enum.GetNames (enumType))), e); }
1100 string GetStringConfigValue (NameValueCollection config, string name, string def)
1103 string val = config[name];
1109 void EmitValidatingPassword (string username, string password, bool isNewUser)
1111 ValidatePasswordEventArgs args = new ValidatePasswordEventArgs (username, password, isNewUser);
1112 OnValidatingPassword (args);
1114 /* if we're canceled.. */
1116 if (args.FailureInformation == null)
1117 throw new ProviderException ("Password validation canceled");
1119 throw args.FailureInformation;
1123 public override void Initialize (string name, NameValueCollection config)
1126 throw new ArgumentNullException ("config");
1128 base.Initialize (name, config);
1130 applicationName = GetStringConfigValue (config, "applicationName", "/");
1131 enablePasswordReset = GetBoolConfigValue (config, "enablePasswordReset", true);
1132 enablePasswordRetrieval = GetBoolConfigValue (config, "enablePasswordRetrieval", false);
1133 requiresQuestionAndAnswer = GetBoolConfigValue (config, "requiresQuestionAndAnswer", true);
1134 requiresUniqueEmail = GetBoolConfigValue (config, "requiresUniqueEmail", false);
1135 passwordFormat = (MembershipPasswordFormat)GetEnumConfigValue (config, "passwordFormat", typeof (MembershipPasswordFormat),
1136 (int)MembershipPasswordFormat.Hashed);
1137 maxInvalidPasswordAttempts = GetIntConfigValue (config, "maxInvalidPasswordAttempts", 5);
1138 minRequiredPasswordLength = GetIntConfigValue (config, "minRequiredPasswordLength", 7);
1139 minRequiredNonAlphanumericCharacters = GetIntConfigValue (config, "minRequiredNonAlphanumericCharacters", 1);
1140 passwordAttemptWindow = GetIntConfigValue (config, "passwordAttemptWindow", 10);
1141 passwordStrengthRegularExpression = GetStringConfigValue (config, "passwordStrengthRegularExpression", "");
1143 MembershipSection section = (MembershipSection)WebConfigurationManager.GetSection ("system.web/membership");
1145 userIsOnlineTimeWindow = section.UserIsOnlineTimeWindow;
1147 /* we can't support password retrieval with hashed passwords */
1148 if (passwordFormat == MembershipPasswordFormat.Hashed && enablePasswordRetrieval)
1149 throw new ProviderException ("password retrieval cannot be used with hashed passwords");
1151 string connectionStringName = config["connectionStringName"];
1153 if (applicationName.Length > 256)
1154 throw new ProviderException ("The ApplicationName attribute must be 256 characters long or less.");
1155 if (connectionStringName == null || connectionStringName.Length == 0)
1156 throw new ProviderException ("The ConnectionStringName attribute must be present and non-zero length.");
1158 connectionString = WebConfigurationManager.ConnectionStrings[connectionStringName];
1161 public override string ResetPassword (string username, string answer)
1163 if (!enablePasswordReset)
1164 throw new NotSupportedException ("this provider has not been configured to allow the resetting of passwords");
1166 CheckParam ("username", username, 256);
1167 if (RequiresQuestionAndAnswer)
1168 CheckParam ("answer", answer, 128);
1170 MembershipUser user = GetUser (username, false);
1171 if (user == null) throw new ProviderException ("could not find user in membership database");
1172 if (user.IsLockedOut) throw new MembershipPasswordException ("user is currently locked out");
1179 DbTransaction trans = connection.BeginTransaction ();
1182 MembershipPasswordFormat db_passwordFormat;
1184 string newPassword = null;
1186 if (ValidateUsingPasswordAnswer (trans, user.UserName, answer, out db_passwordFormat, out db_salt)) {
1188 newPassword = GeneratePassword ();
1191 EmitValidatingPassword (username, newPassword, false);
1193 /* otherwise update the user's password in the db */
1195 db_password = EncodePassword (newPassword, db_passwordFormat, db_salt);
1199 SET Password = @Password,
1200 FailedPasswordAnswerAttemptCount = 0,
1201 FailedPasswordAnswerAttemptWindowStart = @DefaultDateTime
1202 FROM dbo.aspnet_Membership m, dbo.aspnet_Users u, dbo.aspnet_Applications a
1203 WHERE m.ApplicationId = a.ApplicationId
1204 AND u.ApplicationId = a.ApplicationId
1205 AND m.UserId = u.UserId
1206 AND u.LoweredUserName = LOWER(@UserName)
1207 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1209 command = factory.CreateCommand ();
1210 command.Transaction = trans;
1211 command.CommandText = commandText;
1212 command.Connection = connection;
1213 command.CommandType = CommandType.Text;
1214 AddParameter (command, "UserName", user.UserName);
1215 AddParameter (command, "Password", db_password);
1216 AddParameter (command, "ApplicationName", ApplicationName);
1217 AddParameter (command, "DefaultDateTime", DefaultDateTime.ToString());
1219 if (1 != (int)command.ExecuteNonQuery ())
1220 throw new ProviderException ("failed to update Membership table");
1225 throw new MembershipPasswordException ("The password-answer supplied is wrong.");
1230 catch (MembershipPasswordException) {
1234 catch (ProviderException) {
1238 catch (Exception e) {
1241 throw new ProviderException ("Failed to reset password", e);
1245 public override void UpdateUser (MembershipUser user)
1247 if (user == null) throw new ArgumentNullException ("user");
1248 if (user.UserName == null) throw new ArgumentNullException ("user.UserName");
1249 if (RequiresUniqueEmail && user.Email == null) throw new ArgumentNullException ("user.Email");
1251 CheckParam ("user.UserName", user.UserName, 256);
1252 if (user.Email.Length > 256 || (RequiresUniqueEmail && user.Email.Length == 0))
1253 throw new ArgumentException ("invalid format for user.Email");
1255 DbTransaction trans = connection.BeginTransaction ();
1263 DateTime now = DateTime.Now.ToUniversalTime ();
1265 commandText = String.Format (@"
1269 IsApproved = @IsApproved,
1270 LastLoginDate = @Now
1271 FROM dbo.aspnet_Membership m, dbo.aspnet_Users u, dbo.aspnet_Applications a
1272 WHERE m.ApplicationId = a.ApplicationId
1273 AND u.ApplicationId = a.ApplicationId
1274 AND m.UserId = u.UserId
1275 AND u.LoweredUserName = LOWER(@UserName)
1276 AND a.LoweredApplicationName = LOWER(@ApplicationName)",
1277 user.Email == null ? "NULL" : "@Email",
1278 user.Comment == null ? "NULL" : "@Comment");
1280 command = factory.CreateCommand ();
1281 command.Transaction = trans;
1282 command.CommandText = commandText;
1283 command.Connection = connection;
1284 command.CommandType = CommandType.Text;
1285 if (user.Email != null)
1286 AddParameter (command, "Email", user.Email);
1287 if (user.Comment != null)
1288 AddParameter (command, "Comment", user.Comment);
1289 AddParameter (command, "IsApproved", user.IsApproved.ToString());
1290 AddParameter (command, "UserName", user.UserName);
1291 AddParameter (command, "ApplicationName", ApplicationName);
1292 AddParameter (command, "Now", now.ToString ());
1294 if (0 == command.ExecuteNonQuery())
1295 throw new ProviderException ("failed to membership table");
1299 UPDATE dbo.aspnet_Users
1300 SET LastActivityDate = @Now
1301 FROM dbo.aspnet_Users u, dbo.aspnet_Applications a
1302 WHERE a.ApplicationId = a.ApplicationId
1303 AND u.LoweredUserName = LOWER(@UserName)
1304 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1306 command = factory.CreateCommand ();
1307 command.Transaction = trans;
1308 command.CommandText = commandText;
1309 command.Connection = connection;
1310 command.CommandType = CommandType.Text;
1311 AddParameter (command, "UserName", user.UserName);
1312 AddParameter (command, "ApplicationName", ApplicationName);
1313 AddParameter (command, "Now", now.ToString ());
1315 if (0 == command.ExecuteNonQuery())
1316 throw new ProviderException ("failed to user table");
1320 catch (ProviderException) {
1324 catch (Exception e) {
1326 throw new ProviderException ("failed to update user", e);
1330 public override bool ValidateUser (string username, string password)
1332 MembershipUser user = GetUser (username, false);
1334 /* if the user is locked out, return false immediately */
1335 if (user.IsLockedOut)
1338 /* if the user is not yet approved, return false */
1339 if (!user.IsApproved)
1342 EmitValidatingPassword (username, password, false);
1346 DbTransaction trans = connection.BeginTransaction ();
1352 MembershipPasswordFormat passwordFormat;
1355 bool valid = ValidateUsingPassword (trans, username, password, out passwordFormat, out salt);
1358 DateTime now = DateTime.Now.ToUniversalTime ();
1360 /* if the validation succeeds:
1361 set LastLoginDate to DateTime.Now
1362 set FailedPasswordAttemptCount to 0
1363 set FailedPasswordAttemptWindow to DefaultDateTime
1364 set FailedPasswordAnswerAttemptCount to 0
1365 set FailedPasswordAnswerAttemptWindowStart to DefaultDateTime
1369 UPDATE dbo.aspnet_Membership
1370 SET LastLoginDate = @Now,
1371 FailedPasswordAttemptCount = 0,
1372 FailedPasswordAttemptWindowStart = @DefaultDateTime,
1373 FailedPasswordAnswerAttemptCount = 0,
1374 FailedPasswordAnswerAttemptWindowStart = @DefaultDateTime
1375 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
1376 WHERE m.ApplicationId = a.ApplicationId
1377 AND u.ApplicationId = a.ApplicationId
1378 AND m.UserId = u.UserId
1379 AND u.LoweredUserName = LOWER(@UserName)
1380 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1382 command = factory.CreateCommand ();
1383 command.Transaction = trans;
1384 command.CommandText = commandText;
1385 command.Connection = connection;
1386 command.CommandType = CommandType.Text;
1387 AddParameter (command, "UserName", user.UserName);
1388 AddParameter (command, "ApplicationName", ApplicationName);
1389 AddParameter (command, "Now", now.ToString ());
1390 AddParameter (command, "DefaultDateTime", DefaultDateTime.ToString());
1392 if (1 != (int)command.ExecuteNonQuery ())
1393 throw new ProviderException ("failed to update Membership table");
1396 UPDATE dbo.aspnet_Users
1397 SET LastActivityDate = @Now
1398 FROM dbo.aspnet_Applications a, dbo.aspnet_Users u
1399 WHERE u.ApplicationId = a.ApplicationId
1400 AND u.LoweredUserName = LOWER(@UserName)
1401 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1403 command = factory.CreateCommand ();
1404 command.Transaction = trans;
1405 command.CommandText = commandText;
1406 command.Connection = connection;
1407 command.CommandType = CommandType.Text;
1408 AddParameter (command, "UserName", user.UserName);
1409 AddParameter (command, "ApplicationName", ApplicationName);
1410 AddParameter (command, "Now", now.ToString ());
1412 if (1 != (int)command.ExecuteNonQuery ())
1413 throw new ProviderException ("failed to update User table");
1427 public override bool UnlockUser (string userName)
1429 CheckParam ("userName", userName, 256);
1431 string commandText = @"
1432 UPDATE dbo.aspnet_Membership
1433 SET IsLockedOut = 0,
1434 LastLockoutDate = @DefaultDateTime,
1435 FailedPasswordAttemptCount = 0,
1436 FailedPasswordAttemptWindowStart = @DefaultDateTime,
1437 FailedPasswordAnswerAttemptCount = 0,
1438 FailedPasswordAnswerAttemptWindowStart = @DefaultDateTime
1439 FROM dbo.aspnet_Membership m, dbo.aspnet_Users u, dbo.aspnet_Applications a
1440 WHERE m.UserId = u.UserId
1441 AND m.ApplicationId = a.ApplicationId
1442 AND u.ApplicationId = a.ApplicationId
1443 AND u.LoweredUserName = LOWER (@UserName)
1444 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1448 DbCommand command = factory.CreateCommand ();
1449 command.CommandText = commandText;
1450 command.Connection = connection;
1451 command.CommandType = CommandType.Text;
1452 AddParameter (command, "UserName", userName);
1453 AddParameter (command, "ApplicationName", ApplicationName);
1454 AddParameter (command, "DefaultDateTime", DefaultDateTime.ToString());
1456 return command.ExecuteNonQuery() == 1;
1459 void IncrementFailureAndMaybeLockout (DbTransaction trans, string username,
1460 string failureCountAttribute, string failureWindowAttribute)
1462 DateTime now = DateTime.Now;
1464 /* if validation fails:
1465 if (FailedPasswordAttemptWindowStart - DateTime.Now < PasswordAttemptWindow)
1466 increment FailedPasswordAttemptCount
1467 FailedPasswordAttemptWindowStart = DateTime.Now
1468 if (FailedPasswordAttemptCount > MaxInvalidPasswordAttempts)
1469 set IsLockedOut = true.
1470 set LastLockoutDate = DateTime.Now
1473 string commandText = String.Format (@"
1475 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
1476 WHERE m.ApplicationId = a.ApplicationId
1477 AND u.ApplicationId = a.ApplicationId
1478 AND m.UserId = u.UserId
1479 AND u.LoweredUserName = LOWER(@UserName)
1480 AND a.LoweredApplicationName = LOWER(@ApplicationName)",
1481 failureCountAttribute, failureWindowAttribute);
1483 DbCommand command = factory.CreateCommand ();
1484 command.Transaction = trans;
1485 command.CommandText = commandText;
1486 command.Connection = connection;
1487 command.CommandType = CommandType.Text;
1488 AddParameter (command, "UserName", username);
1489 AddParameter (command, "ApplicationName", ApplicationName);
1491 DateTime db_FailedWindowStart;
1494 DbDataReader reader = command.ExecuteReader ();
1496 db_FailedCount = reader.GetInt32 (0);
1497 db_FailedWindowStart = reader.GetDateTime (1).ToLocalTime ();
1500 TimeSpan diff = now.Subtract (db_FailedWindowStart);
1501 if ((db_FailedWindowStart == DefaultDateTime.ToLocalTime ())
1502 || diff.Minutes < PasswordAttemptWindow)
1505 if (db_FailedCount > MaxInvalidPasswordAttempts) {
1506 /* lock the user out */
1508 UPDATE dbo.aspnet_Membership
1509 SET IsLockedOut = 1,
1510 LastLockoutDate = @LastLockoutDate
1511 FROM dbo.aspnet_Membership m, dbo.aspnet_Users u, dbo.aspnet_Applications a
1512 WHERE m.ApplicationId = a.ApplicationId
1513 AND u.ApplicationId = a.ApplicationId
1514 AND m.UserId = u.UserId
1515 AND u.LoweredUserName = LOWER(@UserName)
1516 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1518 command = factory.CreateCommand ();
1519 command.Transaction = trans;
1520 command.CommandText = commandText;
1521 command.Connection = connection;
1522 command.CommandType = CommandType.Text;
1523 AddParameter (command, "UserName", username);
1524 AddParameter (command, "ApplicationName", ApplicationName);
1525 AddParameter (command, "LastLockoutDate", now.ToUniversalTime().ToString ());
1528 /* just store back the updated window start and count */
1529 commandText = String.Format (@"
1530 UPDATE dbo.aspnet_Membership
1533 FROM dbo.aspnet_Membership m, dbo.aspnet_Users u, dbo.aspnet_Applications a
1534 WHERE m.ApplicationId = a.ApplicationId
1535 AND u.ApplicationId = a.ApplicationId
1536 AND m.UserId = u.UserId
1537 AND u.LoweredUserName = LOWER(@UserName)
1538 AND a.LoweredApplicationName = LOWER(@ApplicationName)",
1539 failureCountAttribute, failureWindowAttribute);
1541 command = factory.CreateCommand ();
1542 command.Transaction = trans;
1543 command.CommandText = commandText;
1544 command.Connection = connection;
1545 command.CommandType = CommandType.Text;
1546 AddParameter (command, "UserName", username);
1547 AddParameter (command, "ApplicationName", ApplicationName);
1548 AddParameter (command, failureCountAttribute, db_FailedCount.ToString());
1549 AddParameter (command, failureWindowAttribute, now.ToUniversalTime().ToString ());
1552 if (1 != (int)command.ExecuteNonQuery ())
1553 throw new ProviderException ("failed to update Membership table");
1556 bool ValidateUsingPassword (DbTransaction trans, string username, string password,
1557 out MembershipPasswordFormat passwordFormat,
1560 string commandText = @"
1561 SELECT m.Password, m.PasswordFormat, m.PasswordSalt
1562 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
1563 WHERE m.ApplicationId = a.ApplicationId
1564 AND u.ApplicationId = a.ApplicationId
1565 AND m.UserId = u.UserId
1566 AND u.LoweredUserName = LOWER(@UserName)
1567 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1569 DbCommand command = factory.CreateCommand ();
1570 command.Transaction = trans;
1571 command.CommandText = commandText;
1572 command.Connection = connection;
1573 command.CommandType = CommandType.Text;
1574 AddParameter (command, "UserName", username);
1575 AddParameter (command, "ApplicationName", ApplicationName);
1579 DbDataReader reader = command.ExecuteReader ();
1581 db_password = reader.GetString (0);
1582 passwordFormat = (MembershipPasswordFormat)reader.GetInt32 (1);
1583 salt = reader.GetString (2);
1586 /* do the actual validation */
1587 password = EncodePassword (password, passwordFormat, salt);
1589 bool valid = (password == db_password);
1592 IncrementFailureAndMaybeLockout (trans, username,
1593 "FailedPasswordAttemptCount", "FailedPasswordAttemptWindowStart");
1599 bool ValidateUsingPasswordAnswer (DbTransaction trans, string username, string answer,
1600 out MembershipPasswordFormat passwordFormat,
1603 string commandText = @"
1604 SELECT m.PasswordAnswer, m.PasswordFormat, m.PasswordSalt
1605 FROM dbo.aspnet_Membership m, dbo.aspnet_Applications a, dbo.aspnet_Users u
1606 WHERE m.ApplicationId = a.ApplicationId
1607 AND u.ApplicationId = a.ApplicationId
1608 AND m.UserId = u.UserId
1609 AND u.LoweredUserName = LOWER(@UserName)
1610 AND a.LoweredApplicationName = LOWER(@ApplicationName)";
1612 DbCommand command = factory.CreateCommand ();
1613 command.Transaction = trans;
1614 command.CommandText = commandText;
1615 command.Connection = connection;
1616 command.CommandType = CommandType.Text;
1617 AddParameter (command, "UserName", username);
1618 AddParameter (command, "ApplicationName", ApplicationName);
1622 DbDataReader reader = command.ExecuteReader ();
1624 db_answer = reader.GetString (0);
1625 passwordFormat = (MembershipPasswordFormat)reader.GetInt32 (1);
1626 salt = reader.GetString (2);
1629 /* do the actual password answer check */
1630 answer = EncodePassword (answer, passwordFormat, salt);
1632 if (answer.Length > 128)
1633 throw new ArgumentException (String.Format ("password answer hashed to longer than 128 characters"));
1635 bool valid = (answer == db_answer);
1638 IncrementFailureAndMaybeLockout (trans, username,
1639 "FailedPasswordAnswerAttemptCount",
1640 "FailedPasswordAnswerAttemptWindowStart");
1646 public override string ApplicationName {
1647 get { return applicationName; }
1648 set { applicationName = value; }
1651 public override bool EnablePasswordReset {
1652 get { return enablePasswordReset; }
1655 public override bool EnablePasswordRetrieval {
1656 get { return enablePasswordRetrieval; }
1659 public override MembershipPasswordFormat PasswordFormat {
1660 get { return passwordFormat; }
1663 public override bool RequiresQuestionAndAnswer {
1664 get { return requiresQuestionAndAnswer; }
1667 public override bool RequiresUniqueEmail {
1668 get { return requiresUniqueEmail; }
1671 public override int MaxInvalidPasswordAttempts {
1672 get { return maxInvalidPasswordAttempts; }
1675 public override int MinRequiredNonAlphanumericCharacters {
1676 get { return minRequiredNonAlphanumericCharacters; }
1679 public override int MinRequiredPasswordLength {
1680 get { return minRequiredPasswordLength; }
1683 public override int PasswordAttemptWindow {
1684 get { return passwordAttemptWindow; }
1687 public override string PasswordStrengthRegularExpression {
1688 get { return passwordStrengthRegularExpression; }