2008-02-25 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Security / SqlMembershipProvider.cs
1 //
2 // System.Web.Security.SqlMembershipProvider
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Lluis Sanchez Gual (lluis@novell.com)
7 //      Chris Toshok (toshok@ximian.com)
8 //
9 // (C) 2003 Ben Maurer
10 // Copyright (c) 2005,2006 Novell, Inc (http://www.novell.com)
11 //
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:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
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.
30 //
31
32 #if NET_2_0
33 using System.Collections;
34 using System.Collections.Specialized;
35 using System.Configuration;
36 using System.Configuration.Provider;
37 using System.Data;
38 using System.Data.Common;
39 using System.Text;
40 using System.Web.Configuration;
41 using System.Security.Cryptography;
42
43 namespace System.Web.Security {
44         public class SqlMembershipProvider : MembershipProvider
45         {
46                 bool enablePasswordReset;
47                 bool enablePasswordRetrieval;
48                 int maxInvalidPasswordAttempts;
49                 MembershipPasswordFormat passwordFormat;
50                 bool requiresQuestionAndAnswer;
51                 bool requiresUniqueEmail;
52                 int minRequiredNonAlphanumericCharacters;
53                 int minRequiredPasswordLength;
54                 int passwordAttemptWindow;
55                 string passwordStrengthRegularExpression;
56                 TimeSpan userIsOnlineTimeWindow;
57
58                 ConnectionStringSettings connectionString;
59                 DbProviderFactory factory;
60
61                 string applicationName;
62                 bool schemaIsOk = false;
63
64                 DbConnection CreateConnection ()
65                 {
66                         if (!schemaIsOk && !(schemaIsOk = AspNetDBSchemaChecker.CheckMembershipSchemaVersion (factory, connectionString.ConnectionString, "membership", "1")))
67                                 throw new ProviderException ("Incorrect ASP.NET DB Schema Version.");
68
69                         DbConnection connection;
70
71                         if (connectionString == null)
72                                 throw new ProviderException ("Connection string for the SQL Membership Provider has not been provided.");
73                         
74                         try {
75                                 connection = factory.CreateConnection ();
76                                 connection.ConnectionString = connectionString.ConnectionString;
77                                 connection.Open ();
78                         } catch (Exception ex) {
79                                 throw new ProviderException ("Unable to open SQL connection for the SQL Membership Provider.",
80                                                              ex);
81                         }
82                         
83                         return connection;
84                 }
85
86                 DbParameter AddParameter (DbCommand command, string parameterName, object parameterValue)
87                 {
88                         return AddParameter (command, parameterName, ParameterDirection.Input, parameterValue);
89                 }
90
91                 DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, object parameterValue)
92                 {
93                         DbParameter dbp = command.CreateParameter ();
94                         dbp.ParameterName = parameterName;
95                         dbp.Value = parameterValue;
96                         dbp.Direction = direction;
97                         command.Parameters.Add (dbp);
98                         return dbp;
99                 }
100
101                 DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, DbType type, object parameterValue)
102                 {
103                         DbParameter dbp = command.CreateParameter ();
104                         dbp.ParameterName = parameterName;
105                         dbp.Value = parameterValue;
106                         dbp.Direction = direction;
107                         dbp.DbType = type;
108                         command.Parameters.Add (dbp);
109                         return dbp;
110                 }
111
112                 static int GetReturnValue (DbParameter returnValue)
113                 {
114                         object value = returnValue.Value;
115                         return value is int ? (int) value : -1;
116                 }
117
118                 void CheckParam (string pName, string p, int length)
119                 {
120                         if (p == null)
121                                 throw new ArgumentNullException (pName);
122                         if (p.Length == 0 || p.Length > length || p.IndexOf (",") != -1)
123                                 throw new ArgumentException (String.Format ("invalid format for {0}", pName));
124                 }
125
126                 public override bool ChangePassword (string username, string oldPwd, string newPwd)
127                 {
128                         if (username != null) username = username.Trim ();
129                         if (oldPwd != null) oldPwd = oldPwd.Trim ();
130                         if (newPwd != null) newPwd = newPwd.Trim ();
131
132                         CheckParam ("username", username, 256);
133                         CheckParam ("oldPwd", oldPwd, 128);
134                         CheckParam ("newPwd", newPwd, 128);
135
136                         if (!CheckPassword (newPwd))
137                                 throw new ArgumentException (string.Format (
138                                                 "New Password invalid. New Password length minimum: {0}. Non-alphanumeric characters required: {1}.",
139                                                 MinRequiredPasswordLength,
140                                                 MinRequiredNonAlphanumericCharacters));
141
142                         using (DbConnection connection = CreateConnection ()) {
143                                 PasswordInfo pi = ValidateUsingPassword (username, oldPwd);
144
145                                 if (pi != null) {
146                                         EmitValidatingPassword (username, newPwd, false);
147                                         string db_password = EncodePassword (newPwd, pi.PasswordFormat, pi.PasswordSalt);
148
149                                         DbCommand command = factory.CreateCommand ();
150                                         command.Connection = connection;
151                                         command.CommandText = @"aspnet_Membership_SetPassword";
152                                         command.CommandType = CommandType.StoredProcedure;
153
154                                         AddParameter (command, "@ApplicationName", ApplicationName);
155                                         AddParameter (command, "@UserName", username);
156                                         AddParameter (command, "@NewPassword", db_password);
157                                         AddParameter (command, "@PasswordFormat", (int) pi.PasswordFormat);
158                                         AddParameter (command, "@PasswordSalt", pi.PasswordSalt);
159                                         AddParameter (command, "@CurrentTimeUtc", DateTime.UtcNow);
160                                         DbParameter returnValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
161
162                                         command.ExecuteNonQuery ();
163
164                                         if (GetReturnValue (returnValue) != 0)
165                                                 return false;
166
167                                         return true;
168                                 }
169                                 return false;
170                         }
171                 }
172
173                 public override bool ChangePasswordQuestionAndAnswer (string username, string password, string newPwdQuestion, string newPwdAnswer)
174                 {
175                         if (username != null) username = username.Trim ();
176                         if (newPwdQuestion != null) newPwdQuestion = newPwdQuestion.Trim ();
177                         if (newPwdAnswer != null) newPwdAnswer = newPwdAnswer.Trim ();
178
179                         CheckParam ("username", username, 256);
180                         if (RequiresQuestionAndAnswer)
181                                 CheckParam ("newPwdQuestion", newPwdQuestion, 128);
182                         if (RequiresQuestionAndAnswer)
183                                 CheckParam ("newPwdAnswer", newPwdAnswer, 128);
184
185                         using (DbConnection connection = CreateConnection ()) {
186                                 PasswordInfo pi = ValidateUsingPassword (username, password);
187
188                                 if (pi != null) {
189                                         string db_passwordAnswer = EncodePassword (newPwdAnswer, pi.PasswordFormat, pi.PasswordSalt);
190
191                                         DbCommand command = factory.CreateCommand ();
192                                         command.Connection = connection;
193                                         command.CommandType = CommandType.StoredProcedure;
194                                         command.CommandText = @"aspnet_Membership_ChangePasswordQuestionAndAnswer";
195
196                                         AddParameter (command, "@ApplicationName", ApplicationName);
197                                         AddParameter (command, "@UserName", username);
198                                         AddParameter (command, "@NewPasswordQuestion", newPwdQuestion);
199                                         AddParameter (command, "@NewPasswordAnswer", db_passwordAnswer);
200                                         DbParameter returnValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
201
202                                         command.ExecuteNonQuery ();
203
204                                         if (GetReturnValue (returnValue) != 0)
205                                                 return false;
206
207                                         return true;
208                                 }
209                                 return false;
210                         }
211                 }
212
213                 public override MembershipUser CreateUser (string username,
214                                                            string password,
215                                                            string email,
216                                                            string pwdQuestion,
217                                                            string pwdAnswer,
218                                                            bool isApproved,
219                                                            object providerUserKey,
220                                                            out MembershipCreateStatus status)
221                 {
222                         if (username != null) username = username.Trim ();
223                         if (password != null) password = password.Trim ();
224                         if (email != null) email = email.Trim ();
225                         if (pwdQuestion != null) pwdQuestion = pwdQuestion.Trim ();
226                         if (pwdAnswer != null) pwdAnswer = pwdAnswer.Trim ();
227
228                         /* some initial validation */
229                         if (username == null || username.Length == 0 || username.Length > 256 || username.IndexOf (",") != -1) {
230                                 status = MembershipCreateStatus.InvalidUserName;
231                                 return null;
232                         }
233                         if (password == null || password.Length == 0 || password.Length > 128) {
234                                 status = MembershipCreateStatus.InvalidPassword;
235                                 return null;
236                         }
237
238                         if (!CheckPassword (password)) {
239                                 status = MembershipCreateStatus.InvalidPassword;
240                                 return null;
241                         }
242                         EmitValidatingPassword (username, password, true);
243
244                         if (RequiresUniqueEmail && (email == null || email.Length == 0)) {
245                                 status = MembershipCreateStatus.InvalidEmail;
246                                 return null;
247                         }
248                         if (RequiresQuestionAndAnswer &&
249                                 (pwdQuestion == null ||
250                                  pwdQuestion.Length == 0 || pwdQuestion.Length > 256)) {
251                                 status = MembershipCreateStatus.InvalidQuestion;
252                                 return null;
253                         }
254                         if (RequiresQuestionAndAnswer &&
255                                 (pwdAnswer == null ||
256                                  pwdAnswer.Length == 0 || pwdAnswer.Length > 128)) {
257                                 status = MembershipCreateStatus.InvalidAnswer;
258                                 return null;
259                         }
260                         if (providerUserKey != null && !(providerUserKey is Guid)) {
261                                 status = MembershipCreateStatus.InvalidProviderUserKey;
262                                 return null;
263                         }
264
265                         if (providerUserKey == null)
266                                 providerUserKey = Guid.NewGuid();
267
268                         /* encode our password/answer using the
269                          * "passwordFormat" configuration option */
270                         string passwordSalt = "";
271
272                         RandomNumberGenerator rng = RandomNumberGenerator.Create ();
273                         byte [] salt = new byte [SALT_BYTES];
274                         rng.GetBytes (salt);
275                         passwordSalt = Convert.ToBase64String (salt);
276
277                         password = EncodePassword (password, PasswordFormat, passwordSalt);
278                         if (RequiresQuestionAndAnswer)
279                                 pwdAnswer = EncodePassword (pwdAnswer, PasswordFormat, passwordSalt);
280
281                         /* make sure the hashed/encrypted password and
282                          * answer are still under 128 characters. */
283                         if (password.Length > 128) {
284                                 status = MembershipCreateStatus.InvalidPassword;
285                                 return null;
286                         }
287
288                         if (RequiresQuestionAndAnswer) {
289                                 if (pwdAnswer.Length > 128) {
290                                         status = MembershipCreateStatus.InvalidAnswer;
291                                         return null;
292                                 }
293                         }
294                         status = MembershipCreateStatus.Success;
295
296                         using (DbConnection connection = CreateConnection ()) {
297
298                                 try {
299                                         DbCommand command = factory.CreateCommand ();
300                                         command.Connection = connection;
301                                         command.CommandText = @"aspnet_Membership_CreateUser";
302                                         command.CommandType = CommandType.StoredProcedure;
303
304                                         DateTime Now = DateTime.UtcNow;
305
306                                         AddParameter (command, "@ApplicationName", ApplicationName);
307                                         AddParameter (command, "@UserName", username);
308                                         AddParameter (command, "@Password", password);
309                                         AddParameter (command, "@PasswordSalt", passwordSalt);
310                                         AddParameter (command, "@Email", email);
311                                         AddParameter (command, "@PasswordQuestion", pwdQuestion);
312                                         AddParameter (command, "@PasswordAnswer", pwdAnswer);
313                                         AddParameter (command, "@IsApproved", isApproved);
314                                         AddParameter (command, "@CurrentTimeUtc", Now);
315                                         AddParameter (command, "@CreateDate", Now);
316                                         AddParameter (command, "@UniqueEmail", RequiresUniqueEmail);
317                                         AddParameter (command, "@PasswordFormat", (int) PasswordFormat);
318                                         AddParameter (command, "@UserId", ParameterDirection.InputOutput, providerUserKey);
319                                         DbParameter returnValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
320
321                                         command.ExecuteNonQuery ();
322
323                                         int st = GetReturnValue (returnValue);
324
325                                         if (st == 0)
326                                                 return GetUser (username, false);
327                                         else if (st == 6)
328                                                 status = MembershipCreateStatus.DuplicateUserName;
329                                         else if (st == 7)
330                                                 status = MembershipCreateStatus.DuplicateEmail;
331                                         else if (st == 10)
332                                                 status = MembershipCreateStatus.DuplicateProviderUserKey;
333                                         else
334                                                 status = MembershipCreateStatus.ProviderError;
335
336                                         return null;
337                                 }
338                                 catch (Exception) {
339                                         status = MembershipCreateStatus.ProviderError;
340                                         return null;
341                                 }
342                         }
343                 }
344
345                 private bool CheckPassword (string password)
346                 {
347                         if (password.Length < MinRequiredPasswordLength)
348                                 return false;
349
350                         if (MinRequiredNonAlphanumericCharacters > 0) {
351                                 int nonAlphanumeric = 0;
352                                 for (int i = 0; i < password.Length; i++) {
353                                         if (!Char.IsLetterOrDigit (password [i]))
354                                                 nonAlphanumeric++;
355                                 }
356                                 return nonAlphanumeric >= MinRequiredNonAlphanumericCharacters;
357                         }
358                         return true;
359                 }
360
361                 public override bool DeleteUser (string username, bool deleteAllRelatedData)
362                 {
363                         CheckParam ("username", username, 256);
364
365                         DeleteUserTableMask deleteBitmask = DeleteUserTableMask.MembershipUsers;
366
367                         if (deleteAllRelatedData)
368                                 deleteBitmask |=
369                                         DeleteUserTableMask.Profiles |
370                                         DeleteUserTableMask.UsersInRoles |
371                                         DeleteUserTableMask.WebPartStateUser;
372
373                         using (DbConnection connection = CreateConnection ()) {
374                                 DbCommand command = factory.CreateCommand ();
375                                 command.Connection = connection;
376                                 command.CommandText = @"aspnet_Users_DeleteUser";
377                                 command.CommandType = CommandType.StoredProcedure;
378
379                                 AddParameter (command, "@ApplicationName", ApplicationName);
380                                 AddParameter (command, "@UserName", username);
381                                 AddParameter (command, "@TablesToDeleteFrom", (int) deleteBitmask);
382                                 AddParameter (command, "@NumTablesDeletedFrom", ParameterDirection.Output, 0);
383                                 DbParameter returnValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
384
385                                 command.ExecuteNonQuery ();
386
387                                 if (((int) command.Parameters ["@NumTablesDeletedFrom"].Value) == 0)
388                                         return false;
389
390                                 if (GetReturnValue (returnValue) == 0)
391                                         return true;
392
393                                 return false;
394                         }
395                 }
396
397                 public virtual string GeneratePassword ()
398                 {
399                         return Membership.GeneratePassword (MinRequiredPasswordLength, MinRequiredNonAlphanumericCharacters);
400                 }
401
402                 public override MembershipUserCollection FindUsersByEmail (string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
403                 {
404                         CheckParam ("emailToMatch", emailToMatch, 256);
405
406                         if (pageIndex < 0)
407                                 throw new ArgumentException ("pageIndex must be >= 0");
408                         if (pageSize < 0)
409                                 throw new ArgumentException ("pageSize must be >= 0");
410                         if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
411                                 throw new ArgumentException ("pageIndex and pageSize are too large");
412
413                         using (DbConnection connection = CreateConnection ()) {
414
415                                 DbCommand command = factory.CreateCommand ();
416                                 command.Connection = connection;
417                                 command.CommandText = @"aspnet_Membership_FindUsersByEmail";
418                                 command.CommandType = CommandType.StoredProcedure;
419
420                                 AddParameter (command, "@PageIndex", pageIndex);
421                                 AddParameter (command, "@PageSize", pageSize);
422                                 AddParameter (command, "@EmailToMatch", emailToMatch);
423                                 AddParameter (command, "@ApplicationName", ApplicationName);
424                                 // return value
425                                 AddParameter (command, "@ReturnValue", ParameterDirection.ReturnValue, null);
426
427                                 MembershipUserCollection c = BuildMembershipUserCollection (command, pageIndex, pageSize, out totalRecords);
428
429                                 return c;
430                         }
431                 }
432
433                 public override MembershipUserCollection FindUsersByName (string nameToMatch, int pageIndex, int pageSize, out int totalRecords)
434                 {
435                         CheckParam ("nameToMatch", nameToMatch, 256);
436
437                         if (pageIndex < 0)
438                                 throw new ArgumentException ("pageIndex must be >= 0");
439                         if (pageSize < 0)
440                                 throw new ArgumentException ("pageSize must be >= 0");
441                         if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
442                                 throw new ArgumentException ("pageIndex and pageSize are too large");
443
444                         using (DbConnection connection = CreateConnection ()) {
445
446                                 DbCommand command = factory.CreateCommand ();
447                                 command.Connection = connection;
448                                 command.CommandText = @"aspnet_Membership_FindUsersByName";
449                                 command.CommandType = CommandType.StoredProcedure;
450
451                                 AddParameter (command, "@PageIndex", pageIndex);
452                                 AddParameter (command, "@PageSize", pageSize);
453                                 AddParameter (command, "@UserNameToMatch", nameToMatch);
454                                 AddParameter (command, "@ApplicationName", ApplicationName);
455                                 // return value
456                                 AddParameter (command, "@ReturnValue", ParameterDirection.ReturnValue, null);
457
458                                 MembershipUserCollection c = BuildMembershipUserCollection (command, pageIndex, pageSize, out totalRecords);
459
460                                 return c;
461                         }
462                 }
463
464                 public override MembershipUserCollection GetAllUsers (int pageIndex, int pageSize, out int totalRecords)
465                 {
466                         if (pageIndex < 0)
467                                 throw new ArgumentException ("pageIndex must be >= 0");
468                         if (pageSize < 0)
469                                 throw new ArgumentException ("pageSize must be >= 0");
470                         if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
471                                 throw new ArgumentException ("pageIndex and pageSize are too large");
472
473                         using (DbConnection connection = CreateConnection ()) {
474                                 DbCommand command = factory.CreateCommand ();
475                                 command.Connection = connection;
476                                 command.CommandText = @"aspnet_Membership_GetAllUsers";
477                                 command.CommandType = CommandType.StoredProcedure;
478
479                                 AddParameter (command, "@ApplicationName", ApplicationName);
480                                 AddParameter (command, "@PageIndex", pageIndex);
481                                 AddParameter (command, "@PageSize", pageSize);
482                                 // return value
483                                 AddParameter (command, "@ReturnValue", ParameterDirection.ReturnValue, null);
484
485                                 MembershipUserCollection c = BuildMembershipUserCollection (command, pageIndex, pageSize, out totalRecords);
486
487                                 return c;
488                         }
489                 }
490
491                 MembershipUserCollection BuildMembershipUserCollection (DbCommand command, int pageIndex, int pageSize, out int totalRecords)
492                 {
493                         DbDataReader reader = null;
494                         try {
495                                 MembershipUserCollection users = new MembershipUserCollection ();
496                                 reader = command.ExecuteReader ();
497                                 while (reader.Read ())
498                                         users.Add (GetUserFromReader (reader, null, null));
499
500                                 totalRecords = Convert.ToInt32 (command.Parameters ["@ReturnValue"].Value);
501                                 return users;
502                         } catch (Exception) {
503                                 totalRecords = 0;
504                                 return null; /* should we let the exception through? */
505                         }
506                         finally {
507                                 if (reader != null)
508                                         reader.Close ();
509                         }
510                 }
511
512
513                 public override int GetNumberOfUsersOnline ()
514                 {
515                         using (DbConnection connection = CreateConnection ()) {
516                                 DateTime now = DateTime.UtcNow;
517
518                                 DbCommand command = factory.CreateCommand ();
519                                 command.Connection = connection;
520                                 command.CommandText = @"aspnet_Membership_GetNumberOfUsersOnline";
521                                 command.CommandType = CommandType.StoredProcedure;
522
523                                 AddParameter (command, "@CurrentTimeUtc", now.ToString ());
524                                 AddParameter (command, "@ApplicationName", ApplicationName);
525                                 AddParameter (command, "@MinutesSinceLastInActive", userIsOnlineTimeWindow.Minutes);
526                                 DbParameter returnValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
527
528                                 command.ExecuteScalar ();
529                                 return GetReturnValue (returnValue);
530                         }
531                 }
532
533                 public override string GetPassword (string username, string answer)
534                 {
535                         if (!EnablePasswordRetrieval)
536                                 throw new NotSupportedException ("this provider has not been configured to allow the retrieval of passwords");
537
538                         CheckParam ("username", username, 256);
539                         if (RequiresQuestionAndAnswer)
540                                 CheckParam ("answer", answer, 128);
541
542                         PasswordInfo pi = GetPasswordInfo (username);
543                         if (pi == null)
544                                 throw new ProviderException ("An error occurred while retrieving the password from the database");
545
546                         string user_answer = EncodePassword (answer, pi.PasswordFormat, pi.PasswordSalt);
547                         string password = null;
548
549                         using (DbConnection connection = CreateConnection ()) {
550                                 DbCommand command = factory.CreateCommand ();
551                                 command.Connection = connection;
552                                 command.CommandText = @"aspnet_Membership_GetPassword";
553                                 command.CommandType = CommandType.StoredProcedure;
554
555                                 AddParameter (command, "@ApplicationName", ApplicationName);
556                                 AddParameter (command, "@UserName", username);
557                                 AddParameter (command, "@MaxInvalidPasswordAttempts", MaxInvalidPasswordAttempts);
558                                 AddParameter (command, "@PasswordAttemptWindow", PasswordAttemptWindow);
559                                 AddParameter (command, "@CurrentTimeUtc", DateTime.UtcNow);
560                                 AddParameter (command, "@PasswordAnswer", user_answer);
561                                 DbParameter retValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
562
563                                 DbDataReader reader = command.ExecuteReader ();
564
565                                 int returnValue = GetReturnValue (retValue);
566                                 if (returnValue == 3)
567                                         throw new MembershipPasswordException ("Password Answer is invalid");
568                                 if (returnValue == 99)
569                                         throw new MembershipPasswordException ("The user account is currently locked out");
570
571                                 if (reader.Read ()) {
572                                         password = reader.GetString (0);
573                                         reader.Close ();
574                                 }
575
576                                 if (pi.PasswordFormat == MembershipPasswordFormat.Clear)
577                                         return password;
578                                 else if (pi.PasswordFormat == MembershipPasswordFormat.Encrypted)
579                                         return DecodePassword (password, pi.PasswordFormat);
580
581                                 return password;
582                         }
583                 }
584
585                 MembershipUser GetUserFromReader (DbDataReader reader, string username, object userId)
586                 {
587                         int i = 0;
588                         if (username == null)
589                                 i = 1;
590
591                         if (userId != null)
592                                 username = reader.GetString (8);
593
594                         return new MembershipUser (this.Name, /* XXX is this right?  */
595                                 (username == null ? reader.GetString (0) : username), /* name */
596                                 (userId == null ? reader.GetGuid (8 + i) : userId), /* providerUserKey */
597                                 reader.IsDBNull (0 + i) ? null : reader.GetString (0 + i), /* email */
598                                 reader.IsDBNull (1 + i) ? null : reader.GetString (1 + i), /* passwordQuestion */
599                                 reader.IsDBNull (2 + i) ? null : reader.GetString (2 + i), /* comment */
600                                 reader.GetBoolean (3 + i), /* isApproved */
601                                 reader.GetBoolean (9 + i), /* isLockedOut */
602                                 reader.GetDateTime (4 + i).ToLocalTime (), /* creationDate */
603                                 reader.GetDateTime (5 + i).ToLocalTime (), /* lastLoginDate */
604                                 reader.GetDateTime (6 + i).ToLocalTime (), /* lastActivityDate */
605                                 reader.GetDateTime (7 + i).ToLocalTime (), /* lastPasswordChangedDate */
606                                 reader.GetDateTime (10 + i).ToLocalTime () /* lastLockoutDate */);
607                 }
608
609                 MembershipUser BuildMembershipUser (DbCommand query, string username, object userId)
610                 {
611                         try {
612                                 using (DbConnection connection = CreateConnection ()) {
613                                         query.Connection = connection;
614                                         using (DbDataReader reader = query.ExecuteReader ()) {
615                                                 if (!reader.Read ())
616                                                         return null;
617
618                                                 return GetUserFromReader (reader, username, userId);
619                                         }
620                                 }
621                         } catch (Exception) {
622                                 return null; /* should we let the exception through? */
623                         }
624                         finally {
625                                 query.Connection = null;
626                         }
627                 }
628
629                 public override MembershipUser GetUser (string username, bool userIsOnline)
630                 {
631                         if (username == null)
632                                 throw new ArgumentNullException ("username");
633
634                         if (username.Length == 0)
635                                 return null;
636
637                         CheckParam ("username", username, 256);
638
639                         DbCommand command = factory.CreateCommand ();
640
641                         command.CommandText = @"aspnet_Membership_GetUserByName";
642                         command.CommandType = CommandType.StoredProcedure;
643
644                         AddParameter (command, "@UserName", username);
645                         AddParameter (command, "@ApplicationName", ApplicationName);
646                         AddParameter (command, "@CurrentTimeUtc", DateTime.Now);
647                         AddParameter (command, "@UpdateLastActivity", userIsOnline);
648
649                         MembershipUser u = BuildMembershipUser (command, username, null);
650
651                         return u;
652                 }
653
654                 public override MembershipUser GetUser (object providerUserKey, bool userIsOnline)
655                 {
656                         DbCommand command = factory.CreateCommand ();
657                         command.CommandText = @"aspnet_Membership_GetUserByUserId";
658                         command.CommandType = CommandType.StoredProcedure;
659
660                         AddParameter (command, "@UserId", providerUserKey);
661                         AddParameter (command, "@CurrentTimeUtc", DateTime.Now);
662                         AddParameter (command, "@UpdateLastActivity", userIsOnline);
663
664                         MembershipUser u = BuildMembershipUser (command, string.Empty, providerUserKey);
665                         return u;
666                 }
667
668                 public override string GetUserNameByEmail (string email)
669                 {
670                         CheckParam ("email", email, 256);
671
672                         using (DbConnection connection = CreateConnection ()) {
673
674                                 DbCommand command = factory.CreateCommand ();
675                                 command.Connection = connection;
676                                 command.CommandText = @"aspnet_Membership_GetUserByEmail";
677                                 command.CommandType = CommandType.StoredProcedure;
678
679                                 AddParameter (command, "@ApplicationName", ApplicationName);
680                                 AddParameter (command, "@Email", email);
681
682                                 DbDataReader reader = command.ExecuteReader ();
683                                 string rv = null;
684                                 if (reader.Read ())
685                                         rv = reader.GetString (0);
686                                 reader.Close ();
687                                 return rv;
688                         }
689                 }
690
691                 bool GetBoolConfigValue (NameValueCollection config, string name, bool def)
692                 {
693                         bool rv = def;
694                         string val = config [name];
695                         if (val != null) {
696                                 try { rv = Boolean.Parse (val); }
697                                 catch (Exception e) {
698                                         throw new ProviderException (String.Format ("{0} must be true or false", name), e);
699                                 }
700                         }
701                         return rv;
702                 }
703
704                 int GetIntConfigValue (NameValueCollection config, string name, int def)
705                 {
706                         int rv = def;
707                         string val = config [name];
708                         if (val != null) {
709                                 try { rv = Int32.Parse (val); }
710                                 catch (Exception e) {
711                                         throw new ProviderException (String.Format ("{0} must be an integer", name), e);
712                                 }
713                         }
714                         return rv;
715                 }
716
717                 int GetEnumConfigValue (NameValueCollection config, string name, Type enumType, int def)
718                 {
719                         int rv = def;
720                         string val = config [name];
721                         if (val != null) {
722                                 try { rv = (int) Enum.Parse (enumType, val); }
723                                 catch (Exception e) {
724                                         throw new ProviderException (String.Format ("{0} must be one of the following values: {1}", name, String.Join (",", Enum.GetNames (enumType))), e);
725                                 }
726                         }
727                         return rv;
728                 }
729
730                 string GetStringConfigValue (NameValueCollection config, string name, string def)
731                 {
732                         string rv = def;
733                         string val = config [name];
734                         if (val != null)
735                                 rv = val;
736                         return rv;
737                 }
738
739                 void EmitValidatingPassword (string username, string password, bool isNewUser)
740                 {
741                         ValidatePasswordEventArgs args = new ValidatePasswordEventArgs (username, password, isNewUser);
742                         OnValidatingPassword (args);
743
744                         /* if we're canceled.. */
745                         if (args.Cancel) {
746                                 if (args.FailureInformation == null)
747                                         throw new ProviderException ("Password validation canceled");
748                                 else
749                                         throw args.FailureInformation;
750                         }
751                 }
752
753                 public override void Initialize (string name, NameValueCollection config)
754                 {
755                         if (config == null)
756                                 throw new ArgumentNullException ("config");
757
758                         base.Initialize (name, config);
759
760                         applicationName = GetStringConfigValue (config, "applicationName", "/");
761                         enablePasswordReset = GetBoolConfigValue (config, "enablePasswordReset", true);
762                         enablePasswordRetrieval = GetBoolConfigValue (config, "enablePasswordRetrieval", false);
763                         requiresQuestionAndAnswer = GetBoolConfigValue (config, "requiresQuestionAndAnswer", true);
764                         requiresUniqueEmail = GetBoolConfigValue (config, "requiresUniqueEmail", false);
765                         passwordFormat = (MembershipPasswordFormat) GetEnumConfigValue (config, "passwordFormat", typeof (MembershipPasswordFormat),
766                                                                                            (int) MembershipPasswordFormat.Hashed);
767                         maxInvalidPasswordAttempts = GetIntConfigValue (config, "maxInvalidPasswordAttempts", 5);
768                         minRequiredPasswordLength = GetIntConfigValue (config, "minRequiredPasswordLength", 7);
769                         minRequiredNonAlphanumericCharacters = GetIntConfigValue (config, "minRequiredNonalphanumericCharacters", 1);
770                         passwordAttemptWindow = GetIntConfigValue (config, "passwordAttemptWindow", 10);
771                         passwordStrengthRegularExpression = GetStringConfigValue (config, "passwordStrengthRegularExpression", "");
772
773                         MembershipSection section = (MembershipSection) WebConfigurationManager.GetSection ("system.web/membership");
774
775                         userIsOnlineTimeWindow = section.UserIsOnlineTimeWindow;
776
777                         /* we can't support password retrieval with hashed passwords */
778                         if (passwordFormat == MembershipPasswordFormat.Hashed && enablePasswordRetrieval)
779                                 throw new ProviderException ("password retrieval cannot be used with hashed passwords");
780
781                         string connectionStringName = config ["connectionStringName"];
782
783                         if (applicationName.Length > 256)
784                                 throw new ProviderException ("The ApplicationName attribute must be 256 characters long or less.");
785                         if (connectionStringName == null || connectionStringName.Length == 0)
786                                 throw new ProviderException ("The ConnectionStringName attribute must be present and non-zero length.");
787
788                         connectionString = WebConfigurationManager.ConnectionStrings [connectionStringName];
789                         factory = connectionString == null || String.IsNullOrEmpty (connectionString.ProviderName) ?
790                                 System.Data.SqlClient.SqlClientFactory.Instance :
791                                 ProvidersHelper.GetDbProviderFactory (connectionString.ProviderName);
792                 }
793
794                 public override string ResetPassword (string username, string answer)
795                 {
796                         if (!EnablePasswordReset)
797                                 throw new NotSupportedException ("this provider has not been configured to allow the resetting of passwords");
798
799                         CheckParam ("username", username, 256);
800
801                         if (RequiresQuestionAndAnswer)
802                                 CheckParam ("answer", answer, 128);
803
804                         using (DbConnection connection = CreateConnection ()) {
805
806                                 PasswordInfo pi = GetPasswordInfo (username);
807                                 if (pi == null)
808                                         throw new ProviderException (username + "is not found in the membership database");
809
810                                 string newPassword = GeneratePassword ();
811                                 EmitValidatingPassword (username, newPassword, false);
812
813                                 string db_password = EncodePassword (newPassword, pi.PasswordFormat, pi.PasswordSalt);
814                                 string db_answer = EncodePassword (answer, pi.PasswordFormat, pi.PasswordSalt);
815
816                                 DbCommand command = factory.CreateCommand ();
817                                 command.Connection = connection;
818                                 command.CommandText = @"aspnet_Membership_ResetPassword";
819                                 command.CommandType = CommandType.StoredProcedure;
820
821                                 AddParameter (command, "@ApplicationName", ApplicationName);
822                                 AddParameter (command, "@UserName", username);
823                                 AddParameter (command, "@NewPassword", db_password);
824                                 AddParameter (command, "@MaxInvalidPasswordAttempts", MaxInvalidPasswordAttempts);
825                                 AddParameter (command, "@PasswordAttemptWindow", PasswordAttemptWindow);
826                                 AddParameter (command, "@PasswordSalt", pi.PasswordSalt);
827                                 AddParameter (command, "@CurrentTimeUtc", DateTime.UtcNow);
828                                 AddParameter (command, "@PasswordFormat", (int) pi.PasswordFormat);
829                                 AddParameter (command, "@PasswordAnswer", db_answer);
830                                 DbParameter retValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
831
832                                 command.ExecuteNonQuery ();
833
834                                 int returnValue = GetReturnValue (retValue);
835
836                                 if (returnValue == 0)
837                                         return newPassword;
838                                 else if (returnValue == 3)
839                                         throw new MembershipPasswordException ("Password Answer is invalid");
840                                 else if (returnValue == 99)
841                                         throw new MembershipPasswordException ("The user account is currently locked out");
842                                 else
843                                         throw new ProviderException ("Failed to reset password");
844                         }
845                 }
846
847                 public override void UpdateUser (MembershipUser user)
848                 {
849                         if (user == null)
850                                 throw new ArgumentNullException ("user");
851
852                         if (user.UserName == null)
853                                 throw new ArgumentNullException ("user.UserName");
854
855                         if (RequiresUniqueEmail && user.Email == null)
856                                 throw new ArgumentNullException ("user.Email");
857
858                         CheckParam ("user.UserName", user.UserName, 256);
859
860                         if (user.Email.Length > 256 || (RequiresUniqueEmail && user.Email.Length == 0))
861                                 throw new ArgumentException ("invalid format for user.Email");
862
863                         using (DbConnection connection = CreateConnection ()) {
864                                 int returnValue = 0;
865
866                                 DbCommand command = factory.CreateCommand ();
867                                 command.Connection = connection;
868                                 command.CommandText = @"aspnet_Membership_UpdateUser";
869                                 command.CommandType = CommandType.StoredProcedure;
870
871                                 AddParameter (command, "@ApplicationName", ApplicationName);
872                                 AddParameter (command, "@UserName", user.UserName);
873                                 AddParameter (command, "@Email", user.Email == null ? (object) DBNull.Value : (object) user.Email);
874                                 AddParameter (command, "@Comment", user.Comment == null ? (object) DBNull.Value : (object) user.Comment);
875                                 AddParameter (command, "@IsApproved", user.IsApproved);
876                                 AddParameter (command, "@LastLoginDate", DateTime.UtcNow);
877                                 AddParameter (command, "@LastActivityDate", DateTime.UtcNow);
878                                 AddParameter (command, "@UniqueEmail", RequiresUniqueEmail);
879                                 AddParameter (command, "@CurrentTimeUtc", DateTime.UtcNow);
880                                 DbParameter retValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
881
882                                 command.ExecuteNonQuery ();
883
884                                 returnValue = GetReturnValue (retValue);
885
886                                 if (returnValue == 1)
887                                         throw new ProviderException ("The UserName property of user was not found in the database.");
888                                 if (returnValue == 7)
889                                         throw new ProviderException ("The Email property of user was equal to an existing e-mail address in the database and RequiresUniqueEmail is set to true.");
890                                 if (returnValue != 0)
891                                         throw new ProviderException ("Failed to update user");
892                         }
893                 }
894
895                 public override bool ValidateUser (string username, string password)
896                 {
897                         if (username.Length == 0)
898                                 return false;
899
900                         CheckParam ("username", username, 256);
901                         EmitValidatingPassword (username, password, false);
902
903                         PasswordInfo pi = ValidateUsingPassword (username, password);
904                         if (pi != null) {
905                                 pi.LastLoginDate = DateTime.UtcNow;
906                                 UpdateUserInfo (username, pi, true, true);
907                                 return true;
908                         }
909                         return false;
910                 }
911
912
913                 public override bool UnlockUser (string username)
914                 {
915                         CheckParam ("username", username, 256);
916
917                         using (DbConnection connection = CreateConnection ()) {
918                                 try {
919                                         DbCommand command = factory.CreateCommand ();
920                                         command.Connection = connection;
921                                         command.CommandText = @"aspnet_Membership_UnlockUser"; ;
922                                         command.CommandType = CommandType.StoredProcedure;
923
924                                         AddParameter (command, "@ApplicationName", ApplicationName);
925                                         AddParameter (command, "@UserName", username);
926                                         DbParameter returnValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
927
928                                         command.ExecuteNonQuery ();
929                                         if (GetReturnValue (returnValue) != 0)
930                                                 return false;
931                                 }
932                                 catch (Exception e) {
933                                         throw new ProviderException ("Failed to unlock user", e);
934                                 }
935                         }
936                         return true;
937                 }
938
939                 void UpdateUserInfo (string username, PasswordInfo pi, bool isPasswordCorrect, bool updateLoginActivity)
940                 {
941                         CheckParam ("username", username, 256);
942
943                         using (DbConnection connection = CreateConnection ()) {
944                                 try {
945                                         DbCommand command = factory.CreateCommand ();
946                                         command.Connection = connection;
947                                         command.CommandText = @"aspnet_Membership_UpdateUserInfo"; ;
948                                         command.CommandType = CommandType.StoredProcedure;
949
950                                         AddParameter (command, "@ApplicationName", ApplicationName);
951                                         AddParameter (command, "@UserName", username);
952                                         AddParameter (command, "@IsPasswordCorrect", isPasswordCorrect);
953                                         AddParameter (command, "@UpdateLastLoginActivityDate", updateLoginActivity);
954                                         AddParameter (command, "@MaxInvalidPasswordAttempts", MaxInvalidPasswordAttempts);
955                                         AddParameter (command, "@PasswordAttemptWindow", PasswordAttemptWindow);
956                                         AddParameter (command, "@CurrentTimeUtc", DateTime.UtcNow);
957                                         AddParameter (command, "@LastLoginDate", pi.LastLoginDate);
958                                         AddParameter (command, "@LastActivityDate", pi.LastActivityDate);
959                                         DbParameter retValue = AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
960
961                                         command.ExecuteNonQuery ();
962
963                                         int returnValue = GetReturnValue (retValue);
964                                         if (returnValue != 0)
965                                                 return;
966                                 }
967                                 catch (Exception e) {
968                                         throw new ProviderException ("Failed to update Membership table", e);
969                                 }
970
971                         }
972                 }
973
974                 PasswordInfo ValidateUsingPassword (string username, string password)
975                 {
976                         MembershipUser user = GetUser (username, true);
977                         if (user == null)
978                                 return null;
979
980                         if (!user.IsApproved || user.IsLockedOut)
981                                 return null;
982
983                         PasswordInfo pi = GetPasswordInfo (username);
984
985                         if (pi == null)
986                                 return null;
987
988                         /* do the actual validation */
989                         string user_password = EncodePassword (password, pi.PasswordFormat, pi.PasswordSalt);
990
991                         if (user_password != pi.Password) {
992                                 UpdateUserInfo (username, pi, false, false);
993                                 return null;
994                         }
995
996                         return pi;
997                 }
998
999                 private PasswordInfo GetPasswordInfo (string username)
1000                 {
1001                         using (DbConnection connection = CreateConnection ()) {
1002                                 DbCommand command = factory.CreateCommand ();
1003                                 command.Connection = connection;
1004                                 command.CommandType = CommandType.StoredProcedure;
1005                                 command.CommandText = @"aspnet_Membership_GetPasswordWithFormat";
1006
1007                                 AddParameter (command, "@ApplicationName", ApplicationName);
1008                                 AddParameter (command, "@UserName", username);
1009                                 AddParameter (command, "@UpdateLastLoginActivityDate", false);
1010                                 AddParameter (command, "@CurrentTimeUtc", DateTime.Now);
1011                                 // return value
1012                                 AddParameter (command, "@ReturnVal", ParameterDirection.ReturnValue, DbType.Int32, null);
1013
1014                                 DbDataReader reader = command.ExecuteReader ();
1015                                 if (!reader.Read ())
1016                                         return null;
1017
1018                                 PasswordInfo pi = new PasswordInfo (
1019                                         reader.GetString (0),
1020                                         (MembershipPasswordFormat) reader.GetInt32 (1),
1021                                         reader.GetString (2),
1022                                         reader.GetInt32 (3),
1023                                         reader.GetInt32 (4),
1024                                         reader.GetBoolean (5),
1025                                         reader.GetDateTime (6),
1026                                         reader.GetDateTime (7));
1027
1028                                 return pi;
1029                         }
1030                 }
1031
1032                 private string EncodePassword (string password, MembershipPasswordFormat passwordFormat, string salt)
1033                 {
1034                         byte [] password_bytes;
1035                         byte [] salt_bytes;
1036
1037                         switch (passwordFormat) {
1038                                 case MembershipPasswordFormat.Clear:
1039                                         return password;
1040                                 case MembershipPasswordFormat.Hashed:
1041                                         password_bytes = Encoding.Unicode.GetBytes (password);
1042                                         salt_bytes = Convert.FromBase64String (salt);
1043
1044                                         byte [] hashBytes = new byte [salt_bytes.Length + password_bytes.Length];
1045
1046                                         Buffer.BlockCopy (salt_bytes, 0, hashBytes, 0, salt_bytes.Length);
1047                                         Buffer.BlockCopy (password_bytes, 0, hashBytes, salt_bytes.Length, password_bytes.Length);
1048
1049                                         MembershipSection section = (MembershipSection) WebConfigurationManager.GetSection ("system.web/membership");
1050                                         string alg_type = section.HashAlgorithmType;
1051                                         if (alg_type == "") {
1052                                                 MachineKeySection keysection = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey");
1053                                                 alg_type = keysection.Validation.ToString ();
1054                                         }
1055                                         using (HashAlgorithm hash = HashAlgorithm.Create (alg_type)) {
1056                                                 hash.TransformFinalBlock (hashBytes, 0, hashBytes.Length);
1057                                                 return Convert.ToBase64String (hash.Hash);
1058                                         }
1059                                 case MembershipPasswordFormat.Encrypted:
1060                                         password_bytes = Encoding.Unicode.GetBytes (password);
1061                                         salt_bytes = Convert.FromBase64String (salt);
1062
1063                                         byte [] buf = new byte [password_bytes.Length + salt_bytes.Length];
1064
1065                                         Array.Copy (salt_bytes, 0, buf, 0, salt_bytes.Length);
1066                                         Array.Copy (password_bytes, 0, buf, salt_bytes.Length, password_bytes.Length);
1067
1068                                         return Convert.ToBase64String (EncryptPassword (buf));
1069                                 default:
1070                                         /* not reached.. */
1071                                         return null;
1072                         }
1073                 }
1074
1075                 private string DecodePassword (string password, MembershipPasswordFormat passwordFormat)
1076                 {
1077                         switch (passwordFormat) {
1078                                 case MembershipPasswordFormat.Clear:
1079                                         return password;
1080                                 case MembershipPasswordFormat.Hashed:
1081                                         throw new ProviderException ("Hashed passwords cannot be decoded.");
1082                                 case MembershipPasswordFormat.Encrypted:
1083                                         return Encoding.Unicode.GetString (DecryptPassword (Convert.FromBase64String (password)));
1084                                 default:
1085                                         /* not reached.. */
1086                                         return null;
1087                         }
1088                 }
1089
1090                 public override string ApplicationName
1091                 {
1092                         get { return applicationName; }
1093                         set { applicationName = value; }
1094                 }
1095
1096                 public override bool EnablePasswordReset
1097                 {
1098                         get { return enablePasswordReset; }
1099                 }
1100
1101                 public override bool EnablePasswordRetrieval
1102                 {
1103                         get { return enablePasswordRetrieval; }
1104                 }
1105
1106                 public override MembershipPasswordFormat PasswordFormat
1107                 {
1108                         get { return passwordFormat; }
1109                 }
1110
1111                 public override bool RequiresQuestionAndAnswer
1112                 {
1113                         get { return requiresQuestionAndAnswer; }
1114                 }
1115
1116                 public override bool RequiresUniqueEmail
1117                 {
1118                         get { return requiresUniqueEmail; }
1119                 }
1120
1121                 public override int MaxInvalidPasswordAttempts
1122                 {
1123                         get { return maxInvalidPasswordAttempts; }
1124                 }
1125
1126                 public override int MinRequiredNonAlphanumericCharacters
1127                 {
1128                         get { return minRequiredNonAlphanumericCharacters; }
1129                 }
1130
1131                 public override int MinRequiredPasswordLength
1132                 {
1133                         get { return minRequiredPasswordLength; }
1134                 }
1135
1136                 public override int PasswordAttemptWindow
1137                 {
1138                         get { return passwordAttemptWindow; }
1139                 }
1140
1141                 public override string PasswordStrengthRegularExpression
1142                 {
1143                         get { return passwordStrengthRegularExpression; }
1144                 }
1145
1146                 [Flags]
1147                 private enum DeleteUserTableMask
1148                 {
1149                         MembershipUsers = 1,
1150                         UsersInRoles = 2,
1151                         Profiles = 4,
1152                         WebPartStateUser = 8
1153                 }
1154
1155                 private sealed class PasswordInfo
1156                 {
1157                         private string _password;
1158                         private MembershipPasswordFormat _passwordFormat;
1159                         private string _passwordSalt;
1160                         private int _failedPasswordAttemptCount;
1161                         private int _failedPasswordAnswerAttemptCount;
1162                         private bool _isApproved;
1163                         private DateTime _lastLoginDate;
1164                         private DateTime _lastActivityDate;
1165
1166                         internal PasswordInfo (
1167                                 string password,
1168                                 MembershipPasswordFormat passwordFormat,
1169                                 string passwordSalt,
1170                                 int failedPasswordAttemptCount,
1171                                 int failedPasswordAnswerAttemptCount,
1172                                 bool isApproved,
1173                                 DateTime lastLoginDate,
1174                                 DateTime lastActivityDate)
1175                         {
1176                                 _password = password;
1177                                 _passwordFormat = passwordFormat;
1178                                 _passwordSalt = passwordSalt;
1179                                 _failedPasswordAttemptCount = failedPasswordAttemptCount;
1180                                 _failedPasswordAnswerAttemptCount = failedPasswordAnswerAttemptCount;
1181                                 _isApproved = isApproved;
1182                                 _lastLoginDate = lastLoginDate;
1183                                 _lastActivityDate = lastActivityDate;
1184                         }
1185
1186                         public string Password
1187                         {
1188                                 get { return _password; }
1189                                 set { _password = value; }
1190                         }
1191                         public MembershipPasswordFormat PasswordFormat
1192                         {
1193                                 get { return _passwordFormat; }
1194                                 set { _passwordFormat = value; }
1195                         }
1196                         public string PasswordSalt
1197                         {
1198                                 get { return _passwordSalt; }
1199                                 set { _passwordSalt = value; }
1200                         }
1201                         public int FailedPasswordAttemptCount
1202                         {
1203                                 get { return _failedPasswordAttemptCount; }
1204                                 set { _failedPasswordAttemptCount = value; }
1205                         }
1206                         public int FailedPasswordAnswerAttemptCount
1207                         {
1208                                 get { return _failedPasswordAnswerAttemptCount; }
1209                                 set { _failedPasswordAnswerAttemptCount = value; }
1210                         }
1211                         public bool IsApproved
1212                         {
1213                                 get { return _isApproved; }
1214                                 set { _isApproved = value; }
1215                         }
1216                         public DateTime LastLoginDate
1217                         {
1218                                 get { return _lastLoginDate; }
1219                                 set { _lastLoginDate = value; }
1220                         }
1221                         public DateTime LastActivityDate
1222                         {
1223                                 get { return _lastActivityDate; }
1224                                 set { _lastActivityDate = value; }
1225                         }
1226                 }
1227         }
1228 }
1229 #endif
1230