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:
- Detect the presence of a cookie with a certain name and value and,
- Redirects the caller back to the RP with the necessary RSTR.
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)
5 if (FormsAuthentication.Authenticate(Login1.UserName, Login1.Password))
7 string redirectUrl = FormsAuthentication.GetRedirectUrl(Login1.UserName, false);
8 HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
9 FormsAuthentication.Encrypt(new FormsAuthenticationTicket(Login1.UserName, false, 20)));
12 Response.Redirect(redirectUrl + "?" + Request.QueryString);
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.