January 2009 Archives

In early 2007, I started using WCF on a daily basis while it and Visual Studio 2008 were still in beta.  It was great to get the jump on that technology, but it was really hard to find information when I bumped up against bugs or uncertainties.  Now, two years later, I find myself in the same boat again, but this time with Geneva.  Right now there isn't much info coming out of Redmond, but this is the time I need it not in 11 months when this stuff RTMs.  For this reason, I decided to start collecting all the useful sources of information that I've found related to Geneva framework, server, and Cardspace.

Sources of Information to Get Started

Before you do anything, check out these documents and videos:

Obscure Information

Once you've read and reread the above like 50 times, and you're totally desperate for more info, check out these feeds:

Bloggers Talking About Geneva

I'll update this list as I find more.  If you have some pearls, please post a comment with a link.
Lately, I've been doing a lot of work with WS-Trust, WS-Security, WS-Federation, and Information Cards using the Geneva framework and Cardspace Geneva.  It's been really fun and challenging.  Yesterday, however, I ran into a weird issue with the first beta that cost me and three other team members our coffee breaks.

We needed to create a passive STS that allowed users to authenticate using multiple types of credentials.  As our starting point, we used the "Web Application with Multiple Sign In Methods" sample that is included with the Geneva framework SDK, but altered it to use passive redirect.  To do this, we changed the Web.config of the Relying Party (RP) to include the FormsAuthenticationModule (FAM), removed the superfluous ASP.NET Web control from the RP's Web form, and a few other minor tweaks.  (See the claims-aware Web application getting started sample for a complete example of an RP that uses passive redirect.)

After being sent to the STS, the user was presented with a page where they could select their authentication type -- Web forms or info card -- a switchboard if you will.  Each supported type had a button with an event handler that would redirect the user (again) to another page that dealt only with that type of authentication.  The query string was also tacked on before shipping them off. 

In the page that handled Web forms authentication, there was an event handler that fired after logging in.  It redirected the user (dizzying isn't it?) to another page that contained a FederatedPassiveTokenService ASP.NET Web control.  This control is used to surface the custom STS and should do the following:

  1. Detect the presence of a cookie with a certain name and value and,
  2. Redirects the caller back to the RP with the necessary RSTR.
The problem was that it wasn't doing that.  For some reason the cookie wasn't being created, the control didn't find it, and silently did nothing.  The configuration of the IIS application prevented unauthorized access, and sent the user back to the login page.  After submitting the user name and password again, the event handler fired, authentication was successful, and the caller was once again redirected to the page with the FederatedPassiveTokenService control on it.  The second time, however, an error page was displayed saying that access was denied due to the server configuration (error number 401.2).  Of course, the user wasn't allowed to see anything, but they should not have needed to; they should have been sent back to the RP with the cookie.

There in lies the rub.  The cookie wasn't being created.  If it was, the custom STS would have seen it and used the info in the query string to send the authenticated caller on his way.  The workaround: force the cookie to be created explicitly in the event handler of the login form rather than relying on the framework to do it.  This was achieved using this code:

    3 protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)

    4     {

    5         if (FormsAuthentication.Authenticate(Login1.UserName, Login1.Password))

    6         {

    7             string redirectUrl = FormsAuthentication.GetRedirectUrl(Login1.UserName, false);

    8             HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,

    9                 FormsAuthentication.Encrypt(new FormsAuthenticationTicket(Login1.UserName, false, 20)));


   11             Response.Cookies.Add(cookie);

   12             Response.Redirect(redirectUrl + "?" + Request.QueryString);

   13         }

   14     }

Here's the weird thing.  The cookie actually was created sometimes without this explicit code.  We only found the problem after deleting the cookie, so that we could work on logging in using Carspace.  After some tweaking, we got it to create the cookie automatically again.  Then we deleted the cookie, and, as before, subsequent authentication attempts resulted in no cookie and an error.  It wasn't until we used the code above to force the cookie creation that it started to work consistently. The only reason that we could find for this inconsistency was the beta nature of the framework.  This oddity cost four of us our coffee breaks trying to diagnose the problem and work around it.  That's the price you pay for living on the bleeding edge I guess.