locked
Permissions on documents in a library, based on multiple meta data. RRS feed

  • Question

  • So, I think I have found my way to an answer, but wanted to throw it out there for the greater community to ponder before I start building...
    Scenario:
    Single document library. Trying to avoid folders. Each document has a security level (1-5; 1 being low, 5 being high) and a service (location) associated with it.
    The many employees can be associated to a group of level accessing users...that is, if you're in the level 3 group, you can see docs of security clearance 1, 2 and 3, but not 4 and 5.
    Each employee can belong to one or more 'service' (think office).
    What we need to do is ensure each user can access only those documents of the appropriate level and in a service within which they are associated (can be driven out of another list).
    I have not built a custom view here cos unless you specify the permission on the document, someone could just guess the URL/ID of the doc and see unauthorised content (right?).
    My current thinking is to use a batch/powershell script to run every 'x' minutes and process those files modified in the last 'x' minutes (or associated to services which have been updated in the last x minutes) and iterate thru the doc lib setting permissions for each user as appropriate. Do a nightly full sync on all docs in the lib.
    Concerns:
    Nightmare to support/debug permissions mis-configs
    Could take a long time once there's many thousands of files in there
    Anyway, at the risk of opening pandoras box, anyone else got a brighter idea...?
    (BTW, looked at titus labs, and given the volume of data/way you construct rules there in, it's going to be high admin overhead)
    Thanks in advance
    Iain
    Monday, November 7, 2011 2:14 AM

Answers

  • Heres how you can implement Metadata security at item level. Beware that you can add it but managing individual permission on thousands of items is a headache.

    1. You need to make sure that Sharepoint Group with Appropriate permissions are present.

    2. Add a new site column called MetaDataSecurity to the document library where you want item level changes.

    3. Create an SharePoint 2010 Solution and Add EventReceiver to your list (timer jobs are also good way as you can schedule them at night after working hours)

     

    4. Override ItemAdding or other event(you need to think of from where you will get the column based on which you will apply security) as needed and add below code

     

    using System;

    using Microsoft.SharePoint;

    using System.Collections.Generic;

     

     

            public override void ItemAdding(SPItemEventProperties properties)

            {

                System.Diagnostics.Debug.WriteLine("ChangeSecurityListEventReceiver.ItemAdding(): begin");

                try

                {

                    EventFiringEnabled = false;

     

                    SPList list = properties.List;

                    SPListItem item = properties.ListItem;

                    string MetaDataSecurity = string.Empty;

     

                    MetaDataSecurity = (string)properties.AfterProperties["MetaDataSecurity"];

     

                    if (!string.IsNullOrEmpty(MetaDataSecurity))

                    {

                        EventFiringEnabled = false;

     

                        // break the security inheritence

                        item.BreakRoleInheritance(true);

     

                        List<SPRoleAssignment> roleToDel = new List<SPRoleAssignment>();

     

                        foreach (SPRoleAssignment ra in item.RoleAssignments)

                        {

                            roleToDel.Add(ra);

                        }

     

                        foreach (SPRoleAssignment ra in roleToDel)

                        {

                            item.RoleAssignments.Remove(ra.Member);

                        }

     

                        //Now add the correct security group for this individual

                        try

                        {

     

                            SPGroup S_ContentApprovers = properties.Web.SiteGroups[MetaDataSecurity];

                            SPRoleDefinition S_ContentApproversDefinition = properties.Web.RoleDefinitions[MetaDataSecurity];

     

                            SPRoleAssignment S_ContentApproversRoleAssignment = new SPRoleAssignment(S_ContentApprovers);

                            S_ContentApproversRoleAssignment.RoleDefinitionBindings.Add(S_ContentApproversDefinition);

     

                            item.RoleAssignments.Add(S_ContentApproversRoleAssignment);

                        }

                        catch (Exception ex)

                        {

                            System.Diagnostics.Debug.WriteLine("ChangeSecurityListEventReceiver.ItemAdding() exception" + ex.ToString());

                            properties.Cancel = true;

                            properties.ErrorMessage = ex.ToString();

                        }

                    }

     

                }

     

                catch (Exception ex)

                {

                    System.Diagnostics.Debug.WriteLine("ChangeSecurityListEventReceiver.ItemAdding() exception" + ex.ToString());

                    properties.Cancel = true;

                    properties.ErrorMessage = ex.ToString();

                }

     

                finally

                {

                    //EventFiringEnabled = true;

                }

                System.Diagnostics.Debug.WriteLine("ChangeSecurityListEventReceiver.ItemAdding(): end");

            }

     

     

    5. When creating new item fill the field MetaDataSecurity with the group already present SPGroup1, SPGROUP2 etc. or added by you.

     

    Some useful resources 

    http://spdactivities.codeplex.com/discussions/263425

    http://sharepoint.stackexchange.com/questions/19771/powershell-item-level-permission-by-content-type

           

     

    • Marked as answer by Iain Simms Wednesday, November 9, 2011 11:01 PM
    Wednesday, November 9, 2011 2:38 PM
  • Source

    Security scope

    1,000 per list

    Threshold

    The maximum number of unique security scopes set for a list should not exceed 1,000.

    A scope is the security boundary for a securable object and any of its children that do not have a separate security boundary defined. A scope contains an Access Control List (ACL), but unlike NTFS ACLs, a scope can include security principals that are specific to SharePoint Server. The members of an ACL for a scope can include Windows users, user accounts other than Windows users (such as forms-based accounts), Active Directory groups, or SharePoint groups.

    Vote if useful :)


    Kind regards, HeToC. http://www.linkedin.com/in/hetoc
    • Marked as answer by Iain Simms Wednesday, November 9, 2011 11:01 PM
    Wednesday, November 9, 2011 10:37 PM
  • Thanks

    I found this link: http://technet.microsoft.com/en-us/library/cc287792(office.12).aspx which talks about the same.

    So, I guess I am back to the use of folders again....!

    And even then, if there's over 1000 uniquely secured folders, I'm screwed...! 

    • Marked as answer by Iain Simms Wednesday, November 9, 2011 11:01 PM
    Wednesday, November 9, 2011 11:01 PM

All replies

  • Hello Iain Simms,

    You can do these custom implementations through code for perfect solution. The idea you are proposing is leading to some security issues. Take below scenario.

    I have uploaded a document to document library which is of Security level 4. And at the same time my other colleague logged into the site and opened the same document library where I am in and his/her security level is 3. As there is a time lag that you are running a powershell script for every n minutes or so, user can able to see those document which the security permissions are not set yet. 

    Solution1:

    The ideal way we should do this is, writing event receivers. When an item is updated then you have to set these permissions item level. ItemUpdated event which helps to build it well. 

    Solution 2:

    Create one document library for each security level in the SharePoint site and give access to the user groups who needs access to them. This will work out for sure without any coding.

    Let me know if you need any other help, suggestions.

    thanks


    ASP.NET and SharePoint developer
    Blog: http://praveenbattula.blogspot.com
    Please click "Propose As Answer" if a post solves your problem or "Vote As Helpful" if a post has been useful to you.
    Monday, November 7, 2011 2:45 AM
  • OK...thanks.

    How are event receivers handled...? Because, if for example there's let's say 100,000 documents belonging to service A, then any change to the list of users having access to service A will result in having to execute a change on the permissions to all of those 100,000 documents. And this is the challenge with my powershell idea.

    I've done a little digging here and I think we're well and truly in the custom code arena...so, here is perhaps what would be the ideal scenario...

    Rather than any of the above where we're doing a security set at the time of save, or after the document has been saved...do a check on the security of the doc at the time a retrieve is attempted. Whether that be a full retrieve of the document, or simply listing it in a view or search results.

    How would I put something in place to intercept those calls and do my security checking there...?

    Thanks

    Iain

     

     

     

    Monday, November 7, 2011 3:25 AM
  • OK...I have admitted defeat...

    Because security must be applied on the document level (or on a container of the document...namely folder or library) for it to be respected in search and other areas, I am going to HAVE to use folders as meta data effectively.

    Given the volume we're looking at, I will use your suggestion of event handlers to capture a change in another list where users are associated to services and levels, and administer permissions groups, and folders that way.

    Frustrating...but there you go...

    Given MS is trying to steer people away from folders, I find it surprising that security on meta data is not available, but is on a folder.

     

    Tuesday, November 8, 2011 11:49 PM
  • Heres how you can implement Metadata security at item level. Beware that you can add it but managing individual permission on thousands of items is a headache.

    1. You need to make sure that Sharepoint Group with Appropriate permissions are present.

    2. Add a new site column called MetaDataSecurity to the document library where you want item level changes.

    3. Create an SharePoint 2010 Solution and Add EventReceiver to your list (timer jobs are also good way as you can schedule them at night after working hours)

     

    4. Override ItemAdding or other event(you need to think of from where you will get the column based on which you will apply security) as needed and add below code

     

    using System;

    using Microsoft.SharePoint;

    using System.Collections.Generic;

     

     

            public override void ItemAdding(SPItemEventProperties properties)

            {

                System.Diagnostics.Debug.WriteLine("ChangeSecurityListEventReceiver.ItemAdding(): begin");

                try

                {

                    EventFiringEnabled = false;

     

                    SPList list = properties.List;

                    SPListItem item = properties.ListItem;

                    string MetaDataSecurity = string.Empty;

     

                    MetaDataSecurity = (string)properties.AfterProperties["MetaDataSecurity"];

     

                    if (!string.IsNullOrEmpty(MetaDataSecurity))

                    {

                        EventFiringEnabled = false;

     

                        // break the security inheritence

                        item.BreakRoleInheritance(true);

     

                        List<SPRoleAssignment> roleToDel = new List<SPRoleAssignment>();

     

                        foreach (SPRoleAssignment ra in item.RoleAssignments)

                        {

                            roleToDel.Add(ra);

                        }

     

                        foreach (SPRoleAssignment ra in roleToDel)

                        {

                            item.RoleAssignments.Remove(ra.Member);

                        }

     

                        //Now add the correct security group for this individual

                        try

                        {

     

                            SPGroup S_ContentApprovers = properties.Web.SiteGroups[MetaDataSecurity];

                            SPRoleDefinition S_ContentApproversDefinition = properties.Web.RoleDefinitions[MetaDataSecurity];

     

                            SPRoleAssignment S_ContentApproversRoleAssignment = new SPRoleAssignment(S_ContentApprovers);

                            S_ContentApproversRoleAssignment.RoleDefinitionBindings.Add(S_ContentApproversDefinition);

     

                            item.RoleAssignments.Add(S_ContentApproversRoleAssignment);

                        }

                        catch (Exception ex)

                        {

                            System.Diagnostics.Debug.WriteLine("ChangeSecurityListEventReceiver.ItemAdding() exception" + ex.ToString());

                            properties.Cancel = true;

                            properties.ErrorMessage = ex.ToString();

                        }

                    }

     

                }

     

                catch (Exception ex)

                {

                    System.Diagnostics.Debug.WriteLine("ChangeSecurityListEventReceiver.ItemAdding() exception" + ex.ToString());

                    properties.Cancel = true;

                    properties.ErrorMessage = ex.ToString();

                }

     

                finally

                {

                    //EventFiringEnabled = true;

                }

                System.Diagnostics.Debug.WriteLine("ChangeSecurityListEventReceiver.ItemAdding(): end");

            }

     

     

    5. When creating new item fill the field MetaDataSecurity with the group already present SPGroup1, SPGROUP2 etc. or added by you.

     

    Some useful resources 

    http://spdactivities.codeplex.com/discussions/263425

    http://sharepoint.stackexchange.com/questions/19771/powershell-item-level-permission-by-content-type

           

     

    • Marked as answer by Iain Simms Wednesday, November 9, 2011 11:01 PM
    Wednesday, November 9, 2011 2:38 PM
  • If you don't have a requirement your documents to be searchable you could use Audience targeting settings for your custom List Views so you won't have problems with oversized ACL in the future similar to what we got a time ago.

    Otherwise using separate taxonomy tree and custom metadata field for the library, is the best approach (Dinesh post).


    Kind regards, HeToC. http://www.linkedin.com/in/hetoc
    Wednesday, November 9, 2011 3:24 PM
  • Thank you Dinesh and HeToC.

    Ref 'oversized ACL'...what was the issue there...? Can you describe it better so that we can avoid where possible...? Is there some kind of limit to the number of permissions entries one can have on contents of a library? We DO have the absolute requirement to prevent access at the document level, and for them to be searchable...not just preventing visibility of the doc.

    Dinesh...the approach you outlined is VERY similar to the one that Titus Labs can employ and can use to address the issue...after working with the guys @ Titus Labs, their object looks like it will do the job nicely, albeit with the integration overhead...but they do also wrap it up in a very nice package/UI, etc...so it becomes the usual build or buy trade off. Also...if you didn't want to jump in and build an event handler, you could achieve same with a powershell script, and accept there's a lag around permissions implementation....which may be acceptable based on your scenario.

     

     

    Wednesday, November 9, 2011 10:00 PM
  • Source

    Security scope

    1,000 per list

    Threshold

    The maximum number of unique security scopes set for a list should not exceed 1,000.

    A scope is the security boundary for a securable object and any of its children that do not have a separate security boundary defined. A scope contains an Access Control List (ACL), but unlike NTFS ACLs, a scope can include security principals that are specific to SharePoint Server. The members of an ACL for a scope can include Windows users, user accounts other than Windows users (such as forms-based accounts), Active Directory groups, or SharePoint groups.

    Vote if useful :)


    Kind regards, HeToC. http://www.linkedin.com/in/hetoc
    • Marked as answer by Iain Simms Wednesday, November 9, 2011 11:01 PM
    Wednesday, November 9, 2011 10:37 PM
  • Thanks

    I found this link: http://technet.microsoft.com/en-us/library/cc287792(office.12).aspx which talks about the same.

    So, I guess I am back to the use of folders again....!

    And even then, if there's over 1000 uniquely secured folders, I'm screwed...! 

    • Marked as answer by Iain Simms Wednesday, November 9, 2011 11:01 PM
    Wednesday, November 9, 2011 11:01 PM
  • I made an event receiver for SharePoint 2013 that restricts edits to a file based on one of its metadata field values.  This does not modify the permissions (which would effect performance in large libraries), but does provide an error message when they try to save a change.

    Open source download here:

    http://rrfreeman.blogspot.com/2016/07/restricted-edit-event-receiver.html


    RobertRFreeman


    Friday, July 22, 2016 11:19 PM