2 // System.Web.Security.FormsAuthentication
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
11 using System.Collections;
13 using System.Security.Cryptography;
16 using System.Web.Configuration;
17 using System.Web.Util;
19 namespace System.Web.Security
21 public sealed class FormsAuthentication
23 static string authConfigPath = "system.web/authentication";
24 static bool initialized;
25 static string cookieName;
26 static string cookiePath;
28 static FormsProtectionEnum protection;
30 static bool requireSSL;
31 static bool slidingExpiration;
34 // same names and order used in xsp
35 static string [] indexFiles = { "index.aspx",
41 public static bool Authenticate (string name, string password)
43 if (name == null || password == null)
47 HttpContext context = HttpContext.Current;
49 throw new HttpException ("Context is null!");
51 AuthConfig config = context.GetConfig (authConfigPath) as AuthConfig;
52 Hashtable users = config.CredentialUsers;
53 string stored = users [name] as string;
57 switch (config.PasswordFormat) {
58 case FormsAuthPasswordFormat.Clear:
61 case FormsAuthPasswordFormat.MD5:
62 stored = HashPasswordForStoringInConfigFile (stored, "MD5");
64 case FormsAuthPasswordFormat.SHA1:
65 stored = HashPasswordForStoringInConfigFile (stored, "SHA1");
69 return (password == stored);
72 public static FormsAuthenticationTicket Decrypt (string encryptedTicket)
74 if (encryptedTicket == null || encryptedTicket == String.Empty)
75 throw new ArgumentException ("Invalid encrypted ticket", "encryptedTicket");
78 byte [] bytes = MachineKeyConfigHandler.GetBytes (encryptedTicket, encryptedTicket.Length);
79 string decrypted = Encoding.ASCII.GetString (bytes);
80 FormsAuthenticationTicket ticket = null;
82 string [] values = decrypted.Split ((char) 1, (char) 2, (char) 3, (char) 4, (char) 5, (char) 6, (char) 7);
83 if (values.Length != 8)
84 throw new Exception (values.Length + " " + encryptedTicket);
87 ticket = new FormsAuthenticationTicket (Int32.Parse (values [0]),
89 new DateTime (Int64.Parse (values [2])),
90 new DateTime (Int64.Parse (values [3])),
101 public static string Encrypt (FormsAuthenticationTicket ticket)
104 throw new ArgumentNullException ("ticket");
107 StringBuilder allTicket = new StringBuilder ();
108 allTicket.Append (ticket.Version);
109 allTicket.Append ('\u0001');
110 allTicket.Append (ticket.Name);
111 allTicket.Append ('\u0002');
112 allTicket.Append (ticket.IssueDate.Ticks);
113 allTicket.Append ('\u0003');
114 allTicket.Append (ticket.Expiration.Ticks);
115 allTicket.Append ('\u0004');
116 allTicket.Append (ticket.IsPersistent ? '1' : '0');
117 allTicket.Append ('\u0005');
118 allTicket.Append (ticket.UserData);
119 allTicket.Append ('\u0006');
120 allTicket.Append (ticket.CookiePath);
121 allTicket.Append ('\u0007');
122 //if (protection == FormsProtectionEnum.None)
123 return GetHexString (allTicket.ToString ());
124 //TODO: encrypt and validate
127 public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie)
129 return GetAuthCookie (userName, createPersistentCookie, null);
132 public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie, string strCookiePath)
136 if (userName == null)
137 userName = String.Empty;
139 if (strCookiePath == null || strCookiePath.Length == 0)
140 strCookiePath = cookiePath;
142 DateTime now = DateTime.Now;
144 if (createPersistentCookie)
145 then = now.AddYears (50);
147 then = now.AddMinutes (timeout);
149 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket (1,
153 createPersistentCookie,
157 if (!createPersistentCookie)
158 then = DateTime.MinValue;
160 return new HttpCookie (cookieName, Encrypt (ticket), strCookiePath, then);
163 public static string GetRedirectUrl (string userName, bool createPersistentCookie)
165 if (userName == null)
168 //TODO: what's createPersistentCookie used for?
170 HttpRequest request = HttpContext.Current.Request;
171 string returnUrl = request ["RETURNURL"];
172 if (returnUrl != null)
175 AuthConfig authConfig = context.GetConfig (authConfigPath) as AuthConfig;
176 if (authConfig.LoginUrl != null) {
177 return authConfig.LoginUrl;
180 returnUrl = request.ApplicationPath;
181 string apppath = request.PhysicalApplicationPath;
184 foreach (string indexFile in indexFiles) {
185 string filePath = Path.Combine (apppath, indexFile);
186 if (File.Exists (filePath)) {
187 returnUrl = UrlUtils.Combine (returnUrl, indexFile);
194 returnUrl = UrlUtils.Combine (returnUrl, "index.aspx");
199 static string GetHexString (string str)
201 return GetHexString (Encoding.ASCII.GetBytes (str));
204 static string GetHexString (byte [] bytes)
206 StringBuilder result = new StringBuilder (bytes.Length * 2);
207 foreach (byte b in bytes)
208 result.AppendFormat ("{0:x2}", (int) b);
210 return result.ToString ();
213 public static string HashPasswordForStoringInConfigFile (string password, string passwordFormat)
215 if (password == null)
216 throw new ArgumentNullException ("password");
218 if (passwordFormat == null)
219 throw new ArgumentNullException ("passwordFormat");
222 if (String.Compare (passwordFormat, "MD5", true) == 0) {
223 bytes = MD5.Create ().ComputeHash (Encoding.ASCII.GetBytes (password));
224 } else if (String.Compare (passwordFormat, "SHA1", true) == 0) {
225 bytes = SHA1.Create ().ComputeHash (Encoding.ASCII.GetBytes (password));
227 throw new ArgumentException ("The format must be either MD5 or SHA1", "passwordFormat");
230 return GetHexString (bytes);
233 public static void Initialize ()
238 lock (typeof (FormsAuthentication)) {
242 HttpContext context = HttpContext.Current;
244 throw new HttpException ("Context is null!");
246 AuthConfig authConfig = context.GetConfig (authConfigPath) as AuthConfig;
247 if (authConfig != null) {
248 cookieName = authConfig.CookieName;
249 timeout = authConfig.Timeout;
250 cookiePath = authConfig.CookiePath;
251 protection = authConfig.Protection;
253 requireSSL = authConfig.RequireSSL;
254 slidingExpiration = authConfig.SlidingExpiration;
257 cookieName = ".MONOAUTH";
260 protection = FormsProtectionEnum.All;
262 slidingExpiration = true;
270 public static void RedirectFromLoginPage (string userName, bool createPersistentCookie)
272 RedirectFromLoginPage (userName, createPersistentCookie, null);
275 public static void RedirectFromLoginPage (string userName, bool createPersistentCookie, string strCookiePath)
277 if (userName == null)
281 SetAuthCookie (userName, createPersistentCookie, strCookiePath);
282 HttpResponse resp = HttpContext.Current.Response;
283 resp.Redirect (GetRedirectUrl (userName, createPersistentCookie), false);
286 public static FormsAuthenticationTicket RenewTicketIfOld (FormsAuthenticationTicket tOld)
291 DateTime now = DateTime.Now;
292 TimeSpan toIssue = now - tOld.IssueDate;
293 TimeSpan toExpiration = tOld.Expiration - now;
294 if (toExpiration > toIssue)
297 FormsAuthenticationTicket tNew = tOld.Clone ();
298 tNew.SetDates (now, now - toExpiration + toIssue);
302 public static void SetAuthCookie (string userName, bool createPersistentCookie)
305 SetAuthCookie (userName, createPersistentCookie, cookiePath);
308 public static void SetAuthCookie (string userName, bool createPersistentCookie, string strCookiePath)
310 HttpContext context = HttpContext.Current;
312 throw new HttpException ("Context is null!");
314 HttpResponse response = context.Response;
315 if (response == null)
316 throw new HttpException ("Response is null!");
318 response.Cookies.Add (GetAuthCookie (userName, createPersistentCookie, strCookiePath));
321 public static void SignOut ()
325 HttpContext context = HttpContext.Current;
327 throw new HttpException ("Context is null!");
329 HttpResponse response = context.Response;
330 if (response == null)
331 throw new HttpException ("Response is null!");
333 response.Cookies.MakeCookieExpire (cookieName, cookiePath);
336 public static string FormsCookieName
344 public static string FormsCookiePath
352 public static bool RequireSSL {
359 public static bool SlidingExpiration {
362 return slidingExpiration;