Mark Martis
Mark Martis

Reputation: 21

How can you set security so that a user can only see/edit their items in Sitecore?

Is there any way in Sitecore that I can create a role/user that only can view and edit their own created items? If not, how can I make this possible?

Upvotes: 1

Views: 866

Answers (3)

Sandeepkumar Gupta
Sandeepkumar Gupta

Reputation: 420

To simply things, one can use lock and edit features of Sitecore. User can lock by Review > Edit in workflow group. Once editing done save and click check in. If logged in user wish to see his locked items then user can right click on left side of content tree and select My locked Items to see my locked items gutter. Even you can view all locked items from Review > My Items. Note this does not make any changes to access rights. But disallow other user except admin to unlock items.

Upvotes: 0

Mark Martis
Mark Martis

Reputation: 21

To fix this I have added an item:created event under sitecore/events config.

<event name="item:created" xdt:Transform="Replace" xdt:Locator="Match(name)">
              <handler type="Sirano.Dev.ItemEventHandlers.CustomItemEventHandler, Sirano.Dev" method="OnItemCreated" />
</event>

This event wil run the following code:

    protected void OnItemCreated(object sender, EventArgs args)
    {
        if (args == null)
        {
            return;
        }
        var parameters = Event.ExtractParameters(args);
        var item = ((ItemCreatedEventArgs)parameters[0]).Item;
        if (item == null)
        { 
            return; 
        }

        var user = Sitecore.Context.User;

        var accessRules = item.Security.GetAccessRules();

        accessRules.Helper.AddAccessPermission(user,
           AccessRight.ItemRead,
           PropagationType.Any,
           AccessPermission.Allow);

        accessRules.Helper.AddAccessPermission(user,
           AccessRight.ItemWrite,
           PropagationType.Any,
           AccessPermission.Allow);

        item.Editing.BeginEdit();
        item.Security.SetAccessRules(accessRules);
        item.Editing.EndEdit();
    }

Upvotes: 1

Richard Hauer
Richard Hauer

Reputation: 1346

I just finished building this very function. While there is nothing out-of-the-box, there are a number of possible ways to solve this including:

  • item:saving event handler (note 'saving' and not 'saved' which happens after the fact), or
  • create a processor for the saveUI pipeline, which is executed when the 'Save' button is executed in the UI, or the way we went
  • create a processor for the getContentEditorWarnings pipeline

This last approach allows you to disable the Sitecore UI and display a message to the user, but does not prevent code or APIs from altering items, which was ideal for us. Our processor accepted a list of paths (in the config) as sub-elements that allowed us to limit the functionality to certain areas of the site (we were controlling access to the Marketing Control Panel).

Here is an extract of the <getContentEditorWarnings> pipeline where we injected our piece.

....
<processor type="Sitecore.Pipelines.GetContentEditorWarnings.CanWrite, Sitecore.Kernel"/>
<processor type="PingWorks.Pipelines.GetContentEditorWarnings.EditorIsFromAuthorGroup, PingWorks.Pipelines.GetContentEditorWarnings" patch:source="PingWorks.Pipelines.GetContentEditorWarnings.config">
  <ignoredRoles hint="list:AddIgnoredRole">
    <role>sitecore\_UserBase</role>
  </ignoredRoles>
  <paths hint="list:AddPath">
    <path>/sitecore/system/Marketing Control Panel/Taxonomies/</path>
    <path>/sitecore/system/Marketing Control Panel/Campaigns/</path>
    <path>/sitecore/system/Marketing Control Panel/Engagement Plans/</path>
    <path>/sitecore/system/Marketing Control Panel/Experience Analytics/</path>
    <path>/sitecore/system/Marketing Control Panel/FXM/</path>
    <path>/sitecore/system/Marketing Control Panel/Outcomes/</path>
    <path>/sitecore/system/Marketing Control Panel/Path Analyzer/</path>
    <path>/sitecore/system/Marketing Control Panel/Personalization/</path>
    <path>/sitecore/system/Marketing Control Panel/Test Lab/</path>
    <path>/sitecore/system/Marketing Control Panel/Experience Explorer/</path>
    <path>/sitecore/system/Marketing Control Panel/Analytics Filters/</path>
  </paths>
</processor>
<processor type="Sitecore.Pipelines.GetContentEditorWarnings.CanWriteWorkflow, Sitecore.Kernel"/>
...

Note how you can use the Sitecore Configuration Factory to populate properties of the instance that the pipeline executor will create using sub-elements, and how in this case we're adding strings to a List<string> property by way of the ::AddIgnoredRole() and ::AddPath() methods.

In our particular case we wanted to only allow editing where the editor was a member of the same role group as the original author, though your logic will be even more straight-forward than ours. In our case we also added an override for Administrator users, and added a custom cache to store the role search results to speed up processing as role memberships don't change very often in our case.

I'll spare you the bulk of the processing, but the crux of it is in the ::Process() method (I've had to reflect this code as I can't access the source at present):

public void Process(GetContentEditorWarningsArgs args)
{
    string displayName;
    this._item = args.Item;
    if (!this._isValidForProcessing())
        return;

    User user = null;
    List<string> creatorRoles = this._getRolesForUser(this._item.Statistics.CreatedBy, out user);
    List<string> editorRoles = this._getRolesForUser(Context.User);

    // compare creator's roles with current editor to find a match
    if ( creatorRoles.Any() && editorRoles.Any() && editorRoles.Any( r => creatorRoles.Contains(r) ) )
        return;

    // if we haven't already aborted, add a warning to display and block editing
    GetContentEditorWarningsArgs.ContentEditorWarning cew = args.Add();
    cew.IsExclusive = true;
    cew.Key = "EditorIsFromAuthorGroup";
    cew.Title = "Editing restricted";
    cew.Text = $"Editing for this item is restricted. Editors must share a role with the original author, in this case <{user?.DisplayName ?? "Unknown Author"}>.";
}

private bool _isValidForProcessing()
{
    if (this._item == null)
        return false;

    if (Context.IsAdministrator)
        return false;

    if (!this._paths.Any<string>((string p) => this._item.Paths.FullPath.ToLower().StartsWith(p)))
        return false;

    return true;
}

That's probably sufficient to get you a good start on where you need to be.

Upvotes: 0

Related Questions