2004-06-12 Pedro Mart�nez Juli� <yoros@wanadoo.es>
[mono.git] / mcs / class / System.Web / System.Web.Security / FormsAuthentication.cs
1 //
2 // System.Web.Security.FormsAuthentication
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2002,2003 Ximian, Inc (http://www.ximian.com)
8 //
9
10 using System;
11 using System.Collections;
12 using System.IO;
13 using System.Security.Cryptography;
14 using System.Text;
15 using System.Web;
16 using System.Web.Configuration;
17 using System.Web.Util;
18
19 namespace System.Web.Security
20 {
21         public sealed class FormsAuthentication
22         {
23                 static string authConfigPath = "system.web/authentication";
24                 static bool initialized;
25                 static string cookieName;
26                 static string cookiePath;
27                 static int timeout;
28                 static FormsProtectionEnum protection;
29 #if NET_1_1
30                 static bool requireSSL;
31                 static bool slidingExpiration;
32 #endif
33
34                 // same names and order used in xsp
35                 static string [] indexFiles = { "index.aspx",
36                                                 "Default.aspx",
37                                                 "default.aspx",
38                                                 "index.html",
39                                                 "index.htm" };
40
41                 public static bool Authenticate (string name, string password)
42                 {
43                         if (name == null || password == null)
44                                 return false;
45
46                         Initialize ();
47                         HttpContext context = HttpContext.Current;
48                         if (context == null)
49                                 throw new HttpException ("Context is null!");
50
51                         AuthConfig config = context.GetConfig (authConfigPath) as AuthConfig;
52                         Hashtable users = config.CredentialUsers;
53                         string stored = users [name] as string;
54                         if (stored == null)
55                                 return false;
56
57                         switch (config.PasswordFormat) {
58                         case FormsAuthPasswordFormat.Clear:
59                                 /* Do nothing */
60                                 break;
61                         case FormsAuthPasswordFormat.MD5:
62                                 stored = HashPasswordForStoringInConfigFile (stored, "MD5");
63                                 break;
64                         case FormsAuthPasswordFormat.SHA1:
65                                 stored = HashPasswordForStoringInConfigFile (stored, "SHA1");
66                                 break;
67                         }
68
69                         return (password == stored);
70                 }
71
72                 public static FormsAuthenticationTicket Decrypt (string encryptedTicket)
73                 {
74                         if (encryptedTicket == null || encryptedTicket == String.Empty)
75                                 throw new ArgumentException ("Invalid encrypted ticket", "encryptedTicket");
76
77                         Initialize ();
78                         byte [] bytes = MachineKeyConfigHandler.GetBytes (encryptedTicket, encryptedTicket.Length);
79                         string decrypted = Encoding.ASCII.GetString (bytes);
80                         FormsAuthenticationTicket ticket = null;
81                         try {
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);
85
86
87                                 ticket = new FormsAuthenticationTicket (Int32.Parse (values [0]),
88                                                                         values [1],
89                                                                         new DateTime (Int64.Parse (values [2])),
90                                                                         new DateTime (Int64.Parse (values [3])),
91                                                                         (values [4] == "1"),
92                                                                         values [5],
93                                                                         values [6]);
94                         } catch (Exception) {
95                                 ticket = null;
96                         }
97
98                         return ticket;
99                 }
100
101                 public static string Encrypt (FormsAuthenticationTicket ticket)
102                 {
103                         if (ticket == null)
104                                 throw new ArgumentNullException ("ticket");
105
106                         Initialize ();
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
125                 }
126
127                 public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie)
128                 {
129                         return GetAuthCookie (userName, createPersistentCookie, null);
130                 }
131
132                 public static HttpCookie GetAuthCookie (string userName, bool createPersistentCookie, string strCookiePath)
133                 {
134                         Initialize ();
135
136                         if (userName == null)
137                                 userName = String.Empty;
138
139                         if (strCookiePath == null || strCookiePath.Length == 0)
140                                 strCookiePath = cookiePath;
141
142                         DateTime now = DateTime.Now;
143                         DateTime then;
144                         if (createPersistentCookie)
145                                 then = now.AddYears (50);
146                         else
147                                 then = now.AddMinutes (timeout);
148
149                         FormsAuthenticationTicket ticket = new FormsAuthenticationTicket (1,
150                                                                                           userName,
151                                                                                           now,
152                                                                                           then,
153                                                                                           createPersistentCookie,
154                                                                                           String.Empty,
155                                                                                           cookiePath);
156
157                         if (!createPersistentCookie)
158                                 then = DateTime.MinValue;
159
160                         return new HttpCookie (cookieName, Encrypt (ticket), strCookiePath, then);
161                 }
162
163                 public static string GetRedirectUrl (string userName, bool createPersistentCookie)
164                 {
165                         if (userName == null)
166                                 return null;
167
168                         //TODO: what's createPersistentCookie used for?
169                         Initialize ();
170                         HttpRequest request = HttpContext.Current.Request;
171                         string returnUrl = request ["RETURNURL"];
172                         if (returnUrl != null)
173                                 return returnUrl;
174
175                         AuthConfig authConfig = context.GetConfig (authConfigPath) as AuthConfig;
176                         if (authConfig.LoginUrl != null) {
177                                 return authConfig.LoginUrl;
178                         }
179
180                         returnUrl = request.ApplicationPath;
181                         string apppath = request.PhysicalApplicationPath;
182                         bool found = false;
183
184                         foreach (string indexFile in indexFiles) {
185                                 string filePath = Path.Combine (apppath, indexFile);
186                                 if (File.Exists (filePath)) {
187                                         returnUrl = UrlUtils.Combine (returnUrl, indexFile);
188                                         found = true;
189                                         break;
190                                 }
191                         }
192
193                         if (!found)
194                                 returnUrl = UrlUtils.Combine (returnUrl, "index.aspx");
195
196                         return returnUrl;
197                 }
198
199                 static string GetHexString (string str)
200                 {
201                         return GetHexString (Encoding.ASCII.GetBytes (str));
202                 }
203
204                 static string GetHexString (byte [] bytes)
205                 {
206                         StringBuilder result = new StringBuilder (bytes.Length * 2);
207                         foreach (byte b in bytes)
208                                 result.AppendFormat ("{0:x2}", (int) b);
209
210                         return result.ToString ();
211                 }
212
213                 public static string HashPasswordForStoringInConfigFile (string password, string passwordFormat)
214                 {
215                         if (password == null)
216                                 throw new ArgumentNullException ("password");
217
218                         if (passwordFormat == null)
219                                 throw new ArgumentNullException ("passwordFormat");
220
221                         byte [] bytes;
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));
226                         } else {
227                                 throw new ArgumentException ("The format must be either MD5 or SHA1", "passwordFormat");
228                         }
229
230                         return GetHexString (bytes);
231                 }
232
233                 public static void Initialize ()
234                 {
235                         if (initialized)
236                                 return;
237
238                         lock (typeof (FormsAuthentication)) {
239                                 if (initialized)
240                                         return;
241
242                                 HttpContext context = HttpContext.Current;
243                                 if (context == null)
244                                         throw new HttpException ("Context is null!");
245
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;
252 #if NET_1_1
253                                         requireSSL = authConfig.RequireSSL;
254                                         slidingExpiration = authConfig.SlidingExpiration;
255 #endif
256                                 } else {
257                                         cookieName = ".MONOAUTH";
258                                         timeout = 30;
259                                         cookiePath = "/";
260                                         protection = FormsProtectionEnum.All;
261 #if NET_1_1
262                                         slidingExpiration = true;
263 #endif
264                                 }
265
266                                 initialized = true;
267                         }
268                 }
269
270                 public static void RedirectFromLoginPage (string userName, bool createPersistentCookie)
271                 {
272                         RedirectFromLoginPage (userName, createPersistentCookie, null);
273                 }
274
275                 public static void RedirectFromLoginPage (string userName, bool createPersistentCookie, string strCookiePath)
276                 {
277                         if (userName == null)
278                                 return;
279
280                         Initialize ();
281                         SetAuthCookie (userName, createPersistentCookie, strCookiePath);
282                         HttpResponse resp = HttpContext.Current.Response;
283                         resp.Redirect (GetRedirectUrl (userName, createPersistentCookie), false);
284                 }
285
286                 public static FormsAuthenticationTicket RenewTicketIfOld (FormsAuthenticationTicket tOld)
287                 {
288                         if (tOld == null)
289                                 return null;
290
291                         DateTime now = DateTime.Now;
292                         TimeSpan toIssue = now - tOld.IssueDate;
293                         TimeSpan toExpiration = tOld.Expiration - now;
294                         if (toExpiration > toIssue)
295                                 return tOld;
296
297                         FormsAuthenticationTicket tNew = tOld.Clone ();
298                         tNew.SetDates (now, now - toExpiration + toIssue);
299                         return tNew;
300                 }
301
302                 public static void SetAuthCookie (string userName, bool createPersistentCookie)
303                 {
304                         Initialize ();
305                         SetAuthCookie (userName, createPersistentCookie, cookiePath);
306                 }
307
308                 public static void SetAuthCookie (string userName, bool createPersistentCookie, string strCookiePath)
309                 {
310                         HttpContext context = HttpContext.Current;
311                         if (context == null)
312                                 throw new HttpException ("Context is null!");
313
314                         HttpResponse response = context.Response;
315                         if (response == null)
316                                 throw new HttpException ("Response is null!");
317
318                         response.Cookies.Add (GetAuthCookie (userName, createPersistentCookie, strCookiePath));
319                 }
320
321                 public static void SignOut ()
322                 {
323                         Initialize ();
324
325                         HttpContext context = HttpContext.Current;
326                         if (context == null)
327                                 throw new HttpException ("Context is null!");
328
329                         HttpResponse response = context.Response;
330                         if (response == null)
331                                 throw new HttpException ("Response is null!");
332
333                         response.Cookies.MakeCookieExpire (cookieName, cookiePath);
334                 }
335
336                 public static string FormsCookieName
337                 {
338                         get {
339                                 Initialize ();
340                                 return cookieName;
341                         }
342                 }
343
344                 public static string FormsCookiePath
345                 {
346                         get {
347                                 Initialize ();
348                                 return cookiePath;
349                         }
350                 }
351 #if NET_1_1
352                 public static bool RequireSSL {
353                         get {
354                                 Initialize ();
355                                 return requireSSL;
356                         }
357                 }
358
359                 public static bool SlidingExpiration {
360                         get {
361                                 Initialize ();
362                                 return slidingExpiration;
363                         }
364                 }
365 #endif
366         }
367 }
368