A client of mine wants to provide single sign-on (SSO) capabilities in their web application, so that users don't have to type in their domain password when authenticating to the application. The twist? Only some users of the application use SSO: the rest have accounts that exist only in the application database. So we couldn't just flip on “integrated authentication” in IIS and party on. But with the help of Keith Brown, I was able to figure out a pretty nifty solution.
The trick was realizing that if you enable both “anonymous“ and “integrated“ authentication for a particular virtual directory, the browser won't try to authenticate to the web server until it receives a 401 (Unauthorized) back from the web server. But you can issue your own 401 any time you like! So what I did was to just set up Forms authentication as normal, but also provided a checkbox on the login form that said, “Use my network credentials.” Then, in my login form, I did something like this:
public
class Login : Page {
protected Label ErrorMessageLabel;
protected TextBox UsernameTextBox;
protected TextBox PasswordTextBox;
protected CheckBox CheckBox1;
public void Page_Load(object o, EventArgs e) {
if (IsPostBack) {
string authenticatedUser = null;
if (CheckBox1.Checked) // Use their network credentials
{
string user = Request.ServerVariables["LOGON_USER"];
if (user.Length == 0) // They haven't provided credentials yet
{
Response.StatusCode = 401;
Response.StatusDescription = "Unauthorized";
Response.End();
}
else // They have
{
authenticatedUser = user;
}
}
else // Use the username and password they provide
{
if (IsPasswordOK(UsernameTextBox.Text, PasswordTextBox.Text)) {
authenticatedUser = UsernameTextBox.Text;
}
}
if (authenticatedUser != null) // They authenticated successfully
{
// Issue the Forms Auth cookie and send them on their way
FormsAuthentication.RedirectFromLoginPage(authenticatedUser, false);
}
else // They didn't
{
ErrorMessageLabel.Text = "Invalid username or bad password. Please try again.";
}
}
}
}
What this does is - when the user submits the login - check to see whether they want to authenticate by providing a username and password (normal Forms authentication) or whether they want to authenticate automatically, using their logged-in credentials. Right now, I'm figuring this out by having them explicity check a checkbox, but I do lots of other things. For example, I could have them always enter their username, and then go look in the database to see whether they're supposed to get a SSO login or a normal one. Or I could have them check the checkbox once and remember their settings forever after in a cookie.
Whatever mechanism I decide on, the trick here is that I can force the browser to authenticate by sending back a 401. Then, in subsequent visits, I can check the LOGON_USER server variable to see if the authentication was successful or not. If it is, I'm perfectly welcome to issue them a valid Forms Authentication login, secure in the knowledge that the user has proven knowledge of their password to IIS already.
If the user is using IE, the authentication will happen automatically, using whatever credentials they're logged in to the client machine with. It works in Firefox, too, but they get that little username/password popup dialog box. Oh well - maybe the Firefox people will add auto login in a future release, or someone will write an extension. But failing that, providing SSO only to IE users is good enough for us.
Posted
Jul 24 2004, 08:40 AM
by
craig-andera