Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Services.Authentication Prototyp/HeuristicLab.Services.Authentication Prototype/Service/Provider/HeuristicLabMembershipProvider.cs @ 4427

Last change on this file since 4427 was 4427, checked in by mholper, 14 years ago
File size: 16.7 KB
Line 
1using System;
2using System.Collections.Specialized;
3using System.Configuration;
4using System.Configuration.Provider;
5using System.IO;
6using System.Linq;
7using System.Security.Cryptography;
8using System.Text;
9using System.Web.Configuration;
10using System.Web.Security;
11using Persistence;
12
13
14namespace Service.Provider {
15  class HeuristicLabMembershipProvider : MembershipProvider {
16
17    #region variables
18
19    private string pApplicationName;
20    private bool pEnablePasswordReset;
21    private bool pEnablePasswordRetrieval;
22    private bool pRequiresQuestionAndAnswer;
23    private bool pRequiresUniqueEmail;
24    private int pMaxInvalidPasswordAttempts;
25    private int pPasswordAttemptWindow;
26    private int pMinRequiredPasswordLength;
27    private MembershipPasswordFormat pPasswordFormat = MembershipPasswordFormat.Clear;
28
29    #endregion
30
31    #region properties
32
33    public override string ApplicationName {
34      get { return pApplicationName; }
35      set { pApplicationName = value; }
36    }
37
38    public override bool EnablePasswordReset {
39      get { return pEnablePasswordReset; }
40    }
41
42    public override bool EnablePasswordRetrieval {
43      get { return pEnablePasswordRetrieval; }
44    }
45
46    public override int MaxInvalidPasswordAttempts {
47      get { return pMaxInvalidPasswordAttempts; }
48    }
49
50    public override int MinRequiredNonAlphanumericCharacters {
51      get { return 0; }
52    }
53
54    public override int MinRequiredPasswordLength {
55      get { return pMinRequiredPasswordLength; }
56    }
57
58    public override int PasswordAttemptWindow {
59      get { return pPasswordAttemptWindow; }
60    }
61
62    public override MembershipPasswordFormat PasswordFormat {
63      get { return pPasswordFormat; }
64    }
65
66    public override string PasswordStrengthRegularExpression {
67      get { return string.Empty; }
68    }
69
70    public override bool RequiresQuestionAndAnswer {
71      get { return pRequiresQuestionAndAnswer; }
72    }
73
74    public override bool RequiresUniqueEmail {
75      get { return pRequiresUniqueEmail; }
76    }
77
78    #endregion
79
80    public override void Initialize(string name, NameValueCollection config) {
81      //
82      // Initialize values from web.config.
83      //
84
85      if (config == null)
86        throw new ArgumentNullException("config");
87
88      if (string.IsNullOrEmpty(name) || name.Length == 0)
89        name = "HeuristicLabMembershipProvider";
90
91      if (String.IsNullOrEmpty(config["description"])) {
92        config.Remove("description");
93        config.Add("description", "Heuristic Lab Membership provider");
94      }
95
96      // Initialize the abstract base class.
97      base.Initialize(name, config);
98
99      pApplicationName = GetConfigValue(config["applicationName"], System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
100      pMaxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
101      pPasswordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
102      pMinRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7"));
103      pEnablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
104      pEnablePasswordRetrieval = Convert.ToBoolean(GetConfigValue(config["enablePasswordRetrieval"], "true"));
105      pRequiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "false"));
106      pRequiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "true"));
107
108      string tempFormat = config["passwordFormat"];
109      if (tempFormat == null) {
110        tempFormat = "Clear";
111      }
112
113      switch (tempFormat) {
114        case "Hashed":
115          pPasswordFormat = MembershipPasswordFormat.Hashed;
116          break;
117        case "Encrypted":
118          pPasswordFormat = MembershipPasswordFormat.Encrypted;
119          break;
120        case "Clear":
121          pPasswordFormat = MembershipPasswordFormat.Clear;
122          break;
123        default:
124          throw new ProviderException("Password format not supported.");
125      }
126    }
127
128
129
130    public override bool ChangePassword(string username, string oldPassword, string newPassword) {
131      using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
132        // check database connection
133        if (db == null) {
134          return false;
135        }
136        try {
137          // try to get user
138          HeuristicLabUser u = db.HeuristicLabUsers.Single(x => x.UserName == username);
139          if (u.ChangePassword(oldPassword, newPassword)) {
140            // save user to database only if needed
141            db.SubmitChanges();
142            return true;
143          } else {
144            return false;
145          }
146        }
147        catch (Exception) {
148          return false;
149        }
150      }
151    }
152
153    public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) {
154      using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
155        // check database connection
156        if (db == null) {
157          return false;
158        }
159        try {
160          // try to get user
161          HeuristicLabUser u = db.HeuristicLabUsers.Single(x => x.UserName == username);
162          if (u.ChangePasswordQuestionAndAnswer(password, newPasswordQuestion, newPasswordAnswer)) {
163            // save user to database only if needed
164            db.SubmitChanges();
165            return true;
166          } else {
167            return false;
168          }
169        }
170        catch (Exception) {
171          return false;
172        }
173      }
174    }
175
176    public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) {
177      using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
178        // check database connection
179        if (db == null) {
180          status = MembershipCreateStatus.ProviderError;
181          return null;
182        }
183        try {
184          // check for duplicate entries
185          if (db.HeuristicLabUsers.Count(x => x.UserName == username) > 0) {
186            status = MembershipCreateStatus.DuplicateUserName;
187            return null;
188          }
189          if (db.HeuristicLabUsers.Count(x => x.Email == email) > 0) {
190            status = MembershipCreateStatus.DuplicateEmail;
191            return null;
192          }
193
194          // create new user
195          HeuristicLabUser u = new HeuristicLabUser(username, email, passwordQuestion, "");
196          password = EncodePassword(password);
197          u.ChangePassword("INIT", password);
198          u.ChangePasswordQuestionAndAnswer(password, passwordQuestion, passwordAnswer);
199          // save user into database
200          db.HeuristicLabUsers.InsertOnSubmit(u);
201          db.SubmitChanges();
202
203          // success
204          status = MembershipCreateStatus.Success;
205          return u;
206        }
207        catch (Exception) {
208          // error
209          status = MembershipCreateStatus.ProviderError;
210          return null;
211        }
212      }
213    }
214
215    public override bool DeleteUser(string username, bool deleteAllRelatedData) {
216      using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
217        // check database connection
218        if (db == null) {
219          return false;
220        }
221        try {
222          // try to get user
223          HeuristicLabUser u =
224            db.HeuristicLabUsers.Single<HeuristicLabUser>(x => x.UserName == username);
225
226          // optionally delete related data
227          if (deleteAllRelatedData) {
228            db.HeuristicLabUserRole.DeleteAllOnSubmit<HeuristicLabUserRole>(u.HeuristicLabUserRoles);
229          }
230
231          // delete user
232          db.HeuristicLabUsers.DeleteOnSubmit(u);
233          db.SubmitChanges();
234          return true;
235        }
236        catch (Exception) {
237          return false;
238        }
239      }
240    }
241
242
243
244    public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) {
245      throw new NotImplementedException();
246    }
247
248    public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) {
249      throw new NotImplementedException();
250    }
251
252    // not for production use - fab and dkhan are currently working on that
253    public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) {
254      totalRecords = 0;
255      using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
256        if (db == null) {
257          totalRecords = 0;
258          return new MembershipUserCollection();
259        }
260
261        // bail out if there are no records
262        if (0 == (totalRecords = db.HeuristicLabUsers.Count<HeuristicLabUser>())) return new MembershipUserCollection();
263
264        MembershipUserCollection userCollection = new MembershipUserCollection();
265        int skip = (pageIndex == 0) ? 0 : (pageIndex * pageSize) - 1;
266
267        var users = from u in db.HeuristicLabUsers select u;
268
269        foreach (HeuristicLabUser u in users) {
270
271          // this leads to a npe
272          if (u != null) {
273            userCollection.Add(u);
274          }
275        }
276        return userCollection;
277      }
278    }
279
280    public override int GetNumberOfUsersOnline() {
281      throw new NotImplementedException();
282    }
283
284    public override string GetPassword(string username, string answer) {
285
286      throw new NotImplementedException();
287    }
288
289    public override MembershipUser GetUser(string username, bool userIsOnline) {
290      throw new NotImplementedException();
291    }
292
293    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) {
294      throw new NotImplementedException();
295    }
296
297    public override string GetUserNameByEmail(string email) {
298      throw new NotImplementedException();
299    }
300
301
302
303    public override string ResetPassword(string username, string answer) {
304      throw new NotImplementedException();
305    }
306
307    public bool LockUser(string userName)
308    {
309        using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext())
310        {
311            // check database connection
312            if (db == null)
313            {
314                return false;
315            }
316            try
317            {
318                // try to get user
319                HeuristicLabUser u =
320                  db.HeuristicLabUsers.Single<HeuristicLabUser>(x => x.UserName == userName);
321
322                // unlock user
323                u.LockUser();
324                db.SubmitChanges();
325                return true;
326            }
327            catch (Exception)
328            {
329                return false;
330            }
331        }
332    }
333
334    public override bool UnlockUser(string userName)
335    {
336        using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext())
337        {
338            // check database connection
339            if (db == null)
340            {
341                return false;
342            }
343            try
344            {
345                // try to get user
346                HeuristicLabUser u =
347                  db.HeuristicLabUsers.Single<HeuristicLabUser>(x => x.UserName == userName);
348
349                // unlock user
350                u.UnlockUser();
351                db.SubmitChanges();
352                return true;
353            }
354            catch (Exception)
355            {
356                return false;
357            }
358        }
359    }
360
361    public override void UpdateUser(MembershipUser user) {
362      throw new NotImplementedException();
363    }
364    /// <summary>
365    /// Validates a user
366    /// </summary>
367    /// <param name="username"></param>
368    /// <param name="password"></param>
369    /// <returns></returns>
370    public override bool ValidateUser(string username, string password) {
371      bool isValid = false;
372      using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
373        if (db == null) {
374          return false;
375        }
376        HeuristicLabUser u = db.HeuristicLabUsers.Single(x => x.UserName == username);
377        isValid = CheckPassword(password, u.GetPassword());
378      }
379      return isValid;
380    }
381
382    /// <summary>
383    /// compaiers to passwords
384    /// </summary>
385    /// <param name="password"></param>
386    /// <param name="dbpassword"></param>
387    /// <returns></returns>
388    private bool CheckPassword(string password, string dbpassword) {
389      string pass1 = password;
390      string pass2 = dbpassword;
391
392      switch (PasswordFormat) {
393        case MembershipPasswordFormat.Encrypted:
394          pass2 = DecodePassword(dbpassword);
395          break;
396        case MembershipPasswordFormat.Hashed:
397          pass1 = EncodePassword(password);
398          break;
399        default:
400          break;
401      }
402
403      if (pass1 == pass2) {
404        return true;
405      }
406
407      return false;
408    }
409
410
411    /// <summary>
412    /// Encodes a password
413    /// </summary>
414    /// <param name="password"></param>
415    /// <returns></returns>
416    private string EncodePassword(string password) {
417      string encodedPassword = password;
418
419      switch (PasswordFormat) {
420        case MembershipPasswordFormat.Clear:
421          break;
422        case MembershipPasswordFormat.Encrypted:
423          encodedPassword =
424            Convert.ToBase64String(EncryptPassword(Encoding.Unicode.GetBytes(password)));
425          break;
426        case MembershipPasswordFormat.Hashed:
427          SHA512 sha512 = SHA512.Create();
428          ASCIIEncoding encoder = new ASCIIEncoding();
429          byte[] combined = encoder.GetBytes(password);
430          sha512.ComputeHash(combined);
431          encodedPassword = Convert.ToBase64String(sha512.Hash);
432          break;
433        default:
434          throw new ProviderException("Unsupported password format.");
435      }
436
437      return encodedPassword;
438    }
439
440    private readonly byte[] _rgbKey = new byte[]
441                           {
442                             182, 140, 37, 101, 52, 157, 80, 17, 65, 35, 130, 208, 101, 68, 161, 45, 197, 102, 112, 190,
443                             187, 177, 37, 76, 63, 38, 190, 117, 247, 122, 94, 17
444                           };
445    private readonly byte[] _rgbIv = new byte[] { 60, 121, 178, 142, 50, 160, 226, 84, 41, 66, 158, 180, 26, 232, 42, 113 };
446
447    protected override byte[] EncryptPassword(byte[] password) {
448      SymmetricAlgorithm sa = Aes.Create();
449      MemoryStream msEncrypt = new MemoryStream();
450      CryptoStream csEncrypt = new CryptoStream(msEncrypt, sa.CreateEncryptor(_rgbKey, _rgbIv), CryptoStreamMode.Write);
451      csEncrypt.Write(password, 0, password.Length);
452      csEncrypt.Close();
453      byte[] encryptedTextBytes = msEncrypt.ToArray();
454      msEncrypt.Close();
455      return encryptedTextBytes;
456    }
457
458    protected override byte[] DecryptPassword(byte[] encodedPassword) {
459      SymmetricAlgorithm sa = Aes.Create();
460      MemoryStream msDecrypt = new MemoryStream(encodedPassword);
461      CryptoStream csDecrypt = new CryptoStream(msDecrypt, sa.CreateDecryptor(_rgbKey, _rgbIv), CryptoStreamMode.Read);
462      byte[] decryptedTextBytes = new Byte[encodedPassword.Length];
463      csDecrypt.Read(decryptedTextBytes, 0, encodedPassword.Length);
464      csDecrypt.Close();
465      msDecrypt.Close();
466      return decryptedTextBytes;
467    }
468
469    /// <summary>
470    /// Decodes a encoded Password
471    /// </summary>
472    /// <param name="encodedPassword"></param>
473    /// <returns></returns>
474    private string DecodePassword(string encodedPassword) {
475      string password = encodedPassword;
476
477      switch (PasswordFormat) {
478        case MembershipPasswordFormat.Clear:
479          break;
480        case MembershipPasswordFormat.Encrypted:
481          password =
482            Encoding.Unicode.GetString(DecryptPassword(Convert.FromBase64String(password))).TrimEnd('\0');
483
484
485          break;
486        case MembershipPasswordFormat.Hashed:
487          throw new ProviderException("Cannot unencode a hashed password.");
488        default:
489          throw new ProviderException("Unsupported password format.");
490      }
491
492      return password;
493    }
494
495    /// <summary>
496    /// returns the configuration string, if the value is null or empty the default value is returned
497    /// </summary>
498    /// <param name="configValue"></param>
499    /// <param name="defaultValue"></param>
500    /// <returns></returns>
501    private string GetConfigValue(string configValue, string defaultValue) {
502      if (String.IsNullOrEmpty(configValue))
503        return defaultValue;
504
505      return configValue;
506    }
507  }
508}
Note: See TracBrowser for help on using the repository browser.