2 // System.Web.Security.FormsAuthentication
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
34 using System.Security.Cryptography;
37 using System.Web.Configuration;
38 using System.Web.Util;
40 namespace System.Web.Security
42 public sealed class FormsAuthentication
44 static string authConfigPath = "system.web/authentication";
45 static bool initialized;
46 static string cookieName;
47 static string cookiePath;
49 static FormsProtectionEnum protection;
50 static object locker = new object ();
52 static bool requireSSL;
53 static bool slidingExpiration;
56 // same names and order used in xsp
57 static string [] indexFiles = { "index.aspx",
63 public static bool Authenticate (string name, string password)
65 if (name == null || password == null)
69 HttpContext context = HttpContext.Current;
71 throw new HttpException ("Context is null!");
73 AuthConfig config = context.GetConfig (authConfigPath) as AuthConfig;
74 Hashtable users = config.CredentialUsers;
75 string stored = users [name] as string;
79 switch (config.PasswordFormat) {
80 case FormsAuthPasswordFormat.Clear:
83 case FormsAuthPasswordFormat.MD5:
84 password = HashPasswordForStoringInConfigFile (password, "MD5");
86 case FormsAuthPasswordFormat.SHA1:
87 password = HashPasswordForStoringInConfigFile (password, "SHA1");
91 return (password == stored);
94 public static FormsAuthenticationTicket Decrypt (string encryptedTicket)
96 if (encryptedTicket == null || encryptedTicket == String.Empty)
97 throw new ArgumentException ("Invalid encrypted ticket", "encryptedTicket");
100 byte [] bytes = MachineKeyConfigHandler.GetBytes (encryptedTicket, encryptedTicket.Length);
101 string decrypted = Encoding.ASCII.GetString (bytes);
102 FormsAuthenticationTicket ticket = null;
104 string [] values = decrypted.Split ((char) 1, (char) 2, (char) 3, (char) 4, (char) 5, (char) 6, (char) 7);
105 if (values.Length != 8)
106 throw new Exception (values.Length + " " + encryptedTicket);
109 ticket = new FormsAuthenticationTicket (Int32.Parse (values [0]),
111 new DateTime (Int64.Parse (values [2])),
112 new DateTime (Int64.Parse (values [3])),
116 } catch (Exception) {
123 public static string Encrypt (FormsAuthenticationTicket ticket)
126 throw new ArgumentNullException ("ticket");
129 StringBuilder allTicket = new StringBuilder ();
130 allTicket.Append (ticket.Version);
131 allTicket.Append ('\u0001');
132 allTicket.Append (ticket.Name);
133 allTicket.Append ('\u0002');
134 allTicket.Append (ticket.IssueDate.Ticks);
135 allTicket.Append ('\u0003');
136 allTicket.Append (ticket.Expiration.Ticks);
137 allTicket.Append ('\u0004');
138 allTicket.Append (ticket.IsPersistent ? '1' : '0');
139 allTicket.Append ('\u0005');
140 allTicket.Append (ticket.UserData);
141 allTicket.Append ('\u0006');
142 allTicket.Append (ticket.CookiePath);
143 allTicket.Append ('\u0007');
144 //if (protection == FormsProtectionEnum.None)
145 return GetHexString (allTicket.ToString ());
146 //TODO: encrypt and validate
149 public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie)
151 return GetAuthCookie (userName, createPersistentCookie, null);
154 public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie, string strCookiePath)
158 if (userName == null)
159 userName = String.Empty;
161 if (strCookiePath == null || strCookiePath.Length == 0)
162 strCookiePath = cookiePath;
164 DateTime now = DateTime.Now;
166 if (createPersistentCookie)
167 then = now.AddYears (50);
169 then = now.AddMinutes (timeout);
171 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket (1,
175 createPersistentCookie,
179 if (!createPersistentCookie)
180 then = DateTime.MinValue;
182 return new HttpCookie (cookieName, Encrypt (ticket), strCookiePath, then);
185 public static string GetRedirectUrl (string userName, bool createPersistentCookie)
187 if (userName == null)
190 //TODO: what's createPersistentCookie used for?
192 HttpRequest request = HttpContext.Current.Request;
193 string returnUrl = request ["RETURNURL"];
194 if (returnUrl != null)
197 returnUrl = request.ApplicationPath;
198 string apppath = request.PhysicalApplicationPath;
201 foreach (string indexFile in indexFiles) {
202 string filePath = Path.Combine (apppath, indexFile);
203 if (File.Exists (filePath)) {
204 returnUrl = UrlUtils.Combine (returnUrl, indexFile);
211 returnUrl = UrlUtils.Combine (returnUrl, "index.aspx");
216 static string GetHexString (string str)
218 return GetHexString (Encoding.ASCII.GetBytes (str));
221 static string GetHexString (byte [] bytes)
223 StringBuilder result = new StringBuilder (bytes.Length * 2);
224 foreach (byte b in bytes)
225 result.AppendFormat ("{0:x2}", (int) b);
227 return result.ToString ();
230 public static string HashPasswordForStoringInConfigFile (string password, string passwordFormat)
232 if (password == null)
233 throw new ArgumentNullException ("password");
235 if (passwordFormat == null)
236 throw new ArgumentNullException ("passwordFormat");
239 if (String.Compare (passwordFormat, "MD5", true) == 0) {
240 bytes = MD5.Create ().ComputeHash (Encoding.ASCII.GetBytes (password));
241 } else if (String.Compare (passwordFormat, "SHA1", true) == 0) {
242 bytes = SHA1.Create ().ComputeHash (Encoding.ASCII.GetBytes (password));
244 throw new ArgumentException ("The format must be either MD5 or SHA1", "passwordFormat");
247 return GetHexString (bytes);
250 public static void Initialize ()
259 HttpContext context = HttpContext.Current;
261 throw new HttpException ("Context is null!");
263 AuthConfig authConfig = context.GetConfig (authConfigPath) as AuthConfig;
264 if (authConfig != null) {
265 cookieName = authConfig.CookieName;
266 timeout = authConfig.Timeout;
267 cookiePath = authConfig.CookiePath;
268 protection = authConfig.Protection;
270 requireSSL = authConfig.RequireSSL;
271 slidingExpiration = authConfig.SlidingExpiration;
274 cookieName = ".MONOAUTH";
277 protection = FormsProtectionEnum.All;
279 slidingExpiration = true;
287 public static void RedirectFromLoginPage (string userName, bool createPersistentCookie)
289 RedirectFromLoginPage (userName, createPersistentCookie, null);
292 public static void RedirectFromLoginPage (string userName, bool createPersistentCookie, string strCookiePath)
294 if (userName == null)
298 SetAuthCookie (userName, createPersistentCookie, strCookiePath);
299 HttpResponse resp = HttpContext.Current.Response;
300 resp.Redirect (GetRedirectUrl (userName, createPersistentCookie), false);
303 public static FormsAuthenticationTicket RenewTicketIfOld (FormsAuthenticationTicket tOld)
308 DateTime now = DateTime.Now;
309 TimeSpan toIssue = now - tOld.IssueDate;
310 TimeSpan toExpiration = tOld.Expiration - now;
311 if (toExpiration > toIssue)
314 FormsAuthenticationTicket tNew = tOld.Clone ();
315 tNew.SetDates (now, now + (tOld.Expiration - tOld.IssueDate));
319 public static void SetAuthCookie (string userName, bool createPersistentCookie)
322 SetAuthCookie (userName, createPersistentCookie, cookiePath);
325 public static void SetAuthCookie (string userName, bool createPersistentCookie, string strCookiePath)
327 HttpContext context = HttpContext.Current;
329 throw new HttpException ("Context is null!");
331 HttpResponse response = context.Response;
332 if (response == null)
333 throw new HttpException ("Response is null!");
335 response.Cookies.Add (GetAuthCookie (userName, createPersistentCookie, strCookiePath));
338 public static void SignOut ()
342 HttpContext context = HttpContext.Current;
344 throw new HttpException ("Context is null!");
346 HttpResponse response = context.Response;
347 if (response == null)
348 throw new HttpException ("Response is null!");
350 response.Cookies.MakeCookieExpire (cookieName, cookiePath);
353 public static string FormsCookieName
361 public static string FormsCookiePath
369 public static bool RequireSSL {
376 public static bool SlidingExpiration {
379 return slidingExpiration;