A Walk on the Pequest Fill

County route 517 leaves Hackettstown, NJ as High Street, heading north. Not far past the huge Mars candy plant on the outskirts of town the road lifts itself up and over the shoulder of Allamuchy Mt., and then it is just 517, the road to Andover and Sparta. As you drive northward past the little crossroads town of Allamuchy,sheltering in the shadow of two highways and what is really a large hill, a broad valley opens up on your left. It is typical northern New Jersey farmland, rolling and rich, stitched into quilted patterns by old stone walls, bits of forest, and wandering streams. This is the valley of the Pequest River,  which has its start in Stickles Pond high on the slopes of Wawayanda, where they call it a creek. Down here in Warren County it is a river, whatever those Sussexers might say.

Continue reading

The Case of the Expiring Auth Ticket

Consider the following scenario: a rich client communicates over the Internet with an ASP.NET service that does not use forms authentication, and also sends requests to a content site that does use forms auth. Initial user authentication is performed by the client and service using a proprietary protocol. The service then creates an authentication ticket for the user that will permit access to the content site. The ticket is created using the FormsAuthentication.GetAuthCookie method, and passed back to the client to be used in later requests. On the content site the web.config file specifies that the authentication ticket timeout is 120 minutes on a sliding reset, however the ticket consistently expires in 30 minutes. What’s wrong?

My colleagues and I recently faced this exact problem on a current development project. In researching the issue we first made sure that our web.config settings were correct. Using the IIS service manager we verified that the values for the timeout, sliding expiration, cookie name, and machine keys were being picked up and used by the server. The timeout was clearly being set to 120 minutes, and everything else was correct, but still the ticket was expiring at 30 minutes. Obviously our config files weren’t at fault.

Configuration can be a tricky thing in ASP.NET, however, and sometimes the properties that end up driving your system are not the ones you thought were at the wheel. Further research led us to a Microsoft support article on forms auth tickets and cookies. The last paragraph in the article contained the following statement:

“If the forms authentication ticket is manually generated, the time-out property of the ticket will override the value that is set in the configuration file.”

Aha! Surely we had the culprit in hand. Someone had set an explicit timeout in the code that generated the cookie, and that timeout was overriding the values set in web.config. It made perfect sense, except for the fact that when we opened up the code the line in question did not set a timeout. In fact we could see no way of specifying a timeout in the call to GetAuthCookie. Lacking an explicit timeout the value in web.config should be used. We were prepared to head back to the drawing board, or at least Google, when one of my smarter coworkers wondered if, in fact, some default timeout was being set during the call to GetAuthCookie? With the help of a friend who had a copy of .NET Reflector handy we peeled System.Web.Security. Ultimately the public versions of FormsAuthentication.GetAuthCookie call a private overload. The disassembly of that method looks like this:

private static HttpCookie GetAuthCookie(string userName, bool createPersistentCookie,
	string strCookiePath, bool hexEncodedTicket)
	if (userName == null)
		userName = string.Empty;
	if ((strCookiePath == null) || (strCookiePath.Length < 1))
		strCookiePath = FormsCookiePath;
	FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, userName,
		DateTime.Now, DateTime.Now.AddMinutes((double) _Timeout),
		createPersistentCookie, string.Empty, strCookiePath);
	string str = Encrypt(ticket, hexEncodedTicket);
	if ((str == null) || (str.Length < 1))
		throw new HttpException(SR.GetString("Unable_to_encrypt_cookie_ticket"));
	HttpCookie cookie = new HttpCookie(FormsCookieName, str);
	cookie.HttpOnly = true;
	cookie.Path = strCookiePath;
	cookie.Secure = _RequireSSL;
	if (_CookieDomain != null)
		cookie.Domain = _CookieDomain;
	if (ticket.IsPersistent)
		cookie.Expires = ticket.Expiration;
	return cookie;

The part that caught our eye right away was the constructor call to create the FormsAuthenticationTicket. Specifically the fourth argument to the call, which is calculated from DateTime.Now.AddMinutes((double) _Timeout). Hmm, _Timeout, a private field, and obviously relevant to our issue. But where was it getting a value? The first line of GetAuthCookie is a call to FormsAuthentication.Initialize, and so we disassembled that, too. In it we found the following line:

_Timeout = (int) authentication.Forms.Timeout.TotalMinutes;

So the timeout value being passed to the constructor was coming from the forms element of the authentication section in our web.config! But we had already verified the web.config was correct… errrm… actually, we had only verified that the web.config values on the content site were correct. The cookie was being created in the service implementation, a different site altogether, and one with its own configuration. When we looked in that web.config we saw that the forms element did not specify a timeout for the ticket. Since it didn’t the value that was ultimately assigned to _Timeout and passed to the constructor for the ticket was the default, and that is… you guessed it, 30 minutes.

Ultimately the solution that worked was to specify the same timeout value in web.config both on the content site where the ticket would be used, and in the service implementation where it was created. And while having a dependency between those two was less than satisfying, getting this vexing bug to go away more than made up for it.

Just a Book

I struck out three times at the library this week. One was a Ben Bova novel about two brothers on opposite sides of the stem cell/cloning/immortality issue. It started pretty well, but then kept switching between first person protagonists in the first three chapters. I like the first person perspective, but I guess I don’t like to get into a new head with every chapter. I might give this one another try because Bova is a fine writer whose work I have enjoyed in the past.

The other two looked like good stories too, and the one I began reading started well. However, what I had missed in both cases, and what was not advertised anywhere on the books’ jackets, was that both were buried in the middle of an -ilogy. One was a second book, and the other a third. This fact was not made clear in the frontispieces or title pages either. You really couldn’t figure it out until you read the back cover testimonials carefully. I took both back to the library and made a desultory effort to find the beginnings of each story in the catalog, but our small library either never had the earlier novels, or doesn’t have them anymore. Perhaps the buyers for the library were deceived as easily as I was.

I don’t like to jump into the middle of a multivolume story. In fact, I’m almost to the point where I just disdain -ilogies alltogether. I was introduced to them by Tolkien at the age of 10 or 11, and ruined for them by Jordan at the age of 45, when, after fifteen years of rambling through eleven increasingly incoherent and plodding volumes in the Wheel of Time series, the author departed the mortal plane without finishing it. I think WoT would have made a really great trilogy.

These days it seems more than half the new volumes at the library are part of a series. If I see “Fifth Volume in the Dreams of Balthazar Chronicles” I just put the damn thing back on the shelf, only slightly more quickly than I would if it were the first volume. My aversion is selective. I’ve been known to go out of my way to get complete sets of O’Brien, Gemmell, and Cornwell, not to mention Mary Stewart. In O’Brien’s case the Aubrey-Maturin books actually stand pretty well on their own, and as for Gemmell, Cornwell, and Stewart they are just worth it, and how. But my weariness of the -ilogy marketing approach just makes it a lot harder to win me over. I’d like to see more really good single volume stories. I’ll be fifty years old in a year and a half or so; I can’t even be sure of living through another Robert Jordan.

And while I am on the subject of books it would be remiss of me not to mention the most lamentable trend of all, which is neatly encapsulated by the title of a book I was looking at in the library last night: “Robert Ludlum’s The Bourne Sanction by Eric van Lustbader.” Robert Ludlum cannot write any more Bourne novels, because he is dead, and van Lustbader shouldn’t be writing them either. “Tom Clancy” is another one. He’s still alive as far as I know, but 95% of the stuff I see with his name on it was written by someone else. Hopefully, the publishing industry has been learning along with the rest of us that pursuit of money for it’s own sake isn’t the point. I’d just like to see good books. The rest of the business will take care of itself.