X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Web%2FSystem.Web.Security%2FFormsAuthentication.cs;h=0bb04b34e179049c02435ff269e819458402c6fb;hb=ce127979614f27e95c901fbf490d0e1b0af17e04;hp=d21d0c46275abd7233d864353296a03f61dfb067;hpb=55e297f89d9a26f5d7b171a386264e901dde800b;p=mono.git diff --git a/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs b/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs index d21d0c46275..0bb04b34e17 100644 --- a/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs +++ b/mcs/class/System.Web/System.Web.Security/FormsAuthentication.cs @@ -5,6 +5,7 @@ // Gonzalo Paniagua Javier (gonzalo@ximian.com) // // (C) 2002,2003 Ximian, Inc (http://www.ximian.com) +// Copyright (c) 2005 Novell, Inc (http://www.novell.com) // // @@ -41,6 +42,9 @@ namespace System.Web.Security { public sealed class FormsAuthentication { + const int MD5_hash_size = 16; + const int SHA1_hash_size = 20; + static string authConfigPath = "system.web/authentication"; static bool initialized; static string cookieName; @@ -48,6 +52,7 @@ namespace System.Web.Security static int timeout; static FormsProtectionEnum protection; static object locker = new object (); + static byte [] init_vector; // initialization vector used for 3DES #if NET_1_1 static bool requireSSL; static bool slidingExpiration; @@ -91,28 +96,71 @@ namespace System.Web.Security return (password == stored); } + static FormsAuthenticationTicket Decrypt2 (byte [] bytes) + { + if (protection == FormsProtectionEnum.None) + return FormsAuthenticationTicket.FromByteArray (bytes); + + MachineKeyConfig config = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig; + bool all = (protection == FormsProtectionEnum.All); + + byte [] result = bytes; + if (all || protection == FormsProtectionEnum.Encryption) { + ICryptoTransform decryptor; + decryptor = new TripleDESCryptoServiceProvider().CreateDecryptor (config.DecryptionKey192Bits, init_vector); + result = decryptor.TransformFinalBlock (bytes, 0, bytes.Length); + bytes = null; + } + + if (all || protection == FormsProtectionEnum.Validation) { + int count; + + if (config.ValidationType == MachineKeyValidation.MD5) + count = MD5_hash_size; + else + count = SHA1_hash_size; // 3DES and SHA1 + + byte [] vk = config.ValidationKey; + byte [] mix = new byte [result.Length - count + vk.Length]; + Buffer.BlockCopy (result, 0, mix, 0, result.Length - count); + Buffer.BlockCopy (vk, 0, mix, result.Length - count, vk.Length); + + byte [] hash = null; + switch (config.ValidationType) { + case MachineKeyValidation.MD5: + hash = MD5.Create ().ComputeHash (mix); + break; + // From MS docs: "When 3DES is specified, forms authentication defaults to SHA1" + case MachineKeyValidation.TripleDES: + case MachineKeyValidation.SHA1: + hash = SHA1.Create ().ComputeHash (mix); + break; + } + + if (result.Length < count) + throw new ArgumentException ("Error validating ticket (length).", "encryptedTicket"); + + int i, k; + for (i = result.Length - count, k = 0; k < count; i++, k++) { + if (result [i] != hash [k]) + throw new ArgumentException ("Error validating ticket.", "encryptedTicket"); + } + } + + return FormsAuthenticationTicket.FromByteArray (result); + } + public static FormsAuthenticationTicket Decrypt (string encryptedTicket) { if (encryptedTicket == null || encryptedTicket == String.Empty) throw new ArgumentException ("Invalid encrypted ticket", "encryptedTicket"); Initialize (); - byte [] bytes = MachineKeyConfigHandler.GetBytes (encryptedTicket, encryptedTicket.Length); - string decrypted = Encoding.ASCII.GetString (bytes); - FormsAuthenticationTicket ticket = null; + + FormsAuthenticationTicket ticket; + byte [] bytes = MachineKeyConfig.GetBytes (encryptedTicket, encryptedTicket.Length); try { - string [] values = decrypted.Split ((char) 1, (char) 2, (char) 3, (char) 4, (char) 5, (char) 6, (char) 7); - if (values.Length != 8) - throw new Exception (values.Length + " " + encryptedTicket); - - - ticket = new FormsAuthenticationTicket (Int32.Parse (values [0]), - values [1], - new DateTime (Int64.Parse (values [2])), - new DateTime (Int64.Parse (values [3])), - (values [4] == "1"), - values [5], - values [6]); + ticket = Decrypt2 (bytes); } catch (Exception) { ticket = null; } @@ -126,24 +174,45 @@ namespace System.Web.Security throw new ArgumentNullException ("ticket"); Initialize (); - StringBuilder allTicket = new StringBuilder (); - allTicket.Append (ticket.Version); - allTicket.Append ('\u0001'); - allTicket.Append (ticket.Name); - allTicket.Append ('\u0002'); - allTicket.Append (ticket.IssueDate.Ticks); - allTicket.Append ('\u0003'); - allTicket.Append (ticket.Expiration.Ticks); - allTicket.Append ('\u0004'); - allTicket.Append (ticket.IsPersistent ? '1' : '0'); - allTicket.Append ('\u0005'); - allTicket.Append (ticket.UserData); - allTicket.Append ('\u0006'); - allTicket.Append (ticket.CookiePath); - allTicket.Append ('\u0007'); - //if (protection == FormsProtectionEnum.None) - return GetHexString (allTicket.ToString ()); - //TODO: encrypt and validate + byte [] ticket_bytes = ticket.ToByteArray (); + if (protection == FormsProtectionEnum.None) + return GetHexString (ticket_bytes); + + byte [] result = ticket_bytes; + MachineKeyConfig config = HttpContext.GetAppConfig ("system.web/machineKey") as MachineKeyConfig; + bool all = (protection == FormsProtectionEnum.All); + if (all || protection == FormsProtectionEnum.Validation) { + byte [] valid_bytes = null; + byte [] vk = config.ValidationKey; + byte [] mix = new byte [ticket_bytes.Length + vk.Length]; + Buffer.BlockCopy (ticket_bytes, 0, mix, 0, ticket_bytes.Length); + Buffer.BlockCopy (vk, 0, mix, result.Length, vk.Length); + + switch (config.ValidationType) { + case MachineKeyValidation.MD5: + valid_bytes = MD5.Create ().ComputeHash (mix); + break; + // From MS docs: "When 3DES is specified, forms authentication defaults to SHA1" + case MachineKeyValidation.TripleDES: + case MachineKeyValidation.SHA1: + valid_bytes = SHA1.Create ().ComputeHash (mix); + break; + } + + int tlen = ticket_bytes.Length; + int vlen = valid_bytes.Length; + result = new byte [tlen + vlen]; + Buffer.BlockCopy (ticket_bytes, 0, result, 0, tlen); + Buffer.BlockCopy (valid_bytes, 0, result, tlen, vlen); + } + + if (all || protection == FormsProtectionEnum.Encryption) { + ICryptoTransform encryptor; + encryptor = new TripleDESCryptoServiceProvider().CreateEncryptor (config.DecryptionKey192Bits, init_vector); + result = encryptor.TransformFinalBlock (result, 0, result.Length); + } + + return GetHexString (result); } public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie) @@ -187,7 +256,6 @@ namespace System.Web.Security if (userName == null) return null; - //TODO: what's createPersistentCookie used for? Initialize (); HttpRequest request = HttpContext.Current.Request; string returnUrl = request ["RETURNURL"]; @@ -215,7 +283,7 @@ namespace System.Web.Security static string GetHexString (string str) { - return GetHexString (Encoding.ASCII.GetBytes (str)); + return GetHexString (Encoding.UTF8.GetBytes (str)); } static string GetHexString (byte [] bytes) @@ -237,9 +305,9 @@ namespace System.Web.Security byte [] bytes; if (String.Compare (passwordFormat, "MD5", true) == 0) { - bytes = MD5.Create ().ComputeHash (Encoding.ASCII.GetBytes (password)); + bytes = MD5.Create ().ComputeHash (Encoding.UTF8.GetBytes (password)); } else if (String.Compare (passwordFormat, "SHA1", true) == 0) { - bytes = SHA1.Create ().ComputeHash (Encoding.ASCII.GetBytes (password)); + bytes = SHA1.Create ().ComputeHash (Encoding.UTF8.GetBytes (password)); } else { throw new ArgumentException ("The format must be either MD5 or SHA1", "passwordFormat"); } @@ -280,6 +348,16 @@ namespace System.Web.Security #endif } + // IV is 8 bytes long for 3DES + init_vector = new byte [8]; + int len = cookieName.Length; + for (int i = 0; i < 8; i++) { + if (i >= len) + break; + + init_vector [i] = (byte) cookieName [i]; + } + initialized = true; } }