Scott Hanselman

The Big News - Update #1

July 15, '05 Comments [29] Posted in Musings
Sponsored By

Had the second ultrasound today and everything looks good, it's a boy!

Baby2

Now playing: Matisyahu - Beat Box

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

I'm in love with FinePrint

July 12, '05 Comments [10] Posted in Reviews | Tools
Sponsored By

FineprintOMG, I'm in love with FinePrint. This is the kind of tool that BillG should just bake into the OS. Just give these folks a million bucks and build it in. I'm so sick of 50 different printer drivers all behaving differently. FinePrint totally evens the playing field and has made my life (and my move to GTD) way easier.

It's a "fake" (virtual) printer driver that basically sits between you and your real printer. You print everything to FinePrint and it gives you an opportunity to mess with the pending print job.

Most interestingly, you can change 1:1 print jobs to 2, 4 or 8 up. This ROCKS. I can take 4 page long meeting agendas and print them on one page to any printer. (Some expensive copier/printer drivers support this in the driver, FinePrint works with all printers.)

How many times have you seen hundreds of sheets of paper (color ink, even) sitting printed in your company's copy room/office that one sided. Seriously, makes my heart ache. With this thing you can print double sided easily and do booklets as well.

Now that I'm all about the 43 Folders, I'm actually printing more, but with FinePrint I'm using less paper. It makes filing really easy.

Other things about FinePrint that make me happy:

  • You can also print to the Clipboard. Ya, read that twice.
  • Adjust the margins AFTER the fact.
  • Create multiple "FinePrinters" that each have their own settings. One for 2 up, one for 8 up, etc.
  • You can delete pages from Print Jobs after the fact.
  • It can save print jobs and replay them like Tivo for Printers.
  • Convert color to black or remove all graphics for fast web page printing.
  • Build custom watermarks and letterhead that is automatically added to your printed output.

Well, I'm gushing, but I'm digging it.

Now playing: Counting Crows - Einstein On the Beach (For an Eggman)

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

New FormsAuthentication.SignOut behavior in ASP.NET 2.0

July 12, '05 Comments [6] Posted in ASP.NET | DasBlog
Sponsored By

Calling FormsAuthentication.SignOut() removes the FormsAuthentication cookies in ASP.NET 1.1. Sometimes folks call it from their Login page, like this:

if (!Page.IsPostBack)
{
    FormsAuthentication.SignOut();
}

This says, "If this is a fresh load of this page, clear out the authentication cookies."

If this seems like a reasonable thing, that's because it is. However, if you run an ASP.NET 1.1 site under ASP.NET 2.0 without recompiling, as a number of dasBlog users do, you may get some odd behavior.

You'll visit the Login.aspx page and redirect to the Login.aspx page forever in a loop...it will make your URL look like this:

/Blog/login.aspx?ReturnUrl=%2fBlog%2flogin.aspx%3fReturnUrl%3d%252fBlog%252flogin.aspx%
253fReturnUrl%253d%25252fBlog%25252flogin.aspx%25253fReturnUrl%25253d%2525252fBlog%
525252flogin.aspx%2525253fReturnUrl%2525253d%252525252fBlog%252525252flogin.aspx%
52525253fReturnUrl%252525253d%25252525252fBlog%25252525252flogin.aspx%25252525253fReturnUrl%
5252525253d%2525252525252fBlog%2525252525252flogin.aspx%2525252525253fReturnUrl%2525252525253d%
52525252525252fBlog%252525252525252flogin.aspx%252525252525253fReturnUrl%252525252525253d%
5252525252525252fBlog%25252525252525252flogin.aspx%25252525252525253fReturnUrl%25252525252525253d%
525252525252525252fBlog%2525252525252525252flogin.aspx%2525252525252525253fReturnUrl%
525252525252525253d%252525252525252525252fBlog%252525252525252525252fLogin.aspx

Why? Because ASP.NET 2.0 add this code inside SignOut():

if (FormsAuthentication.CookieMode != HttpCookieMode.UseCookies)
{
    Response.Redirect(FormsAuthentication.GetLoginPage(null), false);
}

That's pretty interesting. If you call SignOut() it redirects you to the Login page, but only if your CookieMode isn't set to UseCookies. This is because ASP.NET 2.0 added support for cookieless FormsAuthentication. They store the auth information in the URL, and they redirect you because they want to clear the authentication info. Makes sense.

What doesn't make sense is why HttpCookieMode doesn't default to UseCookies. It defaults to Cookieless. Which is lovely under ASP.NET 2.0, but not under 1.1. It stays that way and confuses the system.

So, if you see this kind of infinite redirect with FormsAuthentication while running ASP.NET 1.1 applications under ASP.NET 2.0, you can add cookieless="UseCookies" to your <forms> element in web.config:

<forms cookieless="UseCookies" name=".DASBLOGAUTH" protection="All" timeout="60" path="/"/>

And then I went to sleep.

Now playing: Counting Crows - Angels of the Silences

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Weird Timeouts with custom ASP.NET FormsAuthentication

July 12, '05 Comments [7] Posted in ASP.NET | Bugs
Sponsored By

Ah, life. For me, in what I tend to do day to day, it always seems to come down to debugging weird stuff. So, here's something weird that happened today (actually it's been happening over the last week in QA).

Someone logs into an ASP.NET application successfully and does some stuff. They wait for 10.5 minutes. That means no clicking, just waiting. Then they click and get the next page successfully. Then the click on the NEXT (the second since they've been waiting) and get kicked out to the login page.

Since our FormsAuthentication stuff not only authorizes the user into ASP.NET but also carries with it tokens into other "session-like" systems, folks dug around in those systems initially looking at Audit data, logs, everything. It just doesn't make sense.

The FormsAuthentication timeout is set to 20 minutes and folks are getting "logged out" at 10.5 minutes. They set the timeout to 600 minutes and folks get kicked at 10.5 minutes. Is the timeout value being ignored?

As with most things, we return to first principles and pull out ieHttpHeaders. Why? Because in the context of a Web Application, clicking and looking at HTML only tells you that you clicked and look at some HTML.

TIP: When using ieHttpHeaders or any sniffers, turn OFF Images in your browser. Chances are they aren't the issue (although they might well be) but initially you'll save yourself some clutter in initial debugging.)

So, here's what we saw (abridged and #commented):

#LOGGING IN
POST /fooapp/Login.aspx HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: foo.corillian.net
Content-Length: 104
FI=fooapp&Destination=Accounts%2Ffooapp%2Fsummary.aspx&UserName=BAR

#LOGIN COOL, REDIRECTING and setting NEW AUTH COOKIE
HTTP/1.1 302 Found
Date: Mon, 11 Jul 2005 18:54:31 GMT
Server: Microsoft-IIS/6.0
Location:
http://foo.corillian.net/fooapp/somepath.aspx
Set-Cookie: AuthenticationTicket=32EFESNIPCC65879; path=/
Content-Type: text/html; charset=utf-8
Content-Length: 182

#GOING WHERE YOU SAID, RETURNING NEW AUTH COOKIE
GET /fooapp/somepath.aspx HTTP/1.1
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: foo.corillian.net
Cookie: AuthenticationTicket=32EFESNIPCC65879

#GOT TO WHERE I WAS GOING
HTTP/1.1 200 OK
Date: Mon, 11 Jul 2005 18:54:32 GMT
Server: Microsoft-IIS/6.0
Content-Type: text/html; charset=utf-8
Content-Length: 18224

WAIT 10.5 MINUTES HERE

#CLICK AND GO TO A NEW PAGE
GET /fooapp/newpage.aspx HTTP/1.1
Referer:
http://foo.corillian.net/fooapp/somepath.aspx
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: foo.corillian.net
Cookie: AuthenticationTicket=32EFESNIPCC65879;

#GOT TO THAT NEW PAGE
HTTP/1.1 200 OK
Date: Mon, 11 Jul 2005 19:05:18 GMT
Server: Microsoft-IIS/6.0
Set-Cookie: AuthenticationTicket=AB4665AB0B7495; path=/; secure
Content-Type: text/html; charset=utf-8
Content-Length: 75510

#CLICK AND GO TO THE SECOND PAGE SINCE WE WAITED
GET /fooapp/secondpage.aspx HTTP/1.1
Referer:
http://foo.corillian.net/fooapp/newpage.aspx
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: foo.corillian.net
Connection: Keep-Alive

#NO COOKIES WERE PASSED IN, REDIRECTED TO LOGIN!
HTTP/1.1 302 Found
Date: Mon, 11 Jul 2005 19:05:27 GMT
Server: Microsoft-IIS/6.0
Location:
http://foo.corillian.net/fooapp/login.aspx?ReturnUrl=%2ffooapp%2fnewpage.aspx
Content-Type: text/html; charset=utf-8
Content-Length: 209

Where did it all go wrong? Well, we waited 10.5 minutes the clicked. Notice after we waited, we passed in the AuthenticationTicket we had, "32EFESNIPCC65879." This is the one that we generated ourselves in Login.aspx via:

FormsAuthenticationTicket authTicket = new
    FormsAuthenticationTicket(1,   //version
    userName,                    // user name
    DateTime.Now,                  //creation
    DateTime.Now.AddMinutes(Timeout),  //Expiration
    false};
 
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName,encryptedTicket);   
HttpContext.Current.Response.Cookies.Add(authCookie);

This is a pretty typical thing to do when you're doing FormsAuthentication because you want might more control of the Ticket, or you might want to include user specific data in the cookie, etc.

But, after we waited and passed in the value we had, we got issued a NEW AuthenticationTicket with the value "AB4665AB0B7495" which is OK. Because the age of our original AuthenticationTicket was over 50% of the 20 minute timeout, the FormsAuthenticationModule was kind enough to renew the ticket. How nice of them. And a good thing too. They did it because the <forms> section of our web.config had slidingExpiration="true."

However, then the next GET request includes No AuthenticationTicket at all! Why not? Notice the difference between the first issuance and the second. The second issuing of the cookie included "secure" at its end. Why? Because of this setting in the web.config:

<forms requireSSL="true"
    slidingExpiration="true"
    loginUrl="~/login.aspx"
    name="AuthenticationTicket"
    protection="All"
    timeout="20" />

Ah! The first time the AuthenticationTicket was issued, it was issued by our custom code, and we didn't respect this setting! Later - 10.5 minutes later - when FormsAuthentication saw fit to issue a new cookie, they DID respect this flag.

Why was this a problem? Because in development were weren't running under SSL (https://). Had we been running under SSL this never would have been found. Had we gone live without SLL we would have seen flaky (read: impossible to reproduce) bugs with folks getting timeouts that didn't jive with our timeout settings.

The Fix - respect the RequiresSSL flag in the inital issuing of the AuthenticationTicket and we would have seen the problem in development immediately upon login:

// Create the authentication ticket            
FormsAuthenticationTicket authTicket = new
    FormsAuthenticationTicket(1,   //version
    userName,                    // user name
    DateTime.Now,                  //creation
    DateTime.Now.AddMinutes(Timeout),  //Expiration
    false}
 
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName,encryptedTicket);    
 
//Make sure we mark the cookie as "Secure" if RequireSSL is set in the web.config.
// If we don't, the FIRST issuing of this cookie with not be secure 
// (as we are the ones that did it) while the second issuing (when it's
// beign refreshed) will be secure. That would cause intermitant problems with 
// timeout-like behaviors around "timeout/2" minutes into the user's session.
authCookie.Secure = FormsAuthentication.RequireSSL;
HttpContext.Current.Response.Cookies.Add(authCookie);

And then I went to lunch.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Symantec Client Firewall is Psycho

July 10, '05 Comments [8] Posted in ASP.NET | DasBlog | Bugs
Sponsored By

Some how I got myself into using the Symantec Client Firewall instead of the Windows XP SP2 Firewall.

Today, while doing some local (localhost) debugging, I noticed that when I requested a file called http://localhost/dasblog/themes/elegante/banner.jpg, I was getting back NOTHING. No banner.

Ok, that's weird. So I fired up ieHttpHeaders and saw this (emphasis mine):

GET /DasBlog/themes/elegante/banner.jpg HTTP/1.1
Accept: */*
Accept-Language: en-us,tr;q=0.5
Accept-Encoding: gzip, deflate
If-Modified-Since: Fri, 25 Aug 2000 01:00:00 GMT; length=881
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7; .NET CLR 2.0.50215)
Host: localhost
Connection: Keep-Alive

HTTP/1.0 200 OK
Server: Netscape-Enterprise/2.0a
Pragma: No-cache
Date: Fri, 25 Aug 2000 23:00:00 GMT
Last-modified: Fri, 25 Aug 2000 01:00:00 GMT
Accept-Ranges: bytes
Content-length: 881
Content-type: image/gif

Holy crap! Do I have a Trojan? Spyware? I don't have Netscape anything running on my system. Notice the weird date, the weird Content-length for what was supposed to be a 35k file. I was getting all ready to look at who's got what open on what port, I ran Spyware scans with Search&Destroy and Microsoft AntiSpyware...then I thought, maybe it was AdBlock within FireFox. No, that doesn't make sense, I'm in IE. Who else could be messing around...

Damn you Norton! I disabled the Symantec Client Firewall and poof, there was my banner.

GET /DasBlog/themes/elegante/banner.jpg HTTP/1.1
Accept: */*
Accept-Language: en-us,tr;q=0.5
Accept-Encoding: gzip, deflate
If-Modified-Since: Fri, 25 Aug 2000 01:00:00 GMT; length=881
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Tablet PC 1.7; .NET CLR 2.0.50215)
Host: localhost
Connection: Keep-Alive

HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
X-Powered-By: ASP.NET
Date: Sun, 10 Jul 2005 05:43:40 GMT
Content-Type: image/jpeg
Accept-Ranges: bytes
Last-Modified: Sun, 10 Jul 2005 01:31:50 GMT
ETag: "ae93325ef84c51:8ad"
Content-Length: 36634

Turns out that Symantec Client Firewall has their own brand of ad blocking built in. That's not a bad thing except:

  • They block any graphic requested with the name "banner" anywhere in it - hence the fake HTTP Response.
  • The perform this blocking/sniffing even on requests to your OWN MACHINE (localhost)

Sigh. 7 minutes wasted. Hopefully this tidbit will save you a little time one day.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.