Personalizing Staticlly Based Componenets with the Sitecore Rules Engine

Someone in the SDN forums had asked how to personalize a statically placed component on a page so I thought I’d come up with a solution. One one option would of course be to use template inheritance and to personalize the component on your base page template but that’s no longer a statically placed component.

I decided to create a web control that has settings for the default rendering , datasource, and parameters but allows you to personalize the component via the rules engine.  My first attempt had me creating my own rule context and actions but after a quick rewrite I realized I didn’t need all of that and was able to just use the per-existing context and actions.

Here’s the solution.

Create a Sitecore Template with a Field and call it “Rendering Rule” and make it of type Rule and set the Datasource to “/sitecore/system/Settings/Rules/Conditional Renderings”.

Add a new one to the tree and set the rendering rule. Something easy to test is “Where the current user is adminstrator change the rendering item”. Just make sure not to try and test in preview.

Next, I created the control below which will execute the rule actions for the item

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using Sitecore.Rules.ConditionalRenderings;
using Sitecore.Data.Items;
using Sitecore.Web.UI.WebControls;
using System.Web;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Diagnostics;
using Sitecore.Rules;
using Sitecore.Data.Fields;
using Sitecore.Layouts;

namespace ConditionalRenderings
    public class StaticRendering : WebControl
        public string DataSource { get; set; }
        public string RenderingItem { get; set; }
        public bool IsHidden { get; set; }
        public string RenderingRule { get; set; }
        public string Parameters { get; set; }

        protected override void OnLoad(EventArgs e)

            Assert.IsNotNull(RenderingRule, "Rendering Rule cannot be null");
            Item RenderingRuleItem = Sitecore.Context.Database.SelectSingleItem(RenderingRule);
            Assert.IsNotNull(RenderingRuleItem, "Rendering Rule Item not found.");
            Assert.IsNotNull(RenderingItem, " Rendering Item cannot be null");
            Item renderingItem = Sitecore.Context.Database.SelectSingleItem(RenderingItem);

            //create the rendering reference and set some defaults
            RenderingReference reference = new RenderingReference(new RenderingItem(renderingItem));
            Assert.IsNotNull(RenderingItem, "Rendering Item not found");

            if (!string.IsNullOrEmpty(DataSource))
                reference.Settings.DataSource = DataSource;

            if (!string.IsNullOrEmpty(Parameters))
                reference.Settings.Parameters = Parameters;

            List references = new List();

            //new up the rule context and execute the rule
            ConditionalRenderingsRuleContext ruleContext = new ConditionalRenderingsRuleContext(references,reference);

            RuleList rules = RuleFactory.ParseRules(Sitecore.Context.Database, RenderingRuleItem.Fields["Rendering Rule"].GetValue(true));

            //make sure hide component wasn't selected as an action
            if (ruleContext.References.Count >= 1)
                //add the control to the page


Next, Add the control source to the web config under system.web/pages/controls.

<add tagPrefix=”cr” namespace=”ConditionalRenderings” assembly=”ConditionalRenderings”/>

Finally, add the control to a page pointing it at the Rendereing Rule Item we created and and default Rendering Item.

<cr:StaticRendering runat=”server” RenderingItem=”{2B556B84-364A-4AB3-A64C-933787D19619}” RenderingRule=”{11BD1B9F-A953-4F80-8692-4663B6DB4C78}” />

Package to just download and install is available here. You will still have to update the web.config to use the control.


Sitecore MVC Area Controller Rendering Type

I saw this post a couple weeks back about working with Areas in Sitecore MVC. One of the issues was that you had to specify the view path in all of the actions because Sitecore didn’t understand what area you are in. To get around this I created my own rendering type that allows me to specify an Area field. The Area is then added to the Route Values Dictionary. I’m expecting this would also fix other problems with working in areas, like linking. I do however recomend that you strongly type the controller name when entering it as Sitecore is not using the Area field when it resolves the controller. Perhaps that code could be updated as well.

The code is here and the package to install it is here.

There are three classes that I will describe below :

This class checks to see if the Rendering Item inherits the Area Controller Template. If it does we Assign the AreaControllerRenderer as the Renderer.


This class passes the Action, Controller and Area to the AreaControllerRunner and returns the html to Sitecore.


This class executes the controller.  The big change is made here where I pass the Area in the Route Values Colleciton.  The important line to get area support is below.

requestContext.RouteData.DataTokens[“area”] = this.Area;


There is also a Sitecore.MVC.SitecoreAreas.config file that causes the code to execute in the GetRenderer Pipeline and a new template ‘Sitecore/Templates/User Defined/Mvc Areas/Area Controller’ that has the template to inherit from your rendering.

I personally think everything should be done in areas as it makes things more portable to other projects.  If you’re not using areas you can also use this project as a sample on how to extend Sitecore to support your own rendering type.

Extending Sitecore Rocks – Creating a ContentTreeCommand and Server Component

Sitecore Rocks is completely extensible, much like Sitecore itself.  In this example I’ll be extending it to support cloning with a Sitecore Rocks Server Component and a Sitecore Explorer Command Plug-in.

The Server Component

•Server Components sit in the bin folder of the websites.
•The Hard Rocks Webservice is used for processing custom plugins.
•All assemblies must begin with Sitecore.Rocks.Server
•The class’s namespace must begin with Sitecore.Rocks.Server.Requests
•The class must have an Execute method that returns a string
•The Execute method may contain any number of string parameters

1. Create a new Sitecore Rocks Server Component Project named  Sitecore.Rocks.Server.Cloning

2. Rename the HandleRequest class to Clone in the Requests folder

3. Change the Namespace to Sitecore.Rocks.Server.Requests.Cloning

4. Use the following commented code

using System.IO;
using System.Xml;
using Sitecore.Data;
using Sitecore.Data.Items;
using System;
using Sitecore.Configuration;
namespace Sitecore.Rocks.Server.Requests.Cloning
    public class Clone
        public string Execute(string databaseName, string sourceItemId, string targetItemId, string databaseUri)
            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
                //clone the item
                Database database = Factory.GetDatabase(databaseName);
                Item item = database.SelectSingleItem(sourceItemId);
                Item destination = database.SelectSingleItem(targetItemId);
                Item item2 = item.CloneTo(destination);
                //write out the database uri
                //write out the new item id
            catch (Exception ex)
                //write out an error if we have one and Rocks will throw the error
                xmlTextWriter.WriteString("***ERROR*** " + ex.Message);
            return stringWriter.ToString();

5. Compile and place the assembly in the bin of your website.

Creating the Rocks Plug-in

When Rocks loads it scans the C:\Users\{user}\AppData\Local\Sitecore\Sitecore.Rocks\Plugins folder for assemblies and loads types that are marked with certain attributes[Command],[Pipeline],[FieldControl] etc…

In the code below will be doing the following :
  • Modify the constructor to set the name, group and sort order.
  • Modify the CanExecute Method to make sure only one item is selected.
  • Modify the Execute Method to Show a Dialog that allows the user to select where to place the clone and then call the Server Method.
  • Add an ExecuteCompleted  method to handle the return call from the server and refresh the screen.
  • Add a method to handle the XML Parsing.
1. Create a new Sitecore Rocks Plug-in Project and name it Sitecore.Rocks.Plugins.Cloning
2. Rename the Command to Clone
3. Replace the code with the following commented code
namespace Sitecore.Rocks.Symposium.Commands
    using Sitecore.VisualStudio.Commands;
    using Sitecore.VisualStudio.ContentTrees;
    using System.Linq;
    using Sitecore.VisualStudio.Data;
    using Sitecore.VisualStudio.UI.SelectItem;
    using Sitecore.VisualStudio.Extensions.IItemSelectionContextExtensions;
    using Sitecore.VisualStudio.Data.DataServices;
    using System.Xml;
    using System;
    using System.Windows;

    public class Clone : CommandBase
        public Clone()
            this.Text = "Clone";
            this.Group = "Edit";
            this.SortingValue = 2300;
        public override bool CanExecute(object parameter)
            //this method enables or disables the menu option
            var context = parameter as ContentTreeContext;
            if (context == null || context.SelectedItems == null || context.SelectedItems.Count() != 1)
                return false;
            return true;

        public override void Execute(object parameter)
            //this method executes when the button is pushed
            var context = parameter as ContentTreeContext;
            if (context == null || context.SelectedItems == null || context.SelectedItems.Count() != 1)

            //get the selected item
            IItem selectedItem = context.SelectedItems.FirstOrDefault() as IItem;

            if (selectedItem != null)
                // get the root "sitecore/content" item for our select item dialog.
                var contentItemId = IdManager.GetItemId("/sitecore/content");
                var contentItemUri = new ItemUri(selectedItem.ItemUri.DatabaseUri, contentItemId);

                //Show a popup to select a target
                SelectItemDialog dialog = new SelectItemDialog();
                dialog.Initialize("Select Target Item", contentItemUri);

                if (dialog.ShowDialog() == true)
                    //item is selected to clone to , send the command to the server
                    var targetItem = dialog.SelectedItem;
                    if (targetItem != null)
                        context.GetSite().DataService.ExecuteAsync("Sitecore.Rocks.Server.Requests.Cloning.Clone,Sitecore.Rocks.Server.Cloning", //The class to exectue on the server
                            completed, // the completed event
                            selectedItem.ItemUri.DatabaseName.Name,  //the database name for sitecore
                            selectedItem.ItemUri.ItemId.ToString(), //the source items id
                            targetItem.ItemId.ToString(), // the target items id
                            selectedItem.ItemUri.DatabaseUri.ToString() // the database uri to return to server


        ExecuteCompleted completed = delegate(string response, ExecuteResult result)
            //this method is fired after the item is created on the server
            if (!DataService.HandleExecute(response, result))
            //get the active content tree
            ContentTree activeContentTree = Sitecore.VisualStudio.UI.ActiveContext.ActiveContentTree;
            if (activeContentTree != null)
                // get the return values from the xml that was returned
                string database = GetResultValue(response, "//database");
                string item = GetResultValue(response, "//item");

                //get the databaseUri in the rocks format
                DatabaseUri dbUri;
                DatabaseUri.TryParse(database, out dbUri);
                //get the itemUri in rocks format
                ItemId itemId = new ItemId(new Guid(item));
                ItemUri itemUri = new ItemUri(dbUri, itemId);
                if (itemUri != null)
                    //send the user to our newly created content

        //parse xmlvalue
        public static string GetResultValue(string xml, string xPath)
            XmlDocument xmlDocument = new XmlDocument();
            XmlNode xmlNode = xmlDocument.SelectSingleNode("//result" + xPath);
            return xmlNode.InnerText;

4. Compile the Project.
5. Open up a new instance of visual studio and you should see your new ‘clone’ command when you browse to an item.

Adding Site Filters to DMS Reports with Sitecore 6.5

DMS does not have a Site Filter for multi site enviornments in the latest version of Sitecore 6.5 but I found adding one is quite easy so here is a little tutorial.

Step 1 Create a Filter

  • Browse to /sitecore/system/Marketing Center/Analytics Filters/Report Filters.
  • Insert a new ‘Filter’ named Site.
  • Set the Type to ‘Sitecore.Analytics.Reports.Filters.ValueListFilter, Sitecore.Analytics’
  • Set the ColumnName to ‘MultiSite’

Step 2 Add Filter Values

Select your new new ‘Site’ Filter and insert two new ‘Predefined Filter Values’ name them ‘website’ and ‘site2’ and set their values accordingly.

Step 3  Add the Filters to each Report

  • Browse to the reports in /sitecore/system/Settings/Analytics/Reports SQL Queries.  ( for this example I used ‘Latest Visits’ )
  • Add the column [Visits].[MultiSite] to the SQL fields.
  • Add the new ‘Site’ filter to the Filter field.

Step 4 Go Test the filter on your report

  • Open the Report from the ‘Engagement Analytics’ Menu Option.
  • Test your new filter with the Filter Button up top.

Federated Authentication with Sitecore and the Windows Identity Foundation

UPDATE : There is a new version of the module here:


Over the past few months I’ve done some work integrating Sitecore with multiple Federated Authentication systems like Ping Identity, ADFS and some home grown ones.  The way Federated Authentication works is instead of logging directly into an application the application sends the user to another system for authentication. Once that system authenticates the user an encrypted token, typically SAML, is passed back to the requesting application containing credentials and other information, known as claims.

Getting everything working with the Windows Identity Foundation proved to be more challenging than some of the other API’s I worked with. I’d like to thank Owain Jones, Kern Herskind Nightingale and Ivan Sharamok for their help and suggestions that made this all work.

Here is the source and update file for this solution. There is also this sample web.config.

Step 1: Setting up your development environment for claims based authentication.

This tutorial is already written so I’m just going to point to that. I suggest you set up a basic website and get claims Authentication working there before you go and try integrating it with Sitecore.

Step 2: Add Roles to Sitecore

Login To Sitecore and create the following roles :

Extranet/Registered Users


Assign Sitecore Author to the Sitecore Client Authoring Role so they can login to the system.

Step 3: Modify the mock STS to send the roles

After you have completed that tutorial modify the STS project and change the code in CustomSecurityTokenService.cs that writes out the claims to include two roles that exist in your Sitecore system.

protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)


if (null == principal)


throw new ArgumentNullException("principal");


ClaimsIdentity outputIdentity = new ClaimsIdentity();

// Issue custom claims.

// TODO: Change the claims below to issue custom claims required by your application.

// Update the application's configuration file too to reflect new claims requirement.

outputIdentity.Claims.Add(new Claim(System.IdentityModel.Claims.ClaimTypes.Name, principal.Identity.Name));

outputIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Registered Users"));

outputIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Author"));

return outputIdentity;


Step 4: Install the FedAuthenticator update package.

Login to Sitecore as an admin

Browse to /sitecore/admin/updateinstallationwizard.aspx

Install the update file found here.

Step 5 : Using Visual Studio or FedUtil.exe update the web.config of your sitecore solution to point to your STS like you did in the tutorial found under Step 1.

see :

Step 6: Modify the web.config file.

Under the Modules Section move the Authentication Modules so they fire after Nexus and replace the Session Module with the one in the FedAuthenticator Module.

<add type=”Sitecore.Nexus.Web.HttpModule,Sitecore.Nexus” name=”SitecoreHttpModule” />

      <addname=“WSFederationAuthenticationModule” type=”Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ preCondition=”managedHandler” />

      <addname=“SessionAuthenticationModule” type=”FedAuthenticator.Authentication.WSSessionAuthenticationModule, FedAuthenticator”/>

<add type=”Sitecore.Resources.Media.UploadWatcher, Sitecore.Kernel” name=”SitecoreUploadWatcher” />

Change the Location information inside of the web.config file so it looks like the following:


<location path=”sitecore modules/Shell/FedAuthenticator/sso.aspx”>



<deny users=”?”/>






<deny users=”?” />


<!– Continue to run Sitecore without script validations –>

If you now try to hit sitecore modules/Shell/FedAuthenticator/sso.aspx the user should be logged into Sitecore with the Author Role.

Step 7: Create a secured page in Sitecore.

Under the Home Item create a new Sample Item and name it ‘secured’.

Set the permissions up to break inheritance for Extranet/Everyone then grant read access and enable enheritance for the Extranet/Register Users role.

Step 8 : Test authentication to the front end of the website.

Log out of Sitecore:

Clear your cookies to remove the pre-existing token.

Browse to http://yourwebsite/secured

You should be redirected to the STS token issuer. Once you log in you will be brought back to your website and should see the secured item.

It may be helpful to add this code to your sample layout.aspx page so you can see the users information.

<div><%=Sitecore.Context.User.Name %></div>

<div>Is Virtual? <%=Sitecore.Context.User.RuntimeSettings.IsVirtual %></div>



foreach (var role in Sitecore.Context.User.Roles)



<div><%=role.Name %></div>




Code Review

Ideally this solution would have had two processors and nothing else.

The TokenRequestor looks to see if access is denied to an item and sends the user to the STS with a request for a token if the user is not already authenticated.

The UserResolver looks for a token in a cookie, if it exists and the user is not authenticated we log the user in a virtual user.

That’s all I expected to need when I first wrote this but I was having trouble persisting user information.  This led us to the Sitecore support portal and we found we needed a custom authentication provider and we had to overwrite the WSSessionModule to get this to work.

The root of the problem is three fold:

  1. Both Sitecore and the Windows Identity Foundation are fighting over the threads user identity located at HttpContext.Current.Request.User.
  2. The Windows Identity Foundation does not allow you to just request and parse a token just using the API. It forces you to use the http modules. If I could do this without the modules there would be a lot less code.  This is the approach I took when integrating Ping Identity and it was much easier but my Ping Identity code only works with Ping Identity and this solution should work with a lot of other identity providers, including Ping Identity.
  3. The Sitecore Nexus API is obfuscated and I had trouble figuring out where/when the Identity was being set.

So, now here’s all the ‘other’ code that was added to get the two systems to play nice.

WSSessionAuthenticationModule was added to prevent some of the Session overriding. The binding to PostAuthenticateRequest was removed from initialize module and we override the Authenticate Request method so it exits the method if we already have a Sitecore.Context.User.

The FederatedAuthenticationProvider was also added to get the role and user information to persist. The Forms Authentication Provider uses a cookie for saving the value but this cookie wasn’t persisting when we logged in using SSO so we read the Session Token instead inside of the GetCurrentUser method of the Authentication Helper.

The login method was also changed to not write out a forms cookie.

The sso.aspx page is being used to log in to Sitecore.  The user is assigned to the roles based on the Sitecore Domain. That is why the page currently lives under the sitecore modules folder.

Things that could use improvement

  1. Currently the user is logged in on every request when a token exists. I’d like to be able to just parse the token the first time it’s sent from the STS and log the user in once but that didn’t work out.
  2. Single Sign Out is not yet implemented.
  3. This solution is currently only supporting virtual users.

Sitecore setting Timeout on a Virtual User

A customer was having issues getting a virtual users expiration to timeout. In looking at the code in the Authentication Manager I found that the method being used to load the virtual user passes expires as false and didn’t have an override.

To fix it I overwrote the Login(User) method of the  Authentication Provider and passed in the true variable.

Here’s my Authentication Provider.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Sitecore.Diagnostics;
using System.Web.Security;
using Sitecore.SecurityModel;
using Sitecore.Configuration;
using Sitecore.Security.Accounts;

namespace AdventureWorksMembership
    public class FormsAuthenticationProvider : Sitecore.Security.Authentication.FormsAuthenticationProvider
        public override bool Login(Sitecore.Security.Accounts.User user)
            Assert.ArgumentNotNull(user, "user");
            if (!base.Login(user))
                return false;
            FormsAuthentication.SetAuthCookie(user.Name, true);
            return true;

        private void StoreMetaData(Sitecore.Security.Accounts.User user)
            UserRuntimeSettings runtimeSettings = user.RuntimeSettings;
            if (runtimeSettings.IsVirtual)
                ClientContext.SetValue("SC_USR_" + user.Name, runtimeSettings.Serialize());

And in my web.config file

<authentication defaultProvider="forms">
<add name="forms" type="AdventureWorksMembership.FormsAuthenticationProvider, AdventureWorksMembership"/>

<authentication mode="None">
<forms name=".ASPXAUTH" cookieless="UseCookies" timeout="20"/>

It should be noted that setting slidingexpiration to true doesn’t work so this could open a whole new set of worms for you.

I have a fix for that here in this forum thread :

HTML5 video with Sitecore

I worked with a client that was having trouble getting HTML5 video to play in Sitecore. Inside of our support tickets I found the trick to getting it to work is to add the following MIME Types to the App_Config/MIMETypes.config file.

  <mediaType extensions="ogg">
  <mediaType extensions="m4v">

After that I was able to play video with those two formats in IE9 and the latest versions of FF and Chrome. I have not tested on any mobile devices or older browsers.

With HTML5 you need to specify the source video for each codec you want to support because the browsers do not support the same codecs.

<video controls="controls"">
   <source src="~/media/Files/sample_h264.m4v" type="video/mp4" />
   <source src="~/media/Files/sample_ogg.ogg" type="video/ogg"/>
   <p>Your browser does not support the <code>video</code> element.</p>