Global Office Directory
More Products
Share this page
Home > Community > Technical Blogs > Getting to Know Sitecore > Custom Access Rights
Sitecore's standard authorization model provides the ability to control permissions at a variety of levels of granularity: site, item, field, language and workflow. This functionality is often sufficient for handling authorization-related requirements.
But it doesn't handle all of them. Authorization rights can be used to "allow" or "deny" comments. What if you want to allow comments, but no more than 5 comments on any page? Or if you want to prevent comments from being added to pages that are more than 30 days old?
In this post I'm going to describe how to create a custom authorization that controls the ability to add comments to a page. I also explain how properties can be defined on a specific right that provide additional levels of control.
I want to offer a quick disclaimer before I get started. There are certainly other - arguably easier - ways to implement this functionality. But I thought it would be helpful to explain how to authorization rights can be used. Now then, on with the post.
STEP 1 - Create a custom access right
An access right is basically a label that is applied to a Sitecore item. The label tells Sitecore if a user or role is allowed or denied the ability to do something. Access rights don't really do much except store information such as what kind of item the access right applies to (items, fields, workflow, etc.).
The access right I need stores a little more information. I need to be able to specify the maximum number of comments that should be allowed, as well as a value that determines the number of days after a page is updated that comments can be left.
The following code presents the access right I need:
using
System.Collections.Specialized;
Sitecore.Security.AccessControl;
namespace
Sitecore.Marketing.AccessRights
{
public
class
CommentingAccessRight : AccessRight
CommentingAccessRight(
string
name) :
base
(name)
}
MaxCommentsFieldName {
get
;
private
set
; }
int
DaysToAllowComments {
override
void
Initialize(NameValueCollection config)
.Initialize(config);
//
//Read the maxCommentsFieldName value from the config file.
this
.MaxCommentsFieldName = config[
"maxCommentsFieldName"
];
//Read the daysToAllowComments value from the config file.
//The value should be an int, but if it isn't (or if the
//value isn't set), -1 should be used. -1 indicates that
//comments are allowed indefinitely.
var count = 0;
if
(!
.TryParse(config[
"daysToAllowComments"
],
out
count))
count = -1;
.DaysToAllowComments = count;
STEP 2 - Create ItemAuthorizationHelper
An ItemAuthorizationHelper is used to determine if an access right applies to an item. The following code implements the helper:
System;
Sitecore.Configuration;
Sitecore.Data.Items;
Sitecore.Security.Accounts;
MyItemAuthorizationHelper : ItemAuthorizationHelper
protected
AccessResult GetItemAccess(Item item, Account account, AccessRight accessRight, PropagationType propagationType)
//This method applies the specified AccessRight. Since the custom AccessRight
//has been extended to support additional properties (max comments and
//time range), these properties must be considered.
var result =
.GetItemAccess(item, account, accessRight, propagationType);
(result ==
null
|| result.Permission != AccessPermission.Allow)
return
result;
(accessRight.Name != CommentingRights.AddComments)
var right = accessRight
as
CommentingAccessRight;
(right !=
)
result = GetItemAccess(item, account, right);
virtual
AccessResult GetItemAccess(Item item, Account account, CommentingAccessRight right)
//Determine if comments should be allowed based on the max comments count.
var result = HandleMaxComments(item, account, right);
(result.Permission == AccessPermission.Deny)
//Determine if comments should be allowed based on the time range.
result = HandleDaysToAllowComments(item, account, right);
//Allow comments.
var ex =
new
AccessExplanation(
"Comments are allowed on this item."
);
AccessResult(AccessPermission.Allow, ex);
AccessResult HandleMaxComments(Item item, Account account, CommentingAccessRight right)
//Allow unlimited comments if no field name is specified for MaxCommentsFieldName.
(
.IsNullOrEmpty(right.MaxCommentsFieldName))
"Unlimited comments are allowed."
//Allow unlimited comments if the specified field does not exist on the item.
var field = item.Fields[right.MaxCommentsFieldName];
(field ==
"The item {0} does not have a field named \"{1}\", so unlimited comments are allowed."
, item.ID.ToString(), right.MaxCommentsFieldName);
//Deny commenting if the max comments value is not an integer.
var maxCommentCount = 0;
.IsNullOrEmpty(field.Value) && !
.TryParse(field.Value,
maxCommentCount))
"The value specified for the field named \"{0}\" is not a valid integer: {1}"
, right.MaxCommentsFieldName, field.Value);
AccessResult(AccessPermission.Deny, ex);
//Deny commenting if the max comments limit has already been met.
(maxCommentCount > -1)
var currentCount = GetCurrentCommentCount(item);
(currentCount >= maxCommentCount)
"{0} comments already exist, and the maximum number allowed is {1}."
, currentCount, maxCommentCount);
//No other rules need to be implemented, so allow comments.
var ex1 =
"Additional comments are allowed."
AccessResult(AccessPermission.Allow, ex1);
AccessResult HandleDaysToAllowComments(Item item, Account account, CommentingAccessRight right)
//Allow commenting if the value is -1 since that value means comments
//may be added indefinitely.
(right.DaysToAllowComments == -1)
"Comments can be added indefinitely."
//Deny commenting if the item has not been updated within the allowed
//time range.
var d1 = item.Statistics.Updated;
var d2 = d1.AddDays(right.DaysToAllowComments);
(DateTime.Compare(d1, d2) != -1)
"Comments cannot be added after {0} {1}."
, d2.ToLongDateString(), d2.ToLongTimeString());
"Comments can be added until {0} {1}."
GetCurrentCommentCount(Item item)
//Get the number of children that are based on the template
//specified in the config file.
var templateId = Settings.GetSetting(
"CommentTemplate"
var path =
.Format(
"./*[@@templateid='{0}']"
, templateId);
var items = item.Axes.SelectItems(path);
(items ==
0;
(items.Length);
STEP 3 - Create AuthorizationProvider
Next I need to create an authorization provider. One thing an AuthorizationProvider does is use the ItemAuthorizationHelper to determine if an access right applies to an item.
Another thing an AuthorizationProvider does is handle access right caching. For my requirements, determining if an access right applies or not depends on the value of a field on the item (max comments field name). The value may change at any time. Since access rights don't ordinarily depend on specific items, changes to items do not cause access rights to cleared from the cache. For this reason, I do not want my custom access right to be cached. I need to create an AuthorizationProvider that works this way.
The following code implements the authorization provider that is needed:
MyAuthorizationProvider : SqlServerAuthorizationProvider
MyAuthorizationProvider()
_itemHelper =
MyItemAuthorizationHelper();
ItemAuthorizationHelper _itemHelper;
ItemAuthorizationHelper ItemHelper
_itemHelper; }
{ _itemHelper = value; }
AddAccessResultToCache(ISecurable entity, Account account, AccessRight accessRight, AccessResult accessResult, PropagationType propagationType)
//Do not cache the access result because the result depends
//on the value that is currently set on the item.
(accessRight.Name == CommentingRights.AddComments)
.AddAccessResultToCache(entity, account, accessRight, accessResult, propagationType);
STEP 4 - Create config file
Access rights are controlled using the web.config file. Rather than modify the web.config file directly, an include file should be used.
The following include file is needed. Please note that the specific IDs included below may not match the IDs on your Sitecore server:
<?
xml
version
=
"1.0"
?>
<
configuration
xmlns:patch
"http://www.sitecore.net/xmlconfig/"
>
sitecore
settings
<!--
Any item based on the template /sitecore/templates/Common/Folder should
be considered to be a comment for the purpose of determining if the max
comment count has been met.
-->
setting
name
value
"{A87A00B1-E6DB-45AB-8B54-636FEC3B5523}"
/>
</
authorization
<!-- Set the custom AuthorizationProvider as the default provider -->
patch:attribute
"defaultProvider"
>custom</
providers
clear
add
"custom"
type
"Sitecore.Marketing.AccessRights.MyAuthorizationProvider, Sitecore.Marketing.AccessRights"
connectionStringName
"core"
embedAclInItems
"true"
accessRights
rights
<!-- Add the custom access right -->
patch:before
"*[1]"
"commenting:addcomments"
comment
"Add comments."
title
"Add comments"
"Sitecore.Marketing.AccessRights.CommentingAccessRight, Sitecore.Marketing.AccessRights"
maxCommentsFieldName
"Max Comments"
daysToAllowComments
"30"
rules
Any access right whose name begins with "commenting" should apply to
any child items under /sitecore/content/.
prefix
"commenting"
ancestor
"{0DE95AE4-41AB-4D01-9EB0-67441B7C2450}"
"/sitecore/content"
STEP 5 - Define a constant to store the access right name
In the config file, access rights are named. In this example, the custom access right is named "commenting:addcomments". In a later step I will create a class that adds comments, but only if the access right allows it. In this code I will need to refer to this name.
Rather than hard-coding a name, I will create a class that defines the name as a constant. The following code serves this purpose:
CommentingRights
const
AddComments =
STEP 6 - Define CommentManager
The CommentManager class is used to add comments. This class includes the logic to determine if access rights allow the user to add comments.
The following code implements this logic:
CommentManager
CommentManager(Item item)
.Item = item;
Item Item {
bool
IsAddCommentAllowed
var right = AccessRight.FromName(CommentingRights.AddComments);
(right ==
false
var allowed = AuthorizationManager.IsAllowed(
.Item, right, Sitecore.Context.User);
allowed;
Item AddComment()
.IsAddCommentAllowed)
//TODO: Add logic to actually add a comment.
STEP 7 - Create a sublayout for adding comments
I am not going to detail the steps for creating a sublayout. The sublayout does not actually allow comments to be added. It simply displays a message that indicates if comments should be allowed or not.
The sublayout uses the following code:
System.Web.UI;
Sitecore.Marketing.AccessRights;
Sitecore.Marketing.AccessRights.Controls
partial
CommentingControl : System.Web.UI.UserControl
Render(HtmlTextWriter writer)
.Render(writer);
var commentManager =
CommentManager(Sitecore.Context.Item);
(commentManager.IsAddCommentAllowed)
writer.Write(
"Comments allowed"
else
"Comments NOT allowed"
STEP 8 - Compile and deploy
Now I need to compile the code and deploy the assembly and config file.
STEP 9 - Testing
I am using a clean installation of Sitecore for my testing. The first thing I want to test is if the custom access right is available in the Security Settings dialog.
Next Steps
Hopefully this sheds a little bit of light on the subject of access rights and how to interact with them. For more information, you should read the following documents available on SDN:
I'm curious to hear about how you have used custom access rights, or how you think you might use them in the future. Let me know in the comments!
Tags: API
- Lewanna Rathbun October 01, 2012 at 5:59 PM
- Adam Conn October 03, 2012 at 9:49 AM
- Andy Osika January 03, 2013 at 12:23 PM
Adam is a technical architect on Sitecore's Product Marketing Team. He is responsible for spreading technical knowledge inside and outside of the company, with an emphasis on external systems and applications.
This website is designed to be fully functional with scripts disabled in browser. Please contact the webmaster for any suggestions