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;
51 static bool requireSSL;
52 static bool slidingExpiration;
55 // same names and order used in xsp
56 static string [] indexFiles = { "index.aspx",
62 public static bool Authenticate (string name, string password)
64 if (name == null || password == null)
68 HttpContext context = HttpContext.Current;
70 throw new HttpException ("Context is null!");
72 AuthConfig config = context.GetConfig (authConfigPath) as AuthConfig;
73 Hashtable users = config.CredentialUsers;
74 string stored = users [name] as string;
78 switch (config.PasswordFormat) {
79 case FormsAuthPasswordFormat.Clear:
82 case FormsAuthPasswordFormat.MD5:
83 stored = HashPasswordForStoringInConfigFile (stored, "MD5");
85 case FormsAuthPasswordFormat.SHA1:
86 stored = HashPasswordForStoringInConfigFile (stored, "SHA1");
90 return (password == stored);
93 public static FormsAuthenticationTicket Decrypt (string encryptedTicket)
95 if (encryptedTicket == null || encryptedTicket == String.Empty)
96 throw new ArgumentException ("Invalid encrypted ticket", "encryptedTicket");
99 byte [] bytes = MachineKeyConfigHandler.GetBytes (encryptedTicket, encryptedTicket.Length);
100 string decrypted = Encoding.ASCII.GetString (bytes);
101 FormsAuthenticationTicket ticket = null;
103 string [] values = decrypted.Split ((char) 1, (char) 2, (char) 3, (char) 4, (char) 5, (char) 6, (char) 7);
104 if (values.Length != 8)
105 throw new Exception (values.Length + " " + encryptedTicket);
108 ticket = new FormsAuthenticationTicket (Int32.Parse (values [0]),
110 new DateTime (Int64.Parse (values [2])),
111 new DateTime (Int64.Parse (values [3])),
115 } catch (Exception) {
122 public static string Encrypt (FormsAuthenticationTicket ticket)
125 throw new ArgumentNullException ("ticket");
128 StringBuilder allTicket = new StringBuilder ();
129 allTicket.Append (ticket.Version);
130 allTicket.Append ('\u0001');
131 allTicket.Append (ticket.Name);
132 allTicket.Append ('\u0002');
133 allTicket.Append (ticket.IssueDate.Ticks);
134 allTicket.Append ('\u0003');
135 allTicket.Append (ticket.Expiration.Ticks);
136 allTicket.Append ('\u0004');
137 allTicket.Append (ticket.IsPersistent ? '1' : '0');
138 allTicket.Append ('\u0005');
139 allTicket.Append (ticket.UserData);
140 allTicket.Append ('\u0006');
141 allTicket.Append (ticket.CookiePath);
142 allTicket.Append ('\u0007');
143 //if (protection == FormsProtectionEnum.None)
144 return GetHexString (allTicket.ToString ());
145 //TODO: encrypt and validate
148 public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie)
150 return GetAuthCookie (userName, createPersistentCookie, null);
153 public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie, string strCookiePath)
157 if (userName == null)
158 userName = String.Empty;
160 if (strCookiePath == null || strCookiePath.Length == 0)
161 strCookiePath = cookiePath;
163 DateTime now = DateTime.Now;
165 if (createPersistentCookie)
166 then = now.AddYears (50);
168 then = now.AddMinutes (timeout);
170 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket (1,
174 createPersistentCookie,
178 if (!createPersistentCookie)
179 then = DateTime.MinValue;
181 return new HttpCookie (cookieName, Encrypt (ticket), strCookiePath, then);
184 public static string GetRedirectUrl (string userName, bool createPersistentCookie)
186 if (userName == null)
189 //TODO: what's createPersistentCookie used for?
191 HttpRequest request = HttpContext.Current.Request;
192 string returnUrl = request ["RETURNURL"];
193 if (returnUrl != null)
196 returnUrl = request.ApplicationPath;
197 string apppath = request.PhysicalApplicationPath;
200 foreach (string indexFile in indexFiles) {
201 string filePath = Path.Combine (apppath, indexFile);
202 if (File.Exists (filePath)) {
203 returnUrl = UrlUtils.Combine (returnUrl, indexFile);
210 returnUrl = UrlUtils.Combine (returnUrl, "index.aspx");
215 static string GetHexString (string str)
217 return GetHexString (Encoding.ASCII.GetBytes (str));
220 static string GetHexString (byte [] bytes)
222 StringBuilder result = new StringBuilder (bytes.Length * 2);
223 foreach (byte b in bytes)
224 result.AppendFormat ("{0:x2}", (int) b);
226 return result.ToString ();
229 public static string HashPasswordForStoringInConfigFile (string password, string passwordFormat)
231 if (password == null)
232 throw new ArgumentNullException ("password");
234 if (passwordFormat == null)
235 throw new ArgumentNullException ("passwordFormat");
238 if (String.Compare (passwordFormat, "MD5", true) == 0) {
239 bytes = MD5.Create ().ComputeHash (Encoding.ASCII.GetBytes (password));
240 } else if (String.Compare (passwordFormat, "SHA1", true) == 0) {
241 bytes = SHA1.Create ().ComputeHash (Encoding.ASCII.GetBytes (password));
243 throw new ArgumentException ("The format must be either MD5 or SHA1", "passwordFormat");
246 return GetHexString (bytes);
249 public static void Initialize ()
254 lock (typeof (FormsAuthentication)) {
258 HttpContext context = HttpContext.Current;
260 throw new HttpException ("Context is null!");
262 AuthConfig authConfig = context.GetConfig (authConfigPath) as AuthConfig;
263 if (authConfig != null) {
264 cookieName = authConfig.CookieName;
265 timeout = authConfig.Timeout;
266 cookiePath = authConfig.CookiePath;
267 protection = authConfig.Protection;
269 requireSSL = authConfig.RequireSSL;
270 slidingExpiration = authConfig.SlidingExpiration;
273 cookieName = ".MONOAUTH";
276 protection = FormsProtectionEnum.All;
278 slidingExpiration = true;
286 public static void RedirectFromLoginPage (string userName, bool createPersistentCookie)
288 RedirectFromLoginPage (userName, createPersistentCookie, null);
291 public static void RedirectFromLoginPage (string userName, bool createPersistentCookie, string strCookiePath)
293 if (userName == null)
297 SetAuthCookie (userName, createPersistentCookie, strCookiePath);
298 HttpResponse resp = HttpContext.Current.Response;
299 resp.Redirect (GetRedirectUrl (userName, createPersistentCookie), false);
302 public static FormsAuthenticationTicket RenewTicketIfOld (FormsAuthenticationTicket tOld)
307 DateTime now = DateTime.Now;
308 TimeSpan toIssue = now - tOld.IssueDate;
309 TimeSpan toExpiration = tOld.Expiration - now;
310 if (toExpiration > toIssue)
313 FormsAuthenticationTicket tNew = tOld.Clone ();
314 tNew.SetDates (now, now - toExpiration + toIssue);
318 public static void SetAuthCookie (string userName, bool createPersistentCookie)
321 SetAuthCookie (userName, createPersistentCookie, cookiePath);
324 public static void SetAuthCookie (string userName, bool createPersistentCookie, string strCookiePath)
326 HttpContext context = HttpContext.Current;
328 throw new HttpException ("Context is null!");
330 HttpResponse response = context.Response;
331 if (response == null)
332 throw new HttpException ("Response is null!");
334 response.Cookies.Add (GetAuthCookie (userName, createPersistentCookie, strCookiePath));
337 public static void SignOut ()
341 HttpContext context = HttpContext.Current;
343 throw new HttpException ("Context is null!");
345 HttpResponse response = context.Response;
346 if (response == null)
347 throw new HttpException ("Response is null!");
349 response.Cookies.MakeCookieExpire (cookieName, cookiePath);
352 public static string FormsCookieName
360 public static string FormsCookiePath
368 public static bool RequireSSL {
375 public static bool SlidingExpiration {
378 return slidingExpiration;