PageRenderTime 7ms CodeModel.GetById 2ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Web/System.Web.Security/SqlMembershipProvider.cs

https://github.com/ztfuqingvip/mono
C# | 1241 lines | 984 code | 210 blank | 47 comment | 215 complexity | 59edefce4a82514a9b59d7294793f9ec MD5 | raw file
   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
  33using System.Collections;
  34using System.Collections.Specialized;
  35using System.Configuration;
  36using System.Configuration.Provider;
  37using System.Data;
  38using System.Data.Common;
  39using System.Text;
  40using System.Web.Configuration;
  41using System.Security.Cryptography;
  42
  43namespace 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 [MembershipHelper.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		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		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		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.Length == 0) {
1052						alg_type = MachineKeySection.Config.Validation.ToString ();
1053#if NET_4_0
1054						// support new (4.0) custom algorithms
1055						if (alg_type.StartsWith ("alg:"))
1056							alg_type = alg_type.Substring (4);
1057#endif
1058					}
1059					using (HashAlgorithm hash = HashAlgorithm.Create (alg_type)) {
1060#if NET_4_0
1061						// for compatibility (with 2.0) we'll allow MD5 and SHA1 not to map to HMACMD5 and HMACSHA1
1062						// but that won't work with new (4.0) algorithms, like HMACSHA256|384|512 or custom, won't work without using the key
1063						KeyedHashAlgorithm kha = (hash as KeyedHashAlgorithm);
1064						if (kha != null)
1065							kha.Key = MachineKeySection.Config.GetValidationKey ();
1066#endif
1067						hash.TransformFinalBlock (hashBytes, 0, hashBytes.Length);
1068						return Convert.ToBase64String (hash.Hash);
1069					}
1070				case MembershipPasswordFormat.Encrypted:
1071					password_bytes = Encoding.Unicode.GetBytes (password);
1072					salt_bytes = Convert.FromBase64String (salt);
1073
1074					byte [] buf = new byte [password_bytes.Length + salt_bytes.Length];
1075
1076					Array.Copy (salt_bytes, 0, buf, 0, salt_bytes.Length);
1077					Array.Copy (password_bytes, 0, buf, salt_bytes.Length, password_bytes.Length);
1078
1079					return Convert.ToBase64String (EncryptPassword (buf));
1080				default:
1081					/* not reached.. */
1082					return null;
1083			}
1084		}
1085
1086		string DecodePassword (string password, MembershipPasswordFormat passwordFormat)
1087		{
1088			switch (passwordFormat) {
1089				case MembershipPasswordFormat.Clear:
1090					return password;
1091				case MembershipPasswordFormat.Hashed:
1092					throw new ProviderException ("Hashed passwords cannot be decoded.");
1093				case MembershipPasswordFormat.Encrypted:
1094					return Encoding.Unicode.GetString (DecryptPassword (Convert.FromBase64String (password)));
1095				default:
1096					/* not reached.. */
1097					return null;
1098			}
1099		}
1100
1101		public override string ApplicationName
1102		{
1103			get { return applicationName; }
1104			set { applicationName = value; }
1105		}
1106
1107		public override bool EnablePasswordReset
1108		{
1109			get { return enablePasswordReset; }
1110		}
1111
1112		public override bool EnablePasswordRetrieval
1113		{
1114			get { return enablePasswordRetrieval; }
1115		}
1116
1117		public override MembershipPasswordFormat PasswordFormat
1118		{
1119			get { return passwordFormat; }
1120		}
1121
1122		public override bool RequiresQuestionAndAnswer
1123		{
1124			get { return requiresQuestionAndAnswer; }
1125		}
1126
1127		public override bool RequiresUniqueEmail
1128		{
1129			get { return requiresUniqueEmail; }
1130		}
1131
1132		public override int MaxInvalidPasswordAttempts
1133		{
1134			get { return maxInvalidPasswordAttempts; }
1135		}
1136
1137		public override int MinRequiredNonAlphanumericCharacters
1138		{
1139			get { return minRequiredNonAlphanumericCharacters; }
1140		}
1141
1142		public override int MinRequiredPasswordLength
1143		{
1144			get { return minRequiredPasswordLength; }
1145		}
1146
1147		public override int PasswordAttemptWindow
1148		{
1149			get { return passwordAttemptWindow; }
1150		}
1151
1152		public override string PasswordStrengthRegularExpression
1153		{
1154			get { return passwordStrengthRegularExpression; }
1155		}
1156
1157		[Flags]
1158		enum DeleteUserTableMask
1159		{
1160			MembershipUsers = 1,
1161			UsersInRoles = 2,
1162			Profiles = 4,
1163			WebPartStateUser = 8
1164		}
1165
1166		sealed class PasswordInfo
1167		{
1168			string _password;
1169			MembershipPasswordFormat _passwordFormat;
1170			string _passwordSalt;
1171			int _failedPasswordAttemptCount;
1172			int _failedPasswordAnswerAttemptCount;
1173			bool _isApproved;
1174			DateTime _lastLoginDate;
1175			DateTime _lastActivityDate;
1176
1177			internal PasswordInfo (
1178				string password,
1179				MembershipPasswordFormat passwordFormat,
1180				string passwordSalt,
1181				int failedPasswordAttemptCount,
1182				int failedPasswordAnswerAttemptCount,
1183				bool isApproved,
1184				DateTime lastLoginDate,
1185				DateTime lastActivityDate)
1186			{
1187				_password = password;
1188				_passwordFormat = passwordFormat;
1189				_passwordSalt = passwordSalt;
1190				_failedPasswordAttemptCount = failedPasswordAttemptCount;
1191				_failedPasswordAnswerAttemptCount = failedPasswordAnswerAttemptCount;
1192				_isApproved = isApproved;
1193				_lastLoginDate = lastLoginDate;
1194				_lastActivityDate = lastActivityDate;
1195			}
1196
1197			public string Password
1198			{
1199				get { return _password; }
1200				set { _password = value; }
1201			}
1202			public MembershipPasswordFormat PasswordFormat
1203			{
1204				get { return _passwordFormat; }
1205				set { _passwordFormat = value; }
1206			}
1207			public string PasswordSalt
1208			{
1209				get { return _passwordSalt; }
1210				set { _passwordSalt = value; }
1211			}
1212			public int FailedPasswordAttemptCount
1213			{
1214				get { return _failedPasswordAttemptCount; }
1215				set { _failedPasswordAttemptCount = value; }
1216			}
1217			public int FailedPasswordAnswerAttemptCount
1218			{
1219				get { return _failedPasswordAnswerAttemptCount; }
1220				set { _failedPasswordAnswerAttemptCount = value; }
1221			}
1222			public bool IsApproved
1223			{
1224				get { return _isApproved; }
1225				set { _isApproved = value; }
1226			}
1227			public DateTime LastLoginDate
1228			{
1229				get { return _lastLoginDate; }
1230				set { _lastLoginDate = value; }
1231			}
1232			public DateTime LastActivityDate
1233			{
1234				get { return _lastActivityDate; }
1235				set { _lastActivityDate = value; }
1236			}
1237		}
1238	}
1239}
1240#endif
1241