Almost two months ago , I wrote three blog posts (part1,part 2 and part 3) about Anonymous Users In SharePoint, how to set it up ,challenges you might face dealing with these creatures and couple of solutions. Since then , I have received quite a few emails from people asking for two main things :
1) The source code for the solution I provided in part 3.
2) If there is any way to NOT use global.asax in a farm installation where there are multiple WFEs sitting behind a load balancer. In this case , the feature responsible for copying the global.asax file from the feature folder to the root folder of your SharePoint web application (hosted in IIS) only copies the global.asax to the WFE server on which you activate the feature. For the rest of WFEs , you need to manually replace the global.asax files. Not acceptable! Actually I am covering this issue in more details in my upcoming post : The Importance of Network Load Balancing.
Please download the source code from the link below. Take a look at the two projects included in the download.
This download contains two folders:
I) GuestAccountEnabler_GlobalASAX
This folder contains the source code for “Guest Account Enabler” functionality as a feature scoped at a site collection. The fact that it is a site collection feature might introduce some permission issues (read the comments at FeatureActivated and FeatureDeactivating methods) wen using global.asax approach. Good news is that nothing prevents you to change the scope of the feature to Farm or WebApplication or run the code in FeatureActivated and FeatureDeactivating methods in an elevated context to make sure that activation and deactivation methods are executed with required access level to the file system. Bottom line is , it is not a fully automated approach for Farm installation. Please make sure you also read the ReadMe.txt for configuration steps.
II) GuestAccountEnabler_HttpHandler
To overcome the issues mentioned above , I went a head and implemented the Guest Account Enabler functionality in a Http Module. Remember, global.asax is just a specialized Http Module , but by placing our code into a Http module instead , it is much easier to share it between multiple Web applications plus it introduces much easier deployment in a farm installation. Our Http module sits on the top of the Http Request and check the authentication cookie , if It is not presented and the feature is enabled it injects the virtual “Guest” account into the current request and forces a new http request (reentering the http pipeline) to pick up the new [virtual] Forms identity. Please remember to read the ReadMe.txt file for configuration steps spscific for Http Module approach. Here is the gist of it:
public class GuestModule : IHttpModule
{
public virtual void Init(HttpApplication context)
{
// Subscribe to events.
context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
}
void context_AuthenticateRequest(object sender, EventArgs e)
{
OnAuthenticateRequest(((HttpApplication)sender).Context);
}
public virtual void Dispose(){}
/// <summary>
/// Authenticates the authorization request.
/// </summary>
private void OnAuthenticateRequest(HttpContext context)
{
if (context == null)
throw new ArgumentNullException("context");
//Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = context.Request.Cookies[cookieName];
if (null == authCookie)
{
// There is no authentication cookie. Check to see if Guest Account feature is activated
// If Feature is Activated, ValidateUser would return Guest Account Context
if (Membership.ValidateUser("Guest", ""))
{
string requestedUrl = Uri.UnescapeDataString(context.Request.Url.ToString());
FormsAuthentication.SetAuthCookie("Guest", false);
//Force a new request (reenter the http pipeline)
context.Response.Redirect(requestedUrl);
}
}
}
}
As described in the ReadMe.txt , you need to register this Http Module in your extended site (the one that is protected by FBA). The good thing about this approach is that AuthenticateRequest event receiver only gets executed for your FBA site and only when the authentication cookie is not presented. That’s pretty much all about it !
Wait! I have included two more things in the download files.
1) It is no biggie , but you can see how to localize a feature’s title and description.
2) Have you ever heard about Minimal master page or minimal site definition (I wish there was one 😉 ) ? Both projects have a dummy Membership provider which I have called it “Minimal Membership Provider”. Well, eventually you will have to merge the Guest Account Enabler functionality into your existing membership provider , but to start with, you needed an authentication provider , right? I created that provider to give you the ability to quickly test the sample code. It is also using a dummy connection string so don’t even need to bother changing it to match your environment. Just put them in your Web.config and that’s it!