
Introduction
I just implemented forms authentication for two applications who had to share the same user (so that one user wouldn’t have to log in twice). Most of what I am going to write here is straightforward and can be found on other sites, yet I wanted to detail the process I went through because my implementation was slightly different than most other tutorials on the subject. Here are the major steps.
Web Config
The web.config file will contain the configuration for the forms authentication. Here is the code I used:
<authentication mode="Forms">
<forms loginUrl="Login.aspx" enableCrossAppRedirects="true" defaultUrl="Default.aspx" />
</authentication>
<machineKey validationKey="......"
decryptionKey="........" validation="SHA1"/>
<authorization>
<deny users="?" />
<allow users="*"/>
</authorization>
First off, you must specify the authentication mode to be Forms. Next, configure the loginurl and defaulturl, if needed. The defaulturl will throw the application to that url when a redirect url is not present. Loginurl is obvious, and optional (defaults to login.aspx). Also, I specified enableCrossAppRedirects to be true so that my second application could be accessed by the same user from the first app.
Next, add a machinekey element which is unique to the application. In the code I have provided, I did not paste my own keys, just …. (after all I don’t want amy of you accessing my apps). This means that to protect your app completely you must generate it yourself. This online generator from Peter Bromberg does the job nicely.
The reason we need the key to be unique is if there are two apps on the server and both are using forms authentication. In such a case, one app could access the other since they share a common user identity. It will also help us share the user identity between two apps that we do want to be able to access each other.
In the authorization element, I have specified that anonymous users cannot enter the app, meaning that they must be authenticated first. On the other hand I have specified that all users can use the app if they have been authenticated. You can also filter users with additional settings.
Ok. Now let’s see the code.
Custom Authentication
There are many ways of actually authenticating the user’s identity, usually validating credentials against a database. However, in my case, our organization uses a separate application to do that.
So, i wired my app with forms auth into the authentication app and out came a white rabbit.
What follows is the code where I actually authenticate the user. My app receives an encrypted key from the organizational authentication app and I won’t go into that.
Dim user As Integer = Authentication.Authenticate(Session, Request.Form, Response)
If user > -1 Then
FormsAuthentication.RedirectFromLoginPage(user.ToString, False)
End If
My Authentication.Authenticate method tests the encrypted key I receive (not relevant to all of you) and produces an integer if valid, or -1 if not. Once i see that the integer produced is not -1, I call the FormsAuthentication.RedirectFromLoginPage method from asp.net which actually causes the validation of the user, and that user can now access all of my pages (unless I specify otherwise).
The Second Application
The second application I want my user to be able to access is readily accessible to that user if I just do one thing in this second app. I simply have to copy and paste the exact same code from web.config of the first app into the web.config of the second app. Since they share the same validationkey and encryptionkey, the second app will recognize the user coming from the first app as a valid user identity and allow him to access all of its pages. That’s it!
Update: One weakness I have found and not been able to solve is to get this implementation to work one-way, that is to say the one app can generate authentication for the other, but not vice versa. The enableCrossAppRedirects attribute does not prevent this. Once the first app gives authentication in its own app then the user can simply open a new tab and access the second app. In my case, we have a display site and an admin site. I want the admin user to access the display site (which also requires authentication) but not a display user to access the admin site. In the meantime I have hand coded to block users from entering the admin site unless they have the right identity, but I wish that I could find a built in configuration for this. If anyone has an idea please comment.
Update: I have found a fix to the above problem. In the Global.asax code behind in the session_start event, I added:
FormsAuthentication.SignOut()
FormsAuthentication.RedirectToLoginPage("signout=1")
This made sure that at each session start the previous authentication would be removed. You have to redirect also to remove the browser cookie. Also, I had to add a query string of “signout” (it could be anything) to avoid an infinite recursion when the user would first request the login page. The downside of this approach is that the authentication session is only good for the server session. Not persistent. No choice. If anyone can comment about this approach I would appreciate it.