SqliteMembershipProvider.cs 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651
  1. //
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining
  4. // a copy of this software and associated documentation files (the
  5. // "Software"), to deal in the Software without restriction, including
  6. // without limitation the rights to use, copy, modify, merge, publish,
  7. // distribute, sublicense, and/or sell copies of the Software, and to
  8. // permit persons to whom the Software is furnished to do so, subject to
  9. // the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be
  12. // included in all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. //
  22. // Copyright © 2006, 2007 Nauck IT KG http://www.nauck-it.de
  23. //
  24. // Author:
  25. // Daniel Nauck <d.nauck(at)nauck-it.de>
  26. //
  27. // Adapted to Sqlite by Marek Habersack <[email protected]>
  28. //
  29. #if NET_2_0
  30. using System;
  31. using System.Data;
  32. using System.Data.Common;
  33. using System.Collections.Generic;
  34. using System.Collections.Specialized;
  35. using System.Text;
  36. using System.Security.Cryptography;
  37. using System.Web.Hosting;
  38. using System.Web.Configuration;
  39. using System.Web.Security;
  40. using System.Configuration;
  41. using System.Configuration.Provider;
  42. using System.Diagnostics;
  43. using Mono.Data.Sqlite;
  44. namespace System.Web.Security
  45. {
  46. internal class SqliteMembershipProvider : MembershipProvider
  47. {
  48. private const string m_TableName = "Users";
  49. private string m_ConnectionString = string.Empty;
  50. private const int m_NewPasswordLength = 8;
  51. private bool machineKeyIsAutoGenerated;
  52. // Used when determining encryption key values.
  53. private MachineKeySection m_MachineKey = null;
  54. DbParameter AddParameter (DbCommand command, string parameterName, object parameterValue)
  55. {
  56. return AddParameter (command, parameterName, ParameterDirection.Input, parameterValue);
  57. }
  58. DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, object parameterValue)
  59. {
  60. DbParameter dbp = command.CreateParameter ();
  61. dbp.ParameterName = parameterName;
  62. dbp.Value = parameterValue;
  63. dbp.Direction = direction;
  64. command.Parameters.Add (dbp);
  65. return dbp;
  66. }
  67. DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, DbType type, object parameterValue)
  68. {
  69. DbParameter dbp = command.CreateParameter ();
  70. dbp.ParameterName = parameterName;
  71. dbp.Value = parameterValue;
  72. dbp.Direction = direction;
  73. dbp.DbType = type;
  74. command.Parameters.Add (dbp);
  75. return dbp;
  76. }
  77. /// <summary>
  78. /// System.Configuration.Provider.ProviderBase.Initialize Method.
  79. /// </summary>
  80. public override void Initialize(string name, NameValueCollection config)
  81. {
  82. // Initialize values from web.config.
  83. if (config == null)
  84. throw new ArgumentNullException("Config", Properties.Resources.ErrArgumentNull);
  85. if (string.IsNullOrEmpty(name))
  86. name = Properties.Resources.MembershipProviderDefaultName;
  87. if (string.IsNullOrEmpty(config["description"]))
  88. {
  89. config.Remove("description");
  90. config.Add("description", Properties.Resources.MembershipProviderDefaultDescription);
  91. }
  92. // Initialize the abstract base class.
  93. base.Initialize(name, config);
  94. m_ApplicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
  95. m_MaxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
  96. m_PasswordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
  97. m_MinRequiredNonAlphanumericCharacters = Convert.ToInt32(GetConfigValue(config["minRequiredNonAlphanumericCharacters"], "1"));
  98. m_MinRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7"));
  99. m_PasswordStrengthRegularExpression = Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], ""));
  100. m_EnablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
  101. m_EnablePasswordRetrieval = Convert.ToBoolean(GetConfigValue(config["enablePasswordRetrieval"], "true"));
  102. m_RequiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "false"));
  103. m_RequiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "true"));
  104. // Get password encryption type.
  105. string pwFormat = GetConfigValue(config["passwordFormat"], "Hashed");
  106. switch (pwFormat)
  107. {
  108. case "Hashed":
  109. m_PasswordFormat = MembershipPasswordFormat.Hashed;
  110. break;
  111. case "Encrypted":
  112. m_PasswordFormat = MembershipPasswordFormat.Encrypted;
  113. break;
  114. case "Clear":
  115. m_PasswordFormat = MembershipPasswordFormat.Clear;
  116. break;
  117. default:
  118. throw new ProviderException(Properties.Resources.ErrPwFormatNotSupported);
  119. }
  120. // Get connection string.
  121. string connStrName = config["connectionStringName"];
  122. if (string.IsNullOrEmpty(connStrName))
  123. {
  124. throw new ArgumentOutOfRangeException("ConnectionStringName", Properties.Resources.ErrArgumentNullOrEmpty);
  125. }
  126. else
  127. {
  128. ConnectionStringSettings ConnectionStringSettings = ConfigurationManager.ConnectionStrings[connStrName];
  129. if (ConnectionStringSettings == null || string.IsNullOrEmpty(ConnectionStringSettings.ConnectionString.Trim()))
  130. {
  131. throw new ProviderException(Properties.Resources.ErrConnectionStringNullOrEmpty);
  132. }
  133. m_ConnectionString = ConnectionStringSettings.ConnectionString;
  134. }
  135. // Get encryption and decryption key information from the configuration.
  136. System.Configuration.Configuration cfg = WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath);
  137. m_MachineKey = (MachineKeySection)cfg.GetSection("system.web/machineKey");
  138. if (!m_PasswordFormat.Equals(MembershipPasswordFormat.Clear))
  139. {
  140. if (m_MachineKey == null)
  141. throw new ArgumentNullException("system.web/machineKey", Properties.Resources.ErrArgumentNull);
  142. if (m_MachineKey.ValidationKey.Contains("AutoGenerate")) {
  143. machineKeyIsAutoGenerated = true;
  144. if (m_PasswordFormat.Equals (MembershipPasswordFormat.Encrypted))
  145. throw new ProviderException(Properties.Resources.ErrAutoGeneratedKeyNotSupported);
  146. }
  147. }
  148. }
  149. /// <summary>
  150. /// System.Web.Security.MembershipProvider properties.
  151. /// </summary>
  152. #region System.Web.Security.MembershipProvider properties
  153. private string m_ApplicationName = string.Empty;
  154. private bool m_EnablePasswordReset = false;
  155. private bool m_EnablePasswordRetrieval = false;
  156. private bool m_RequiresQuestionAndAnswer = false;
  157. private bool m_RequiresUniqueEmail = false;
  158. private int m_MaxInvalidPasswordAttempts = 0;
  159. private int m_PasswordAttemptWindow = 0;
  160. private MembershipPasswordFormat m_PasswordFormat = MembershipPasswordFormat.Clear;
  161. private int m_MinRequiredNonAlphanumericCharacters = 0;
  162. private int m_MinRequiredPasswordLength = 0;
  163. private string m_PasswordStrengthRegularExpression = string.Empty;
  164. public override string ApplicationName
  165. {
  166. get { return m_ApplicationName; }
  167. set { m_ApplicationName = value; }
  168. }
  169. public override bool EnablePasswordReset
  170. {
  171. get { return m_EnablePasswordReset; }
  172. }
  173. public override bool EnablePasswordRetrieval
  174. {
  175. get { return m_EnablePasswordRetrieval; }
  176. }
  177. public override bool RequiresQuestionAndAnswer
  178. {
  179. get { return m_RequiresQuestionAndAnswer; }
  180. }
  181. public override bool RequiresUniqueEmail
  182. {
  183. get { return m_RequiresUniqueEmail; }
  184. }
  185. public override int MaxInvalidPasswordAttempts
  186. {
  187. get { return m_MaxInvalidPasswordAttempts; }
  188. }
  189. public override int PasswordAttemptWindow
  190. {
  191. get { return m_PasswordAttemptWindow; }
  192. }
  193. public override MembershipPasswordFormat PasswordFormat
  194. {
  195. get { return m_PasswordFormat; }
  196. }
  197. public override int MinRequiredNonAlphanumericCharacters
  198. {
  199. get { return m_MinRequiredNonAlphanumericCharacters; }
  200. }
  201. public override int MinRequiredPasswordLength
  202. {
  203. get { return m_MinRequiredPasswordLength; }
  204. }
  205. public override string PasswordStrengthRegularExpression
  206. {
  207. get { return m_PasswordStrengthRegularExpression; }
  208. }
  209. #endregion
  210. /// <summary>
  211. /// System.Web.Security.MembershipProvider methods.
  212. /// </summary>
  213. #region System.Web.Security.MembershipProvider methods
  214. /// <summary>
  215. /// MembershipProvider.ChangePassword
  216. /// </summary>
  217. public override bool ChangePassword(string username, string oldPassword, string newPassword)
  218. {
  219. if (!ValidateUser(username, oldPassword))
  220. return false;
  221. ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true);
  222. OnValidatingPassword(args);
  223. if (args.Cancel)
  224. {
  225. if (args.FailureInformation != null)
  226. throw args.FailureInformation;
  227. else
  228. throw new MembershipPasswordException(Properties.Resources.ErrPasswordChangeCanceled);
  229. }
  230. int rowsAffected = 0;
  231. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  232. {
  233. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  234. {
  235. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"Password\" = @Password, \"LastPasswordChangedDate\" = @LastPasswordChangedDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  236. AddParameter (dbCommand,"@Password", EncodePassword(newPassword));
  237. AddParameter (dbCommand,"@LastPasswordChangedDate", DateTime.Now);
  238. AddParameter (dbCommand,"@Username", username);
  239. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  240. try
  241. {
  242. dbConn.Open();
  243. dbCommand.Prepare();
  244. rowsAffected = dbCommand.ExecuteNonQuery();
  245. }
  246. catch (SqliteException e)
  247. {
  248. Trace.WriteLine(e.ToString());
  249. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  250. }
  251. finally
  252. {
  253. if (dbConn != null)
  254. dbConn.Close();
  255. }
  256. }
  257. }
  258. if (rowsAffected > 0)
  259. return true;
  260. else
  261. return false;
  262. }
  263. /// <summary>
  264. /// MembershipProvider.ChangePasswordQuestionAndAnswer
  265. /// </summary>
  266. public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
  267. {
  268. if (!ValidateUser(username, password))
  269. return false;
  270. int rowsAffected = 0;
  271. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  272. {
  273. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  274. {
  275. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"PasswordQuestion\" = @PasswordQuestion, \"PasswordAnswer\" = @PasswordAnswer WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  276. AddParameter (dbCommand,"@PasswordQuestion", newPasswordQuestion);
  277. AddParameter (dbCommand,"@PasswordAnswer", EncodePassword(newPasswordAnswer));
  278. AddParameter (dbCommand,"@Username", username);
  279. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  280. try
  281. {
  282. dbConn.Open();
  283. dbCommand.Prepare();
  284. rowsAffected = dbCommand.ExecuteNonQuery();
  285. }
  286. catch (SqliteException e)
  287. {
  288. Trace.WriteLine(e.ToString());
  289. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  290. }
  291. finally
  292. {
  293. if (dbConn != null)
  294. dbConn.Close();
  295. }
  296. }
  297. }
  298. if (rowsAffected > 0)
  299. return true;
  300. else
  301. return false;
  302. }
  303. /// <summary>
  304. /// MembershipProvider.CreateUser
  305. /// </summary>
  306. public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved,
  307. object providerUserKey, out MembershipCreateStatus status)
  308. {
  309. ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, password, true);
  310. OnValidatingPassword(args);
  311. if (args.Cancel)
  312. {
  313. status = MembershipCreateStatus.InvalidPassword;
  314. return null;
  315. }
  316. if (RequiresUniqueEmail && string.IsNullOrEmpty(email))
  317. {
  318. status = MembershipCreateStatus.InvalidEmail;
  319. return null;
  320. }
  321. if (RequiresUniqueEmail && !string.IsNullOrEmpty(GetUserNameByEmail(email)))
  322. {
  323. status = MembershipCreateStatus.DuplicateEmail;
  324. return null;
  325. }
  326. if (GetUser(username, false) == null)
  327. {
  328. DateTime createDate = DateTime.Now;
  329. if (providerUserKey == null)
  330. {
  331. providerUserKey = Guid.NewGuid();
  332. }
  333. else
  334. {
  335. if (!(providerUserKey is Guid))
  336. {
  337. status = MembershipCreateStatus.InvalidProviderUserKey;
  338. return null;
  339. }
  340. }
  341. // Create user in database
  342. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  343. {
  344. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  345. {
  346. dbCommand.CommandText = string.Format("INSERT INTO \"{0}\" (\"pId\", \"Username\", \"Password\", \"Email\", \"PasswordQuestion\", \"PasswordAnswer\", \"IsApproved\", \"CreationDate\", \"LastPasswordChangedDate\", \"LastActivityDate\", \"ApplicationName\", \"IsLockedOut\", \"LastLockedOutDate\", \"FailedPasswordAttemptCount\", \"FailedPasswordAttemptWindowStart\", \"FailedPasswordAnswerAttemptCount\", \"FailedPasswordAnswerAttemptWindowStart\") Values (@pId, @Username, @Password, @Email, @PasswordQuestion, @PasswordAnswer, @IsApproved, @CreationDate, @LastPasswordChangedDate, @LastActivityDate, @ApplicationName, @IsLockedOut, @LastLockedOutDate, @FailedPasswordAttemptCount, @FailedPasswordAttemptWindowStart, @FailedPasswordAnswerAttemptCount, @FailedPasswordAnswerAttemptWindowStart)", m_TableName);
  347. AddParameter (dbCommand,"@pId", providerUserKey);
  348. AddParameter (dbCommand,"@Username", username);
  349. AddParameter (dbCommand,"@Password", EncodePassword(password));
  350. AddParameter (dbCommand,"@Email", email);
  351. AddParameter (dbCommand,"@PasswordQuestion", passwordQuestion);
  352. AddParameter (dbCommand,"@PasswordAnswer", EncodePassword(passwordAnswer));
  353. AddParameter (dbCommand,"@IsApproved", isApproved);
  354. AddParameter (dbCommand,"@CreationDate", createDate);
  355. AddParameter (dbCommand,"@LastPasswordChangedDate", createDate);
  356. AddParameter (dbCommand,"@LastActivityDate", createDate);
  357. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  358. AddParameter (dbCommand,"@IsLockedOut", false);
  359. AddParameter (dbCommand,"@LastLockedOutDate", createDate);
  360. AddParameter (dbCommand,"@FailedPasswordAttemptCount", 0);
  361. AddParameter (dbCommand,"@FailedPasswordAttemptWindowStart", createDate);
  362. AddParameter (dbCommand,"@FailedPasswordAnswerAttemptCount", 0);
  363. AddParameter (dbCommand,"@FailedPasswordAnswerAttemptWindowStart", createDate);
  364. try
  365. {
  366. dbConn.Open();
  367. dbCommand.Prepare();
  368. if (dbCommand.ExecuteNonQuery() > 0)
  369. {
  370. status = MembershipCreateStatus.Success;
  371. }
  372. else
  373. {
  374. status = MembershipCreateStatus.UserRejected;
  375. }
  376. }
  377. catch (SqliteException e)
  378. {
  379. status = MembershipCreateStatus.ProviderError;
  380. Trace.WriteLine(e.ToString());
  381. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  382. }
  383. finally
  384. {
  385. if (dbConn != null)
  386. dbConn.Close();
  387. }
  388. return GetUser(username, false);
  389. }
  390. }
  391. }
  392. else
  393. {
  394. status = MembershipCreateStatus.DuplicateUserName;
  395. }
  396. return null;
  397. }
  398. /// <summary>
  399. /// MembershipProvider.DeleteUser
  400. /// </summary>
  401. public override bool DeleteUser(string username, bool deleteAllRelatedData)
  402. {
  403. int rowsAffected = 0;
  404. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  405. {
  406. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  407. {
  408. dbCommand.CommandText = string.Format("DELETE FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  409. AddParameter (dbCommand,"@Username", username);
  410. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  411. try
  412. {
  413. dbConn.Open();
  414. dbCommand.Prepare();
  415. rowsAffected = dbCommand.ExecuteNonQuery();
  416. if (deleteAllRelatedData)
  417. {
  418. // Process commands to delete all data for the user in the database.
  419. }
  420. }
  421. catch (SqliteException e)
  422. {
  423. Trace.WriteLine(e.ToString());
  424. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  425. }
  426. finally
  427. {
  428. if (dbConn != null)
  429. dbConn.Close();
  430. }
  431. }
  432. }
  433. if (rowsAffected > 0)
  434. return true;
  435. else
  436. return false;
  437. }
  438. /// <summary>
  439. /// MembershipProvider.FindUsersByEmail
  440. /// </summary>
  441. public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
  442. {
  443. totalRecords = 0;
  444. MembershipUserCollection users = new MembershipUserCollection();
  445. // replace permitted wildcard characters
  446. emailToMatch = emailToMatch.Replace('*','%');
  447. emailToMatch = emailToMatch.Replace('?', '_');
  448. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  449. {
  450. // Get user count
  451. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  452. {
  453. dbCommand.CommandText = string.Format("SELECT Count(*) FROM \"{0}\" WHERE \"Email\" LIKE @Email AND \"ApplicationName\" = @ApplicationName", m_TableName);
  454. AddParameter (dbCommand,"@Email", emailToMatch);
  455. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  456. try
  457. {
  458. dbConn.Open();
  459. dbCommand.Prepare();
  460. Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out totalRecords);
  461. if (totalRecords <= 0) { return users; }
  462. }
  463. catch (SqliteException e)
  464. {
  465. Trace.WriteLine(e.ToString());
  466. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  467. }
  468. finally
  469. {
  470. if (dbConn != null)
  471. dbConn.Close();
  472. }
  473. }
  474. // Fetch user from database
  475. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  476. {
  477. dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"Email\" LIKE @Email AND \"ApplicationName\" = @ApplicationName ORDER BY \"Username\" ASC LIMIT @MaxCount OFFSET @StartIndex", m_TableName);
  478. AddParameter (dbCommand,"@Email", emailToMatch);
  479. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  480. AddParameter (dbCommand,"@MaxCount", pageSize);
  481. AddParameter (dbCommand,"@StartIndex", pageSize * pageIndex);
  482. try
  483. {
  484. dbConn.Open();
  485. dbCommand.Prepare();
  486. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  487. {
  488. while (reader.Read())
  489. {
  490. MembershipUser u = GetUserFromReader(reader);
  491. users.Add(u);
  492. }
  493. }
  494. }
  495. catch (SqliteException e)
  496. {
  497. Trace.WriteLine(e.ToString());
  498. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  499. }
  500. finally
  501. {
  502. if (dbConn != null)
  503. dbConn.Close();
  504. }
  505. }
  506. }
  507. return users;
  508. }
  509. /// <summary>
  510. /// MembershipProvider.FindUsersByName
  511. /// </summary>
  512. public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
  513. {
  514. totalRecords = 0;
  515. MembershipUserCollection users = new MembershipUserCollection();
  516. // replace permitted wildcard characters
  517. usernameToMatch = usernameToMatch.Replace('*', '%');
  518. usernameToMatch = usernameToMatch.Replace('?', '_');
  519. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  520. {
  521. // Get user count
  522. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  523. {
  524. dbCommand.CommandText = string.Format("SELECT Count(*) FROM \"{0}\" WHERE \"Username\" LIKE @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  525. AddParameter (dbCommand,"@Username", usernameToMatch);
  526. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  527. try
  528. {
  529. dbConn.Open();
  530. dbCommand.Prepare();
  531. Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out totalRecords);
  532. if (totalRecords <= 0) { return users; }
  533. }
  534. catch (SqliteException e)
  535. {
  536. Trace.WriteLine(e.ToString());
  537. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  538. }
  539. finally
  540. {
  541. if (dbConn != null)
  542. dbConn.Close();
  543. }
  544. }
  545. // Fetch user from database
  546. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  547. {
  548. dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"Username\" LIKE @Username AND \"ApplicationName\" = @ApplicationName ORDER BY \"Username\" ASC LIMIT @MaxCount OFFSET @StartIndex", m_TableName);
  549. AddParameter (dbCommand,"@Username", usernameToMatch);
  550. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  551. AddParameter (dbCommand,"@MaxCount", pageSize);
  552. AddParameter (dbCommand,"@StartIndex", pageSize * pageIndex);
  553. try
  554. {
  555. dbConn.Open();
  556. dbCommand.Prepare();
  557. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  558. {
  559. while (reader.Read())
  560. {
  561. MembershipUser u = GetUserFromReader(reader);
  562. users.Add(u);
  563. }
  564. }
  565. }
  566. catch (SqliteException e)
  567. {
  568. Trace.WriteLine(e.ToString());
  569. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  570. }
  571. finally
  572. {
  573. if (dbConn != null)
  574. dbConn.Close();
  575. }
  576. }
  577. }
  578. return users;
  579. }
  580. /// <summary>
  581. /// MembershipProvider.GetAllUsers
  582. /// </summary>
  583. public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
  584. {
  585. totalRecords = 0;
  586. MembershipUserCollection users = new MembershipUserCollection();
  587. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  588. {
  589. // Get user count
  590. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  591. {
  592. dbCommand.CommandText = string.Format("SELECT Count(*) FROM \"{0}\" WHERE \"ApplicationName\" = @ApplicationName", m_TableName);
  593. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  594. try
  595. {
  596. dbConn.Open();
  597. dbCommand.Prepare();
  598. Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out totalRecords);
  599. if (totalRecords <= 0) { return users; }
  600. }
  601. catch (SqliteException e)
  602. {
  603. Trace.WriteLine(e.ToString());
  604. throw e;
  605. }
  606. finally
  607. {
  608. if (dbConn != null)
  609. dbConn.Close();
  610. }
  611. }
  612. // Fetch user from database
  613. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  614. {
  615. dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"ApplicationName\" = @ApplicationName ORDER BY \"Username\" ASC LIMIT @MaxCount OFFSET @StartIndex", m_TableName);
  616. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  617. AddParameter (dbCommand,"@MaxCount", pageSize);
  618. AddParameter (dbCommand,"@StartIndex", pageSize * pageIndex);
  619. try
  620. {
  621. dbConn.Open();
  622. dbCommand.Prepare();
  623. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  624. {
  625. while (reader.Read())
  626. {
  627. MembershipUser u = GetUserFromReader(reader);
  628. users.Add(u);
  629. }
  630. }
  631. }
  632. catch (SqliteException e)
  633. {
  634. Trace.WriteLine(e.ToString());
  635. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  636. }
  637. finally
  638. {
  639. if (dbConn != null)
  640. dbConn.Close();
  641. }
  642. }
  643. }
  644. return users;
  645. }
  646. /// <summary>
  647. /// MembershipProvider.GetNumberOfUsersOnline
  648. /// </summary>
  649. public override int GetNumberOfUsersOnline()
  650. {
  651. int numOnline = 0;
  652. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  653. {
  654. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  655. {
  656. TimeSpan onlineSpan = new TimeSpan(0, System.Web.Security.Membership.UserIsOnlineTimeWindow, 0);
  657. DateTime compareTime = DateTime.Now.Subtract(onlineSpan);
  658. dbCommand.CommandText = string.Format("SELECT Count(*) FROM \"{0}\" WHERE \"LastActivityDate\" > @CompareTime AND \"ApplicationName\" = @ApplicationName", m_TableName);
  659. AddParameter (dbCommand,"@CompareTime", compareTime);
  660. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  661. try
  662. {
  663. dbConn.Open();
  664. dbCommand.Prepare();
  665. numOnline = (int)dbCommand.ExecuteScalar();
  666. }
  667. catch (SqliteException e)
  668. {
  669. Trace.WriteLine(e.ToString());
  670. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  671. }
  672. finally
  673. {
  674. if (dbConn != null)
  675. dbConn.Close();
  676. }
  677. }
  678. }
  679. return numOnline;
  680. }
  681. /// <summary>
  682. /// MembershipProvider.GetPassword
  683. /// </summary>
  684. public override string GetPassword(string username, string answer)
  685. {
  686. if (!EnablePasswordRetrieval)
  687. {
  688. throw new ProviderException(Properties.Resources.ErrPasswordRetrievalNotEnabled);
  689. }
  690. if (PasswordFormat == MembershipPasswordFormat.Hashed)
  691. {
  692. throw new ProviderException(Properties.Resources.ErrCantRetrieveHashedPw);
  693. }
  694. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  695. {
  696. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  697. {
  698. dbCommand.CommandText = string.Format("SELECT \"Password\", \"PasswordAnswer\", \"IsLockedOut\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  699. AddParameter (dbCommand,"@Username", username);
  700. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  701. try
  702. {
  703. dbConn.Open();
  704. dbCommand.Prepare();
  705. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  706. {
  707. if (reader.HasRows)
  708. {
  709. reader.Read();
  710. string password = reader.GetString(0);
  711. string passwordAnswer = reader.GetString(1);
  712. bool isLockedOut = reader.GetBoolean(2);
  713. reader.Close();
  714. if (isLockedOut)
  715. throw new MembershipPasswordException(Properties.Resources.ErrUserIsLoggedOut);
  716. if (m_RequiresQuestionAndAnswer && !CheckPassword(answer, passwordAnswer))
  717. {
  718. UpdateFailureCount(username, FailureType.PasswordAnswer);
  719. throw new MembershipPasswordException(Properties.Resources.ErrIncorrectPasswordAnswer);
  720. }
  721. if (m_PasswordFormat == MembershipPasswordFormat.Encrypted)
  722. {
  723. password = UnEncodePassword(password);
  724. }
  725. return password;
  726. }
  727. else
  728. {
  729. throw new MembershipPasswordException(Properties.Resources.ErrUserNotFound);
  730. }
  731. }
  732. }
  733. catch (SqliteException e)
  734. {
  735. Trace.WriteLine(e.ToString());
  736. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  737. }
  738. finally
  739. {
  740. if (dbConn != null)
  741. dbConn.Close();
  742. }
  743. }
  744. }
  745. }
  746. /// <summary>
  747. /// MembershipProvider.GetUser
  748. /// </summary>
  749. public override MembershipUser GetUser(string username, bool userIsOnline)
  750. {
  751. MembershipUser u = null;
  752. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  753. {
  754. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  755. {
  756. dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  757. AddParameter (dbCommand,"@Username", username);
  758. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  759. try
  760. {
  761. dbConn.Open();
  762. dbCommand.Prepare();
  763. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  764. {
  765. if (reader.HasRows)
  766. {
  767. reader.Read();
  768. u = GetUserFromReader(reader);
  769. if (userIsOnline)
  770. {
  771. // Update user online status
  772. using (SqliteCommand dbUpdateCommand = dbConn.CreateCommand())
  773. {
  774. dbUpdateCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"LastActivityDate\" = @LastActivityDate WHERE \"pId\" = @pId", m_TableName);
  775. AddParameter (dbUpdateCommand, "@LastActivityDate", DateTime.Now);
  776. AddParameter (dbUpdateCommand, "@pId", u.ProviderUserKey);
  777. dbUpdateCommand.Prepare();
  778. dbUpdateCommand.ExecuteNonQuery();
  779. }
  780. }
  781. }
  782. }
  783. }
  784. catch (SqliteException e)
  785. {
  786. Trace.WriteLine(e.ToString());
  787. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  788. }
  789. finally
  790. {
  791. if (dbConn != null)
  792. dbConn.Close();
  793. }
  794. }
  795. }
  796. return u;
  797. }
  798. /// <summary>
  799. /// MembershipProvider.GetUser
  800. /// </summary>
  801. public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
  802. {
  803. MembershipUser u = null;
  804. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  805. {
  806. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  807. {
  808. dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"pId\" = @pId", m_TableName);
  809. AddParameter (dbCommand,"@pId", providerUserKey);
  810. try
  811. {
  812. dbConn.Open();
  813. dbCommand.Prepare();
  814. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  815. {
  816. if (reader.HasRows)
  817. {
  818. reader.Read();
  819. u = GetUserFromReader(reader);
  820. if (userIsOnline)
  821. {
  822. // Update user online status
  823. using (SqliteCommand dbUpdateCommand = dbConn.CreateCommand())
  824. {
  825. dbUpdateCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"LastActivityDate\" = @LastActivityDate WHERE \"pId\" = @pId", m_TableName);
  826. AddParameter (dbUpdateCommand, "@LastActivityDate", DateTime.Now);
  827. AddParameter (dbUpdateCommand, "@pId", u.ProviderUserKey);
  828. dbUpdateCommand.Prepare();
  829. dbUpdateCommand.ExecuteNonQuery();
  830. }
  831. }
  832. }
  833. }
  834. }
  835. catch (SqliteException e)
  836. {
  837. Trace.WriteLine(e.ToString());
  838. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  839. }
  840. finally
  841. {
  842. if (dbConn != null)
  843. dbConn.Close();
  844. }
  845. }
  846. }
  847. return u;
  848. }
  849. /// <summary>
  850. /// MembershipProvider.GetUserNameByEmail
  851. /// </summary>
  852. public override string GetUserNameByEmail(string email)
  853. {
  854. string username = string.Empty;
  855. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  856. {
  857. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  858. {
  859. dbCommand.CommandText = string.Format("SELECT \"Username\" FROM \"{0}\" WHERE \"Email\" = @Email AND \"ApplicationName\" = @ApplicationName", m_TableName);
  860. AddParameter (dbCommand,"@Email", email);
  861. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  862. try
  863. {
  864. dbConn.Open();
  865. dbCommand.Prepare();
  866. username = (dbCommand.ExecuteScalar() as string) ?? string.Empty;
  867. }
  868. catch (SqliteException e)
  869. {
  870. Trace.WriteLine(e.ToString());
  871. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  872. }
  873. finally
  874. {
  875. if (dbConn != null)
  876. dbConn.Close();
  877. }
  878. }
  879. }
  880. return username;
  881. }
  882. /// <summary>
  883. /// MembershipProvider.ResetPassword
  884. /// </summary>
  885. public override string ResetPassword(string username, string answer)
  886. {
  887. if (!m_EnablePasswordReset)
  888. {
  889. throw new NotSupportedException(Properties.Resources.ErrPasswordResetNotEnabled);
  890. }
  891. if (string.IsNullOrEmpty(answer) && m_RequiresQuestionAndAnswer)
  892. {
  893. UpdateFailureCount(username, FailureType.PasswordAnswer);
  894. throw new ProviderException(Properties.Resources.ErrPasswordAnswerRequired);
  895. }
  896. string newPassword = Membership.GeneratePassword(m_NewPasswordLength, m_MinRequiredNonAlphanumericCharacters);
  897. ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true);
  898. OnValidatingPassword(args);
  899. if (args.Cancel)
  900. {
  901. if (args.FailureInformation != null)
  902. throw args.FailureInformation;
  903. else
  904. throw new MembershipPasswordException(Properties.Resources.ErrPasswordResetCanceled);
  905. }
  906. int rowsAffected = 0;
  907. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  908. {
  909. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  910. {
  911. dbCommand.CommandText = string.Format("SELECT \"PasswordAnswer\", \"IsLockedOut\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  912. AddParameter (dbCommand,"@Username", username);
  913. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  914. try
  915. {
  916. string passwordAnswer = string.Empty;
  917. dbConn.Open();
  918. dbCommand.Prepare();
  919. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  920. {
  921. if (reader.HasRows)
  922. {
  923. reader.Read();
  924. passwordAnswer = reader.GetString(0);
  925. bool isLockedOut = reader.GetBoolean(1);
  926. reader.Close();
  927. if (isLockedOut)
  928. throw new MembershipPasswordException(Properties.Resources.ErrUserIsLoggedOut);
  929. if (m_RequiresQuestionAndAnswer && !CheckPassword(answer, passwordAnswer))
  930. {
  931. UpdateFailureCount(username, FailureType.PasswordAnswer);
  932. throw new MembershipPasswordException(Properties.Resources.ErrIncorrectPasswordAnswer);
  933. }
  934. }
  935. else
  936. {
  937. throw new MembershipPasswordException(Properties.Resources.ErrUserNotFound);
  938. }
  939. }
  940. // Reset Password
  941. using (SqliteCommand dbUpdateCommand = dbConn.CreateCommand())
  942. {
  943. dbUpdateCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"Password\" = @Password, \"LastPasswordChangedDate\" = @LastPasswordChangedDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsLockedOut\" = @IsLockedOut", m_TableName);
  944. AddParameter (dbUpdateCommand, "@Password", EncodePassword(newPassword));
  945. AddParameter (dbUpdateCommand, "@LastPasswordChangedDate", DateTime.Now);
  946. AddParameter (dbUpdateCommand, "@Username", username);
  947. AddParameter (dbUpdateCommand, "@ApplicationName", m_ApplicationName);
  948. AddParameter (dbUpdateCommand, "@IsLockedOut", false);
  949. dbUpdateCommand.Prepare();
  950. rowsAffected = dbUpdateCommand.ExecuteNonQuery();
  951. }
  952. }
  953. catch (SqliteException e)
  954. {
  955. Trace.WriteLine(e.ToString());
  956. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  957. }
  958. finally
  959. {
  960. if (dbConn != null)
  961. dbConn.Close();
  962. }
  963. }
  964. }
  965. if (rowsAffected > 0)
  966. return newPassword;
  967. else
  968. throw new MembershipPasswordException(Properties.Resources.ErrPasswordResetAborted);
  969. }
  970. /// <summary>
  971. /// MembershipProvider.UnlockUser
  972. /// </summary>
  973. public override bool UnlockUser(string userName)
  974. {
  975. int rowsAffected = 0;
  976. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  977. {
  978. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  979. {
  980. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"IsLockedOut\" = @IsLockedOut, \"LastLockedOutDate\" = @LastLockedOutDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  981. AddParameter (dbCommand,"@IsLockedOut", false);
  982. AddParameter (dbCommand,"@LastLockedOutDate", DateTime.Now);
  983. AddParameter (dbCommand,"@Username", userName);
  984. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  985. try
  986. {
  987. dbConn.Open();
  988. dbCommand.Prepare();
  989. rowsAffected = dbCommand.ExecuteNonQuery();
  990. }
  991. catch (SqliteException e)
  992. {
  993. Trace.WriteLine(e.ToString());
  994. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  995. }
  996. finally
  997. {
  998. if (dbConn != null)
  999. dbConn.Close();
  1000. }
  1001. }
  1002. }
  1003. if (rowsAffected > 0)
  1004. return true;
  1005. else
  1006. return false;
  1007. }
  1008. /// <summary>
  1009. /// MembershipProvider.UpdateUser
  1010. /// </summary>
  1011. public override void UpdateUser(MembershipUser user)
  1012. {
  1013. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  1014. {
  1015. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  1016. {
  1017. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"Email\" = @Email, \"Comment\" = @Comment, \"IsApproved\" = @IsApproved WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  1018. AddParameter (dbCommand,"@Email", user.Email);
  1019. AddParameter (dbCommand,"@Comment", user.Comment);
  1020. AddParameter (dbCommand,"@IsApproved", user.IsApproved);
  1021. AddParameter (dbCommand,"@Username", user.UserName);
  1022. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  1023. try
  1024. {
  1025. dbConn.Open();
  1026. dbCommand.Prepare();
  1027. dbCommand.ExecuteNonQuery();
  1028. }
  1029. catch (SqliteException e)
  1030. {
  1031. Trace.WriteLine(e.ToString());
  1032. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  1033. }
  1034. finally
  1035. {
  1036. if (dbConn != null)
  1037. dbConn.Close();
  1038. }
  1039. }
  1040. }
  1041. }
  1042. /// <summary>
  1043. /// MembershipProvider.ValidateUser
  1044. /// </summary>
  1045. public override bool ValidateUser(string username, string password)
  1046. {
  1047. string dbPassword = string.Empty;
  1048. bool dbIsApproved = false;
  1049. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  1050. {
  1051. // Fetch user data from database
  1052. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  1053. {
  1054. dbCommand.CommandText = string.Format("SELECT \"Password\", \"IsApproved\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsLockedOut\" = @IsLockedOut", m_TableName);
  1055. AddParameter (dbCommand,"@Username", username);
  1056. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  1057. AddParameter (dbCommand,"@IsLockedOut", false);
  1058. try
  1059. {
  1060. dbConn.Open();
  1061. dbCommand.Prepare();
  1062. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  1063. {
  1064. if (reader.HasRows)
  1065. {
  1066. reader.Read();
  1067. dbPassword = reader.GetString(0);
  1068. dbIsApproved = reader.GetBoolean(1);
  1069. }
  1070. else
  1071. {
  1072. return false;
  1073. }
  1074. }
  1075. }
  1076. catch (SqliteException e)
  1077. {
  1078. Trace.WriteLine(e.ToString());
  1079. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  1080. }
  1081. finally
  1082. {
  1083. if (dbConn != null)
  1084. dbConn.Close();
  1085. }
  1086. }
  1087. if (CheckPassword(password, dbPassword))
  1088. {
  1089. if (dbIsApproved)
  1090. {
  1091. // Update last login date
  1092. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  1093. {
  1094. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"LastLoginDate\" = @LastLoginDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  1095. AddParameter (dbCommand,"@LastLoginDate", DateTime.Now);
  1096. AddParameter (dbCommand,"@Username", username);
  1097. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  1098. try
  1099. {
  1100. dbConn.Open();
  1101. dbCommand.Prepare();
  1102. dbCommand.ExecuteNonQuery();
  1103. return true;
  1104. }
  1105. catch (SqliteException e)
  1106. {
  1107. Trace.WriteLine(e.ToString());
  1108. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  1109. }
  1110. finally
  1111. {
  1112. if (dbConn != null)
  1113. dbConn.Close();
  1114. }
  1115. }
  1116. }
  1117. }
  1118. return false;
  1119. }
  1120. }
  1121. #endregion
  1122. #region private methods
  1123. /// <summary>
  1124. /// A helper function to retrieve config values from the configuration file.
  1125. /// </summary>
  1126. /// <param name="configValue"></param>
  1127. /// <param name="defaultValue"></param>
  1128. /// <returns></returns>
  1129. private string GetConfigValue(string configValue, string defaultValue)
  1130. {
  1131. if (string.IsNullOrEmpty(configValue))
  1132. return defaultValue;
  1133. return configValue;
  1134. }
  1135. /// <summary>
  1136. /// A helper function that takes the current row from the SqliteDataReader
  1137. /// and hydrates a MembershipUser from the values. Called by the
  1138. /// MembershipUser.GetUser implementation.
  1139. /// </summary>
  1140. /// <param name="reader">SqliteDataReader object</param>
  1141. /// <returns>MembershipUser object</returns>
  1142. private MembershipUser GetUserFromReader(SqliteDataReader reader)
  1143. {
  1144. object providerUserKey = reader.GetValue(0);
  1145. string username = reader.GetString(1);
  1146. string email = string.Empty;
  1147. if (!reader.IsDBNull(2))
  1148. email = reader.GetString(2);
  1149. string passwordQuestion = string.Empty;
  1150. if (!reader.IsDBNull(3))
  1151. passwordQuestion = reader.GetString(3);
  1152. string comment = string.Empty;
  1153. if (!reader.IsDBNull(4))
  1154. comment = reader.GetString(4);
  1155. bool isApproved = reader.GetBoolean(5);
  1156. bool isLockedOut = reader.GetBoolean(6);
  1157. DateTime creationDate = reader.GetDateTime(7);
  1158. DateTime lastLoginDate = new DateTime();
  1159. if (!reader.IsDBNull(8))
  1160. lastLoginDate = reader.GetDateTime(8);
  1161. DateTime lastActivityDate = reader.GetDateTime(9);
  1162. DateTime lastPasswordChangedDate = reader.GetDateTime(10);
  1163. DateTime lastLockedOutDate = new DateTime();
  1164. if (!reader.IsDBNull(11))
  1165. lastLockedOutDate = reader.GetDateTime(11);
  1166. MembershipUser u = new MembershipUser(this.Name,
  1167. username,
  1168. providerUserKey,
  1169. email,
  1170. passwordQuestion,
  1171. comment,
  1172. isApproved,
  1173. isLockedOut,
  1174. creationDate,
  1175. lastLoginDate,
  1176. lastActivityDate,
  1177. lastPasswordChangedDate,
  1178. lastLockedOutDate);
  1179. return u;
  1180. }
  1181. /// <summary>
  1182. /// Compares password values based on the MembershipPasswordFormat.
  1183. /// </summary>
  1184. /// <param name="password"></param>
  1185. /// <param name="dbpassword"></param>
  1186. /// <returns></returns>
  1187. private bool CheckPassword(string password, string dbpassword)
  1188. {
  1189. string pass1 = password;
  1190. string pass2 = dbpassword;
  1191. switch (PasswordFormat)
  1192. {
  1193. case MembershipPasswordFormat.Encrypted:
  1194. pass2 = UnEncodePassword(dbpassword);
  1195. break;
  1196. case MembershipPasswordFormat.Hashed:
  1197. pass1 = EncodePassword(password);
  1198. break;
  1199. default:
  1200. break;
  1201. }
  1202. if (pass1.Equals(pass2))
  1203. return true;
  1204. else
  1205. return false;
  1206. }
  1207. /// <summary>
  1208. /// Encrypts, Hashes, or leaves the password clear based on the PasswordFormat.
  1209. /// </summary>
  1210. /// <param name="password"></param>
  1211. /// <returns></returns>
  1212. private string EncodePassword(string password)
  1213. {
  1214. if (string.IsNullOrEmpty(password))
  1215. return password;
  1216. string encodedPassword = password;
  1217. switch (PasswordFormat)
  1218. {
  1219. case MembershipPasswordFormat.Clear:
  1220. break;
  1221. case MembershipPasswordFormat.Encrypted:
  1222. encodedPassword = Convert.ToBase64String(EncryptPassword(Encoding.Unicode.GetBytes(password)));
  1223. break;
  1224. case MembershipPasswordFormat.Hashed:
  1225. HMACSHA1 hash = new HMACSHA1();
  1226. if (machineKeyIsAutoGenerated)
  1227. hash.Key = MachineKeySectionUtils.ValidationKeyBytes ();
  1228. else
  1229. hash.Key = HexToByte(m_MachineKey.ValidationKey);
  1230. encodedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
  1231. break;
  1232. default:
  1233. throw new ProviderException(Properties.Resources.ErrPwFormatNotSupported);
  1234. }
  1235. return encodedPassword;
  1236. }
  1237. /// <summary>
  1238. /// Decrypts or leaves the password clear based on the PasswordFormat.
  1239. /// </summary>
  1240. /// <param name="encodedPassword"></param>
  1241. /// <returns></returns>
  1242. private string UnEncodePassword(string encodedPassword)
  1243. {
  1244. string password = encodedPassword;
  1245. switch (PasswordFormat)
  1246. {
  1247. case MembershipPasswordFormat.Clear:
  1248. break;
  1249. case MembershipPasswordFormat.Encrypted:
  1250. password = Encoding.Unicode.GetString(DecryptPassword(Convert.FromBase64String(password)));
  1251. break;
  1252. case MembershipPasswordFormat.Hashed:
  1253. throw new ProviderException(Properties.Resources.ErrCantDecodeHashedPw);
  1254. default:
  1255. throw new ProviderException(Properties.Resources.ErrPwFormatNotSupported);
  1256. }
  1257. return password;
  1258. }
  1259. /// <summary>
  1260. /// Converts a hexadecimal string to a byte array. Used to convert encryption
  1261. /// key values from the configuration.
  1262. /// </summary>
  1263. /// <param name="hexString"></param>
  1264. /// <returns></returns>
  1265. private byte[] HexToByte(string hexString)
  1266. {
  1267. byte[] returnBytes = new byte[hexString.Length / 2];
  1268. for (int i = 0; i < returnBytes.Length; i++)
  1269. returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
  1270. return returnBytes;
  1271. }
  1272. /// <summary>
  1273. /// A helper method that performs the checks and updates associated with
  1274. /// password failure tracking.
  1275. /// </summary>
  1276. /// <param name="username"></param>
  1277. /// <param name="failType"></param>
  1278. private void UpdateFailureCount(string username, FailureType failType)
  1279. {
  1280. DateTime windowStart = new DateTime();
  1281. int failureCount = 0;
  1282. using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
  1283. {
  1284. // Fetch user data from database
  1285. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  1286. {
  1287. dbCommand.CommandText = string.Format("SELECT \"FailedPasswordAttemptCount\", \"FailedPasswordAttemptWindowStart\", \"FailedPasswordAnswerAttemptCount\", \"FailedPasswordAnswerAttemptWindowStart\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  1288. AddParameter (dbCommand,"@Username", username);
  1289. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  1290. try
  1291. {
  1292. dbConn.Open();
  1293. dbCommand.Prepare();
  1294. using (SqliteDataReader reader = dbCommand.ExecuteReader())
  1295. {
  1296. if (reader.HasRows)
  1297. {
  1298. reader.Read();
  1299. if (failType.Equals(FailureType.Password))
  1300. {
  1301. failureCount = reader.GetInt32(0);
  1302. windowStart = reader.GetDateTime(1);
  1303. }
  1304. else if (failType.Equals(FailureType.PasswordAnswer))
  1305. {
  1306. failureCount = reader.GetInt32(2);
  1307. windowStart = reader.GetDateTime(3);
  1308. }
  1309. }
  1310. }
  1311. }
  1312. catch (SqliteException e)
  1313. {
  1314. Trace.WriteLine(e.ToString());
  1315. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  1316. }
  1317. finally
  1318. {
  1319. if (dbConn != null)
  1320. dbConn.Close();
  1321. }
  1322. }
  1323. // Calculate failture count and update database
  1324. using (SqliteCommand dbCommand = dbConn.CreateCommand())
  1325. {
  1326. DateTime windowEnd = windowStart.AddMinutes(m_PasswordAttemptWindow);
  1327. try
  1328. {
  1329. if (failureCount == 0 || DateTime.Now > windowEnd)
  1330. {
  1331. // First password failure or outside of PasswordAttemptWindow.
  1332. // Start a new password failure count from 1 and a new window starting now.
  1333. if (failType.Equals(FailureType.Password))
  1334. {
  1335. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"FailedPasswordAttemptCount\" = @Count, \"FailedPasswordAttemptWindowStart\" = @WindowStart WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  1336. }
  1337. else if (failType.Equals(FailureType.PasswordAnswer))
  1338. {
  1339. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"FailedPasswordAnswerAttemptCount\" = @Count, \"FailedPasswordAnswerAttemptWindowStart\" = @WindowStart WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  1340. }
  1341. AddParameter (dbCommand,"@Count", 1);
  1342. AddParameter (dbCommand,"@WindowStart", DateTime.Now);
  1343. AddParameter (dbCommand,"@Username", username);
  1344. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  1345. if (dbCommand.ExecuteNonQuery() < 0)
  1346. throw new ProviderException(Properties.Resources.ErrCantUpdateFailtureCountAndWindowStart);
  1347. }
  1348. else
  1349. {
  1350. failureCount++;
  1351. if (failureCount >= m_MaxInvalidPasswordAttempts)
  1352. {
  1353. // Password attempts have exceeded the failure threshold. Lock out
  1354. // the user.
  1355. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"IsLockedOut\" = @IsLockedOut, \"LastLockedOutDate\" = @LastLockedOutDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  1356. AddParameter (dbCommand,"@IsLockedOut", true);
  1357. AddParameter (dbCommand,"@LastLockedOutDate", DateTime.Now);
  1358. AddParameter (dbCommand,"@Username", username);
  1359. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  1360. if (dbCommand.ExecuteNonQuery() < 0)
  1361. throw new ProviderException(string.Format(Properties.Resources.ErrCantLogoutUser, username));
  1362. }
  1363. else
  1364. {
  1365. // Password attempts have not exceeded the failure threshold. Update
  1366. // the failure counts. Leave the window the same.
  1367. if (failType.Equals(FailureType.Password))
  1368. {
  1369. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"FailedPasswordAttemptCount\" = @Count WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  1370. }
  1371. else if (failType.Equals(FailureType.PasswordAnswer))
  1372. {
  1373. dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"FailedPasswordAnswerAttemptCount\" = @Count WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
  1374. }
  1375. AddParameter (dbCommand,"@Count", failureCount);
  1376. AddParameter (dbCommand,"@Username", username);
  1377. AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
  1378. if (dbCommand.ExecuteNonQuery() < 0)
  1379. throw new ProviderException(Properties.Resources.ErrCantUpdateFailtureCount);
  1380. }
  1381. }
  1382. }
  1383. catch (SqliteException e)
  1384. {
  1385. Trace.WriteLine(e.ToString());
  1386. throw new ProviderException(Properties.Resources.ErrOperationAborted);
  1387. }
  1388. finally
  1389. {
  1390. if (dbConn != null)
  1391. dbConn.Close();
  1392. }
  1393. }
  1394. }
  1395. }
  1396. private enum FailureType
  1397. {
  1398. Password,
  1399. PasswordAnswer
  1400. }
  1401. #endregion
  1402. }
  1403. }
  1404. #endif