force page permissions to cascade after children are created - General Discussions - General Discussions - Progress Community
 General Discussions

force page permissions to cascade after children are created

  • force page permissions to cascade after children are created
  • Hi.

    I programatically create a tree of pages.  When I create the children pages I set InheritsPermissions to true.
    After that. I set the permissions on the root page of the tree.
    However, the children pages do not then show that they have the same permissions.

    Is there a way I can force the permissions to cascade to the children?

  • Hi Phil,

    When a page node is created, it inherits permissions from its parent page node by default.
    For front-end pages, the topmost node is the Frontend root node under which pages can be created, and for back-end pages, the topmost node is the Backend root node.

    Note that a page node may inherit permissions from its parent node (or ancestor, if the inheritance chain is longer), in which case, the "effective" permissions are the inherited ones.
    Other permissions (which are attached directly to the page node) do not show in the UI, and are not effective when evaluating an action performed by a certain user.
    So, in the case you describe, the logic should be-

    1. The parent page is created.
    2. The parent page breaks the permissions inheritance.
      This is done by calling the manager's BreakPermiossionsInheritance method.
    3. Any specific permissions are created and added to the parent.
    4. A child page is created and defined as a child of the parent.
      This automatically defines the child page as inheritor of the parent page's permissions.
      It is possible, however not advised, to force-create the permissions inheritance relation between 2 secured objects by calling the manager's CreatePermissionInheritanceAssociation method.
      This is, in fact, the method which is called when the child is created which defines the inheritance relation.

    Note that steps 2-3 can be applied at any point, either before or after the child is created.
    Skipping step 2, would cause the permission not to be available in the UI, and not effective in terms of security constraints.

    Another important point to note is that since objects which inherit permissions may differ from each other (e.g. blog posts inherit from permissions from their relative blogs) or may even come from different providers, a transaction must be used when creating/fetching the objects and adding permissions to them.

    In order to ensure that the permissions cascade down the hierarchy as they should, they should not be added manually to the Permissions collection, but instead they should be added by calling the manager's AddPermissionToObject method.

    Here's a small piece of sample code which demonstrates the process:

     It creates 3 page nodes:
    "New Page 1" (topPage variable) which is created under the front-end root (lines 12-22),
    "Child Page 2" which is created as a child of "New Page 1" (lines 44-55) and
    "Grandchild Page 3" which is created as a child page of "Child Page 2" (lines 62-72).

    Notice that PageManager instance pm works with a transaction (line 2), when new permissions are added they also use the same transaction (lines 42 and 91).

    The top page of the 3 breaks the permissions inheritance and then adds a permission which denies "SomeRole" from modifying the page (lines 24-42).
    The 2 other pages are created as sub-pages of each other, thus they inherit the permissions in hierarchy.
    The end result is that the added permission is inherited down the tree, visible in the UI and should be effective for any users of "SomeRole".

    After all pages are created, another permission is added at the top level, to the topPage (lines 74-91). This new permission also cascades down the tree to the inheritors.
    In the end, the transaction is committed (line 93), and all changes are saved and applied.

    01.string transactionName = "transact" + Guid.NewGuid().ToString();
    02.PageManager pm = PageManager.GetManager(null, transactionName);
    03.RoleManager rm = RoleManager.GetManager();
    05.Role someRole = rm.GetRole("SomeRole");
    06.PageNode frontendRoot = pm.GetPageNode(SiteInitializer.FrontendRootNodeId);
    08.string topPageTitle = "New Page 1";
    09.string childPageTitle = "Child Page 2";
    10.string grandchildPageTitle = "Grandchild Page 3";
    12.//Create the top page, if doesn't exist
    13.PageNode topPage = pm.GetPageNodes()
    14.  .Where(node => node.Title == topPageTitle)
    15.  .FirstOrDefault();
    16.if (topPage == null)
    18.  topPage = pm.CreatePage(
    19.    frontendRoot, Guid.NewGuid(),
    20.    PageType.Standard);
    22.topPage.Page.Title = topPageTitle;
    24.//The top page does not inherit permissions, but uses its own;
    26.//Create the permission if doesn't exist
    27.Permission someRolePermission = pm.GetPermission(
    28.  SecurityConstants.Sets.Pages.SetName,
    29.  topPage.Id,
    30.  someRole.Id);
    31.if (someRolePermission == null)
    32.  someRolePermission = pm.CreatePermission(
    33.    SecurityConstants.Sets.Pages.SetName,
    34.    topPage.Id,
    35.    someRole.Id);
    36.//Deny some role from modifying
    38.  true,
    39.  SecurityConstants.Sets.Pages.Modify);
    40.//Add the permission to the page, if it's not already there
    41.if (!topPage.Permissions.Contains(someRolePermission))
    42.  pm.AddPermissionToObject(topPage, someRolePermission, transactionName);
    44.PageNode childPage = pm.GetPageNodes()
    45.  .Where(node => node.Title == childPageTitle)
    46.  .FirstOrDefault();
    47.if (childPage == null)
    49.  //the child page inherits permissions from its parent by default
    50.  childPage = pm.CreatePage(
    51.    topPage,
    52.    Guid.NewGuid(),
    53.    PageType.Standard);
    55.childPage.Page.Title = childPageTitle;
    57.//It's possible to manually make sure the inheritance is applied,
    58.//by calling CreatePermissionInheritanceAssociation:
    60.//pm.CreatePermissionInheritanceAssociation(topPage, childPage);
    62.PageNode grandchildPage = pm.GetPageNodes()
    63.  .Where(node => node.Title == grandchildPageTitle)
    64.  .FirstOrDefault();
    65.if (grandchildPage == null)
    67.  //the grandchild page inherits permissions from the child page by default
    68.  grandchildPage = pm.CreatePage(
    69.    childPage, Guid.NewGuid(),
    70.    PageType.Standard);
    72.grandchildPage.Page.Title = grandchildPageTitle;
    74.//Create a permission AFTER the pages exist
    75.Role anotherRole = rm.GetRole("anotherRole");
    76.Permission anotherRolePermission = pm.GetPermission(
    77.  SecurityConstants.Sets.Pages.SetName,
    78.  topPage.Id,
    79.  anotherRole.Id);
    80.if (anotherRolePermission == null)
    81.  anotherRolePermission = pm.CreatePermission(
    82.    SecurityConstants.Sets.Pages.SetName,
    83.    topPage.Id,
    84.    anotherRole.Id);
    85.//Deny some role from deleting
    87.  true,
    88.  SecurityConstants.Sets.Pages.Delete);
    89.//Add the permission to the page, if it's not already there
    90.if (!topPage.Permissions.Contains(anotherRolePermission))
    91.  pm.AddPermissionToObject(topPage, anotherRolePermission, transactionName);

    I hope this helps. Should you require any further assistance on this topic, please provide additional information about your specific scenario, and how exactly you create the page's hierarchy and permissions.

     Kind regards,
    Alon Rotem
    the Telerik team
    • OK.  My permissions are cascading down the tree much better now. The key is that I am creating the root page; setting permissions; THEN creating the rest of the tree.


    The problem at this time is that the last pages in the tree are not inheriting the permissions they way that they should.  They are copies of existing pages. The code that I am using to create them is here:

    guidSourcePage is the guid of the page that I am copying. The other variables are self explanatory.
    public bool CopyAPage(Guid guidSourcePage, Guid parentId, string newPageName)
        var mgr = App.WorkWith().Page(guidSourcePage);
        PageNode parentPage = mgr.PageManager.GetPageNodes().
            Where(pi => pi.Id == parentId).OrderByDescending(pd => pd.DateCreated).FirstOrDefault();
                p =>
                    p.Title = newPageName;
                    p.UrlName = newPageName; 
                    p.ShowInNavigation = true;
                    p.Parent = parentPage;    // parentPage is a PageNode object
                    p.CanInheritPermissions = true;
                    p.InheritsPermissions = true;
                    if (p.Page != null)
                        // This is a normal page with Page Data (not a group page)
                        p.Page.Title = newPageName;
        return true;

     - In the finished pages tree, the parent pages to these copies have all the permissions that I want them to have; but these copies do not.
     - The original pages (which I am making the copies of):
           - are children to a page which is a child to the SF front end root
           - in other words, they are not, themselves, children to the SF front end root (not sure if that matters)
     - I noticed that the original pages had InheritPermissions = true, so
           - I ran the code that way and
           - I broke the inheritance on the original pages and ran the code that way and got the same (unsatisfactory) results.

    What do I need to change in my code to make the copies I am creating inherit permissions from their new parent pages?

  • Hello Phil,

    Thanks for the update.

    This time I wasn't able reproduce your problem by re-using your code, which means you're probably doing something right (or I'm doing something wrong).

    Here's what I tried to do:

    Initially I had 2 pages in the system, where one is defined to be a parent of the other.

    In this sample, ParentPage was breaking the permission inheritance, and has its own permissions set.

    ChildPage was inheriting its permissions from its parent, namely from ParentPage.

    Now using your code, I'm trying to create a sibling to ChildPage which would inherit permissions from ParentPage, just lilke ChildPage does.
    This is my code, which is 1:1 adaptation of yours:

    01.void CreateSibling()
    03.    Guid guidSourcePage = App
    04.        .WorkWith()
    05.        .Pages()
    06.        .Get()
    07.        .Where(node => node.Title == "ChildPage").FirstOrDefault().Id;
    08.    Guid parentId = App
    09.        .WorkWith()
    10.        .Pages()
    11.        .Get()
    12.        .Where(node => node.Title == "ParentPage").FirstOrDefault().Id;
    13.    string newPageName = "New Sibling";
    15.    var mgr = App.WorkWith().Page(guidSourcePage);
    16.    PageNode parentPage = mgr
    17.        .PageManager.GetPageNodes()
    18.        .Where(pi => pi.Id == parentId)
    19.        .OrderByDescending(pd => pd.DateCreated).FirstOrDefault();
    21.    mgr.Duplicate().Do(
    22.            p =>
    24.                p.Title = newPageName;
    25.                p.UrlName = newPageName;
    26.                p.ShowInNavigation = true;
    27.                p.Parent = parentPage;
    28.                p.CanInheritPermissions = true;
    29.                p.InheritsPermissions = true;
    30.                if (p.Page != null)
    32.                    p.Page.Title = newPageName;
    34.            ).SaveChanges();

    I placed it in a sample page, and ran it (as an event handler of a click of a button, but that does not matter).
    The result, in terms of the pages hierarchy tree was:

    And in terms of permissions, New Siblinb now inherits permissions just like its brother, ChildPage:

    - which I think is what you were trying to achieve...

    Thus, in order to assist you better, I'd need additional information about the version and build of Sitefinity which you are using, and additional details about your system, its configuration and the scenario.
    I hope this information helps. Please provide additional information about your case, should you need additional help.

    All the best,
    Alon Rotem
    the Telerik team