LibrarySites.Banner

Require Membership in Multiple Roles in the Sitecore ASP.NET CMS

This blog post describes a prototype that allows access rights only to users who are members of multiple roles in the Sitecore ASP.NET web Content Management System (CMS) and Experience Platform (XP).

By default, Sitecore grants an access right to any user to whom the system explicitly grants that access right or who is a member of any role allowed that access right. In a recent post on the Sitecore Developer Network (SDN) forums, someone asked how to secure content with AND conditions, specifically how to expose items only to users who are members of two roles.

I am not aware of any such feature in Sitecore (nor in NTFS, which Sitecore security mimics relatively closely). Maybe there is another, possibly better, way to achieve this objective, but the solution I proposed uses a loggingin [sic] pipeline processor to ensure that users who are members of both roles are members of a third role used to assign access rights, while users who are not members of both roles are not members of that third role.

For example, we want to allow an access right only to users who are members of both roles A and B. We can create a third role, C, and use that to assign access rights. When a user log in, if they are members of both A and B, we can ensure that they are members of C. If they are not members of both A and B, we can ensure that they are not members of C.

Here is my prototype for such a loggingin pipeline processor:

namespace SitecoreJohn.Pipelines.LoggingIn
{
  using Sitecore.Diagnostics;
  using Sitecore.Pipelines.LoggingIn;
  using Sitecore.Security.Accounts;
  using Sitecore.Security.Domains;
  using Sitecore.SecurityModel;
 
  public class AdjustRoles
  {
    public void Process(LoggingInArgs args)
    {
      User user = User.FromName(args.Username, true);
      Assert.IsNotNull(user, "user");
      Domain sitecoreDomain = DomainManager.GetDomain(
        "sitecore");
      Assert.IsNotNull(sitecoreDomain, "sitecoreDomain");
 
      if (user.Domain != sitecoreDomain || user.Name.ToLower().EndsWith(
        "\\" + sitecoreDomain.AnonymousUserName))
      {
        Log.Warn(
          this + " : unexpected security domain or user : " + user.Name,
          this);
        return;
      }
 
      if (user.IsInRole("sitecore\\C"))
      {
        if (!(user.IsInRole("sitecore\\A")
          && user.IsInRole("sitecore\\B")))
        {
          user.Roles.Remove(Role.FromName("sitecore\\C"));
        }
      }
      else
      {
        if (user.IsInRole("sitecore\\A")
          && user.IsInRole("sitecore\\B"))
        {
          user.Roles.Add(Role.FromName("sitecore\\C"));
        }
      }
    }
  }
}

Here is a Web.config include file that you can use to enable it. In case you decide to type something based on this rather than copying, pasting, and editing it, note that this pipeline definition is within the /configuration/sitecore/processors element in Web.config rather than the /configuration/sitecore/pipelines element that contains most pipeline definitions, and that there are no uppercase letters in the pipeline name.

<configuration
  xmlns:patch="https://www.sitecore.com/xmlconfig/">
  <sitecore>
    <processors>
      <loggingin>
        <processor mode="on"
          type="SitecoreJohn.Pipelines.LoggingIn.OptimizePerformanceSettings,SitecoreJohn"/>
        <processor mode="on"
          type="SitecoreJohn.Pipelines.LoggingIn.AdjustRoles,SitecoreJohn"/>
      </loggingin>
    </processors>
  </sitecore>
</configuration>

Note that with this solution one should NOT grant access rights to A or B, but only to C, except in cases where either A or B should have the access right. Note also that any change to role membership in A or B for the user would not affect their membership in C until their next login.

Resources