2008-11-06 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Security / MembershipProvider.cs
index 102936a9c18b4567455ec4d170e6d521085c072d..812890ab3adc6668ed9a4d8beaeaeb48deb78b66 100644 (file)
@@ -29,6 +29,7 @@
 //
 
 #if NET_2_0
+using System.ComponentModel;
 using System.Configuration.Provider;
 using System.Web.Configuration;
 using System.Security.Cryptography;
@@ -38,6 +39,14 @@ namespace System.Web.Security
 {
        public abstract class MembershipProvider : ProviderBase
        {
+               static readonly object validatingPasswordEvent = new object ();
+
+               EventHandlerList events = new EventHandlerList ();
+               public event MembershipValidatePasswordEventHandler ValidatingPassword {
+                       add { events.AddHandler (validatingPasswordEvent, value); }
+                       remove { events.RemoveHandler (validatingPasswordEvent, value); }
+               }
+               
                protected MembershipProvider ()
                {
                }
@@ -73,80 +82,68 @@ namespace System.Web.Security
                
                protected virtual void OnValidatingPassword (ValidatePasswordEventArgs args)
                {
-                       if (ValidatingPassword != null)
-                               ValidatingPassword (this, args);
+                       MembershipValidatePasswordEventHandler eh = events [validatingPasswordEvent] as MembershipValidatePasswordEventHandler;
+                       if (eh != null)
+                               eh (this, args);
                }
 
-               protected virtual byte[] DecryptPassword (byte[] encodedPassword)
+               SymmetricAlgorithm GetAlg (out byte [] decryptionKey)
                {
-                       throw new NotImplementedException ();
-               }
+                       MachineKeySection section = (MachineKeySection) WebConfigurationManager.GetSection ("system.web/machineKey");
 
-               protected virtual byte[] EncryptPassword (byte[] password)
-               {
-                       throw new NotImplementedException ();
-               }
+                       if (section.DecryptionKey.StartsWith ("AutoGenerate"))
+                               throw new ProviderException ("You must explicitly specify a decryption key in the <machineKey> section when using encrypted passwords.");
+
+                       string alg_type = section.Decryption;
+                       if (alg_type == "Auto")
+                               alg_type = "AES";
 
-               public event MembershipValidatePasswordEventHandler ValidatingPassword;
+                       SymmetricAlgorithm alg = null;
+                       if (alg_type == "AES")
+                               alg = Rijndael.Create ();
+                       else if (alg_type == "3DES")
+                               alg = TripleDES.Create ();
+                       else
+                               throw new ProviderException (String.Format ("Unsupported decryption attribute '{0}' in <machineKey> configuration section", alg_type));
+
+                       decryptionKey = MachineKeySectionUtils.DecryptionKey192Bits (section);
+                       return alg;
+               }
 
-               internal string EncodePassword (string password, MembershipPasswordFormat passwordFormat, string salt)
+               internal const int SALT_BYTES = 16;
+               protected virtual byte [] DecryptPassword (byte [] encodedPassword)
                {
-                       byte[] password_bytes;
-                       byte[] salt_bytes;
-
-                       switch (passwordFormat) {
-                       case MembershipPasswordFormat.Clear:
-                               return password;
-                       case MembershipPasswordFormat.Hashed:
-                               password_bytes = Encoding.Unicode.GetBytes (password);
-                               salt_bytes = Convert.FromBase64String (salt);
-
-                               byte[] hashBytes = new byte[salt_bytes.Length + password_bytes.Length];
-
-                               Buffer.BlockCopy (salt_bytes, 0, hashBytes, 0, salt_bytes.Length);
-                               Buffer.BlockCopy (password_bytes, 0, hashBytes, salt_bytes.Length, password_bytes.Length);
-
-                               MembershipSection section = (MembershipSection)WebConfigurationManager.GetSection ("system.web/membership");
-                               string alg_type = section.HashAlgorithmType;
-                               if (alg_type == "") {
-                                       MachineKeySection keysection = (MachineKeySection)WebConfigurationManager.GetSection ("system.web/machineKey");
-                                       alg_type = keysection.Validation.ToString ();
-                               }
-                               using (HashAlgorithm hash = HashAlgorithm.Create (alg_type)) {
-                                       hash.TransformFinalBlock (hashBytes, 0, hashBytes.Length);
-                                       return Convert.ToBase64String (hash.Hash);
-                               }
-                       case MembershipPasswordFormat.Encrypted:
-                               password_bytes = Encoding.Unicode.GetBytes (password);
-                               salt_bytes = Convert.FromBase64String (salt);
+                       byte [] decryptionKey;
+
+                       using (SymmetricAlgorithm alg = GetAlg (out decryptionKey)) {
+                               alg.Key = decryptionKey;
 
-                               byte[] buf = new byte[password_bytes.Length + salt_bytes.Length];
+                               using (ICryptoTransform decryptor = alg.CreateDecryptor ()) {
 
-                               Array.Copy (salt_bytes, 0, buf, 0, salt_bytes.Length);
-                               Array.Copy (password_bytes, 0, buf, salt_bytes.Length, password_bytes.Length);
+                                       byte [] buf = decryptor.TransformFinalBlock (encodedPassword, 0, encodedPassword.Length);
+                                       byte [] rv = new byte [buf.Length - SALT_BYTES];
 
-                               return Convert.ToBase64String (EncryptPassword (buf));
-                       default:
-                               /* not reached.. */
-                               return null;
+                                       Array.Copy (buf, 16, rv, 0, buf.Length - 16);
+                                       return rv;
+                               }
                        }
                }
 
-               internal string DecodePassword (string password, MembershipPasswordFormat passwordFormat)
+               protected virtual byte[] EncryptPassword (byte[] password)
                {
-                       switch (passwordFormat) {
-                       case MembershipPasswordFormat.Clear:
-                               return password;
-                       case MembershipPasswordFormat.Hashed:
-                               throw new ProviderException ("Hashed passwords cannot be decoded.");
-                       case MembershipPasswordFormat.Encrypted:
-                               return Encoding.Unicode.GetString (DecryptPassword (Convert.FromBase64String (password)));
-                       default:
-                               /* not reached.. */
-                               return null;
+                       byte [] decryptionKey;
+                       byte [] iv = new byte [SALT_BYTES];
+
+                       Array.Copy (password, 0, iv, 0, Math.Min(password.Length, SALT_BYTES));
+
+                       using (SymmetricAlgorithm alg = GetAlg (out decryptionKey)) {
+                               using (ICryptoTransform encryptor = alg.CreateEncryptor (decryptionKey, iv)) {
+                                       return encryptor.TransformFinalBlock (password, 0, password.Length);
+                               }
                        }
                }
        }
 }
 #endif
 
+