Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Services.Authentication Prototype/Service/Provider/HeuristicLabMembershipProvider.cs @ 3965

Last change on this file since 3965 was 3965, checked in by jhaider, 14 years ago

added support for Cryptography (#1046)

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