A few months ago I started experimenting with how preview works with protected pages, and realized umbraco really doesn't support this scenario right now. I naively thought this was a simple bug that I could add a quick fix for, and submitted the pull request found here
https://github.com/umbraco/Umbraco-CMS/pull/331. However as Sebastian noted, my approach really didn't consider the complexity of the issue, and probably stood to make things worse rather than better. Since then I've been thinking more on the issue and I have a couple of ideas I wanted to throw out to the community for feedback on.
As Sebastian points out, once you're in the business of handling pages which are restricted to certain roles, you have to account for the fact that developers may have put additional roles based logic into those pages using the built in ASP.Net membership and roles framework. This adds a whole host of issues that simply aren't a problem when you're previewing as an anonymous user.
To solve this issue, I started kicking around the idea of "Preview Profiles." These would be actual entries in the umbraco members table, that could be edited using the standard back office member UI. For all intents and purposes they would be members, though we'd probably want to take some steps to prevent them from logging on and showing up in the members tree.
When previewing, instead of just inserting the preview badge into the page, we would inserting a dropdown listing all the preview profiles. The previewer could select which one they wanted to use to view the page. Selecting a new profile would cause the system to actually log that user in, so all aspects of the ASP.Net membership framework would behave appropriately.
Since these profiles are actually umbraco members from the membership providers perspective, administrators could edit their membership groups to ensure that all important preview scenarios are covered.
The other thing I like about this approach is that they key components can be implemented without actually touching the umbraco code base. I can put together an extension that creates a new member type, or adds properties to the existing member types, includes a partial view and appropriate surface controller for the switcher, and create a http module that handles ensuring the login. I already created a rudimentary proof of concept of the http module, copied below.
public class ProtectedPreview : IHttpModule
{
public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += context_AuthenticateRequest;
}
void context_AuthenticateRequest(object sender, EventArgs e)
{
if (UmbracoContext.Current != null && UmbracoContext.Current.InPreviewMode)
{
//Hardcoding user for testing, in reality would want to extract from a cookie set by the switcher
var ticket = new FormsAuthenticationTicket(1, user.UserName, DateTime.Now, DateTime.Now.AddMinutes(30),
true, "", FormsAuthentication.FormsCookiePath);
var identity = new FormsIdentity(ticket);
//set the principal object
var principal = new GenericPrincipal(identity, Roles.GetRolesForUser(user.UserName));
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
}
public void Dispose()
{
}
}
The only concern I have with this approach is that the module above overwrites the HttpContext.Current.User property. In the Umbraco.Web.UmbracoModule class the ShouldAuthenticateRequest specifically checks if we're in preview mode. If ShouldAuthenticateRqeust returns true the code later explicitly sets that property to the current back office user. My approach would be overriding that. I did some initial testing, and didn't see any issues, but maybe someone more familiar with the codebase can way in on this specific issue as well as the general approach.