How to achieve a feature similar to single logon for multiple web applications using Basic authentication
Here is something which I recently figured out. This may be very simple to many but thought of sharing it for a wider audience.
Let's say you have two ASP.Net web applications running on two different servers.
Now, assuming you have a constraint wherein you cannot use Windows integrated authentication (in cases where in you have some JSP application running on Websphere and another Asp.Net app on IIS server or any multi-platform scenarios), and you want to access the 2nd web app internally from the 1st web app for authenticated users. Now since you cannot use windows integrated authentication (e.g. Websphere doesn't support windows integrated authentication) the only option is to use Basic authentication which is supported across multiple platforms.
So here Windows integrated and anonymous authentication are out of picture and you are left with Basic authentication. Now if you want to access the 2nd Web app internally from the 1st web app and since both are configured for Basic authentication what will you do. IIS prompts for basic authentication and since you are trying to access it internally from the 1st web app you may get into issues wherein IIS will throw 401 Unauthorized error.
1st Web app ---> 2nd Web app
(Basic Authentication) (Basic Authentication)
Had Windows integrated authentication been supported we could have gone ahead with Kerberos but now that is out of picture.
This is what I figured out. If a user is authenticated using basic authentication, an Authorization header is passed (after user enters the credentials and is authenticated) to the server as part of the request header. Now this header will remain the same for a combination of username and password. Web server recognizes the future requests for the same user using the same header.
Now if you try to call the 2nd web app URL through the 1st web app using httpwebrequest you will get 401 unauthorized. This is because the web request from the 1st web app does not send the Basic authentication token to the destination by default. It sends a new request to the 2nd web app and since 2nd web app is configured for basic authentication only and no anonymous authentication it will fail with 401.
To avoid getting into such issues you can modify your code in the 1st web app such that it also appends the Authorization header (which it gets during the first basic authentication done by the 1st server) along with the new http request to the 2nd web app (now all this assuming the user is allowed to access both the websites on both the servers).
Here is code snippet on the 1st web app which calls the 2nd web app internally.
Default.aspx
==============
Default.aspx.cs
===============
Assuming web app2 being https://shrek:8080/default.aspx
Here is the error thrown on the browser:
Now try adding the following lines and browse to the page in web app1. You should be able to access the web app2 without any issues.
Default.aspx.cs
===============
If you notice we are resending the authorization header that we got during the 1st web app authentication process. The same authorization header when accessing the 2nd web app nullifies the requirement for a new authentication handshake between IIS and the its client request. If we did not pass the authorization header to the 2nd web request IIS has to renegotiate a new authentication process with its client in order to get the necessary credentials for allowing access to its contents. Thereby throwing error 401 in our case since we are calling the 2nd web app internally in the code. The above scenario can work for N number of websites which can easily be greater than 2.
Do remember to add resp.close() and reader.close() in the above code section at the end.
If IIS is configured for basic authentication only it will look for Basic Authorization header before serving the request.
Also remember if you use just a response.redirect from 1st web app to 2nd web app it will work just fine but you will be prompted twice for basic authentication. This is because you get prompted for credentials the first time when you access the 1st web app and then again when a new request is sent for the 2nd web app through response.redirect it doesn't have the authorization header by default (Remember response.redirect cause a new request to be sent to the server from the client's end). So IIS again prompts you for credentials.
If it doesn't find an authorization header it will send a 401 response back asking the client to resend the request with a valid authorization header. Here above we are adding an authorization header along with the request in the first place so that IIS need not send 401 response.
***Basic authentication sends credentials in clear text and is base64 encoded. So it can be easily decoded by a sniffer. So its recommended to use SSL with basic authentication.
Comments
Anonymous
August 12, 2007
Hi , How about using the HttpWebRequest.Credentials Property ? http://msdn2.microsoft.com/en-us/library/system.net.httpwebrequest.credentials.aspx Your Example would then be changed to request.Credentials = CredentialCache.DefaultCredentials; So, tomorrow , if Websphere dependency is removed or a Windows Integrated Auth Module is added, your code wont change :) Thanks, RajAnonymous
September 21, 2007
How would you use to redirect to another page using your code. for example Response.Redirect("http://http:shrek:8080/Default.aspx");Anonymous
September 21, 2007
Hi Dhiren, Sorry if I did not get your question correctly...but when you are using response.redirect you are going away from single-sigon feature. Response.redirect causes the IIS server to send a 302 repsonse back to the client. Client will send a new request to the server so it has to be reauthenticated again depending upon the authentication supported. You can circumvent this by using some sort of feaature like Forms authentication, Kerberos etc. to persist authentication cookie.