linuse
May 9, 2014
  11178
(7 votes)

Restricting access to who is allowed to edit a certain property

I did a presentation in Oslo about a month ago and one thing in EPiServer 7.5 that I wanted to emphasize on is the support for the IMetadataAware attribute. This, in combination with implementing a ValidationAttribute is very powerful and in this blog post I’ll show an example on how this can be used. The goal is to create an attribute when you can control which roles are required to edit a specific property.

First, let us look on how we can make a property that makes the property read only in the editorial interface. Here’s the code for the attribute :

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
 
namespace EPiServer.Samples
{
    public class PropertyEditRestrictionAttribute : ValidationAttribute, IMetadataAware
    {
        public PropertyEditRestrictionAttribute(string[] allowedRoles)
        {
            AllowedRoles = allowedRoles;
        }
 
        public string[] AllowedRoles { get; set; }
 
        public void OnMetadataCreated(ModelMetadata metadata)
        {
            foreach (string role in AllowedRoles)
            {
                if (EPiServer.Security.PrincipalInfo.CurrentPrincipal.IsInRole(role))
                {
                    return;
                }
            }
            metadata.IsReadOnly = true;
        }
    }
}

 

And the usage on the model like this:

[PropertyEditRestriction(new string[]{"administrators2"})]
public virtual XhtmlString MainBody { get; set; }

 

Notice the rather odd group name “administrators2” just to make sure I’m not part of this group.

If we pop into the EPiServer UI, we can see that the editor has been disabled in the forms view:

ReadOnly

 

In the On-Page edit view, the property looks editable but when clicking on the overlay, a read only editor is loaded. There has actually been a bug fix recently that removes the overlay entirely when the property is not editable that’s been sent for testing and will hopefully be release withing a week or two.

ReadOnlyOnPageEdit

 

What about validation on the server?

The code above is really simple and probably solves the customer requirements in most cases. But since this only affects the editorial interface, it is of course possible to post a fake property update to the server even without having the correct access. Let’s see how we can add server validation as well to the same attribute.

using System;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using EPiServer.Core;
 
namespace EPiServer.Samples
{
    public class PropertyEditRestrictionAttribute : ValidationAttribute, IMetadataAware
    {
        public PropertyEditRestrictionAttribute(string[] allowedRoles)
        {
            AllowedRoles = allowedRoles;
        }
 
        public string[] AllowedRoles { get; set; }
 
        public void OnMetadataCreated(ModelMetadata metadata)
        {
            foreach (string role in AllowedRoles)
            {
                if (EPiServer.Security.PrincipalInfo.CurrentPrincipal.IsInRole(role))
                {
                    return;
                }
            }
            //Comment row below to test the server validation.
            metadata.IsReadOnly = true;
        }
 
        public override string FormatErrorMessage(string name)
        {
            return "You do not have access to change " + name;
        }
 
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var contentData = validationContext.ObjectInstance as IContentData;
            if (contentData == null)
            {
                //This attribute only handles instances of IContentData.
                return ValidationResult.Success;
            }
            if (!contentData.Property[validationContext.MemberName].IsModified)
            {
                return ValidationResult.Success;
            }
            if (Validate())
            {
                return ValidationResult.Success;
            }
            else { return new ValidationResult("You do not have access"); }
        }
 
        public override bool RequiresValidationContext
        {
            get
            {
                return true;
            }
        }
 
        public bool Validate()
        {
            foreach (string role in AllowedRoles)
            {
                if (EPiServer.Security.PrincipalInfo.CurrentPrincipal.IsInRole(role))
                {
                    return true;
                }
            }
            return false;
        }
    }
}

 

For demonstration purposes, we can comment out the line that makes the property readonly, and edit the property to validate that the server validation actually does work.

ServerValidation

May 09, 2014

Comments

May 12, 2014 10:17 AM

Great that we won't be needing to set this per Tab!

May 12, 2014 03:02 PM

Nice! Very useful, and eliminates the need for the per tab approach as Alf mentioned.

valdis
valdis May 13, 2014 07:55 AM

Nice!

Al Higgs
Al Higgs May 14, 2014 01:33 PM

This will be so useful! Great work

Jens Qvist
Jens Qvist May 15, 2014 09:06 AM

Sweet! Very useful!

Ted
Ted May 15, 2014 01:56 PM

Excellent work, Linus!

Arve Systad
Arve Systad May 16, 2014 11:42 AM

I want to do exactly this with the Code property in Commerce (since it's only going to be set once from an import job) - can I just override it in my product/variation classes and apply the attribute, or will that cause some other weird problems?

May 16, 2014 11:48 AM

Arne: I see no reason why this should not work given that you are working in EPiServer 7.5 with the typed model support for Commerce. You should also be able to set the metadata property ShowForEdit if you want to hide the value entirely from the editors.

Arve Systad
Arve Systad May 16, 2014 12:35 PM

Good stuff!

Arve Systad
Arve Systad May 16, 2014 01:56 PM

Works like a charm. It also seems to still pick up other attributes on the base classes, which is a nice thing.

Justin Le
Justin Le Dec 2, 2014 03:01 AM

Really nice!

spreston.mbauk
spreston.mbauk Apr 29, 2015 12:21 PM

Very nice and useful. Just a quick question: How do I set a string array in the code and then pass that through with the 

[PropertyEditRestriction(new string[]{"administrators2"})]

This would allow me to set the allowed users just once in the code, as opposed to on every property, which would be very useful should requirements change.

patrik.nordin@it-huset.se
patrik.nordin@it-huset.se Jan 21, 2016 01:32 PM

Nice one, thanks!

Jean Teneglio
Jean Teneglio Apr 4, 2019 06:19 PM

I tried just that and for some reason it does not work for me

I have Episerver version 11

Jean Teneglio
Jean Teneglio Apr 4, 2019 06:19 PM

I tried just that and for some reason it does not work for me

I have Episerver version 11

linuse
linuse Apr 10, 2019 01:05 PM

Hi Jean,

I tried it with the latest version of the Episerver CMS packages (v 11.X) and it still works. The code seems to be case sensitive, so take that into consideration. I have a Github repo with a lot of code examples for Episerver including this that can be found here.

Robin Lindbladh
Robin Lindbladh Sep 2, 2019 07:24 AM

Awesome post, thank you!

Sriram raja
Sriram raja Jun 10, 2020 07:37 AM

can any one please help for this, i need for each users like admin, editors etc..

linuse
linuse Oct 14, 2020 01:20 PM

You should be able to limit access to who can see each tab in the tab configuration in admin.

Please login to comment.
Latest blogs
The 1001st Piece in your 1000 Piece Puzzle: .NET Default Interface Functions

I was recently working with a client who wanted a reasonably large subsystem added to Optimizely that would add automated management to their...

Greg J | Nov 28, 2022 | Syndicated blog

Video Demonstration, creating a CMS12 Alloy Sample Site

Hey All Below you will find a quick video demonstration on how to install a local version of Alloy Sample based on CMS12 / .Net 6. As you will see ...

Minesh Shah (Netcel) | Nov 28, 2022

How to create an admin user I Optimizely CMS – with Episerver CLI

In this blog post I’ll show how to create an admin user for Optimizely CMS in a new environment where you don’t have access to the admin interface.

Ove Lartelius | Nov 28, 2022 | Syndicated blog

Optimizely shortcuts in CMS 12 will get a trailing slash appended!

Not all URLs will work when the trailing slash is added, and that could cause problems. Hopefully it will be fixed soon.

Tomas Hensrud Gulla | Nov 26, 2022 | Syndicated blog

One week left of the beta certification period

Today it's one week until the last beta certification day. Do you exam no later than Wednesday the 30th.  Here are the reference and exam guides:...

Karen McDougall | Nov 23, 2022

Unbelievable FREE Heatmapping With Optimizely Web

Within this guide, you will learn how to integrate a free heat mapping tool to Optimizely Web so you can turbocharge your A/B testing capabilities....

Jon Jones | Nov 22, 2022 | Syndicated blog