I looked for a long time on the forum and various places to see how best to implement something simple, like a way to control display of the menu navigation based on group access from FEU. I saw the funny page alias exclude prefix thing, but that appears to require me to hack up a simple nav menu template and force a kind of ordering that I may not want and makes it harder to assign permissions for each page.
So assuming there was not a better way, I just added the following code to action.default.php for CustomContent which, before it passes all the nav menu nodes to smarty, runs through each node and does an access check. If the access is not allowed, based on group membership, it deletes the node. NOTE: This in no way restricts access for the given page if someone where to just access the url directly - you should check that on your on. But this will hide the nav link for the page which is sometimes a good poor man's approach to security if your stuff isn't all that sensitive.
I decided to make the allowed group access to be overloaded in the Title Attribute field for a given content page. This seemed to be the only place I could put something without adding a whole new database field and a lot more code changes in other files.
The format is: 'access:group1[,group2,] ..." in that field. The field is cleansed of this data before it is passed on to be rendered so that if you use it, it won't show up. So you could have something like "access:Managers This is my description" in the field and when rendered, just the "This is my description" will show up.
Hope this might be helpful to others, I really like CMSMS, a very cool package. The code below is a snippet with a few lines of code before it to give you an indicator of where to plug it in:
#See if origdepth was ever set... if not, then get it from the prevdepth set earlier
if ($origdepth == 0)
$origdepth = $prevdepth;
if (isset($rootnode) && $getchildren)
$this->GetChildNodes($rootnode, $nodelist, $gCms, $prevdepth, $count, $params, $origdepth, $showparents);
// Hack by DML - add access control - if the access: xxxx is on the titleattribute for the node, then restrict access
// First setup an ability to access the FEU module to look at groups
$feu_module =& $this->GetModuleInstance('FrontEndUsers');
$feu_uid = $feu_module->LoggedInId();
foreach ($nodelist as $nodeid => $node) {
// See if we have the special access:x,y,z tag in tite attribute, if so grab it, if not, skip
if (!preg_match('/access:\s*(.*)?\s*/',$node->titleattribute, $matches)) {
// Nothing here to see ... keep moving along folks
continue ;
}
$access_allowed = false ; // Assume the worst
// We have a winner ...
// Before we forget, remove the nonstandard access: stuff from the title attribute field
$nodelist[$nodeid]->titleattribute = preg_replace('/access:.*?\s*/','',$node->titleattribute) ;
// split out the access as csv and check each group against our access list
$groups = explode(',',$matches[1]) ;
// Logic is to loop until we find a match, once we do we set a good flag and break out
foreach ($groups as $group) {
$feu_gid = $feu_module->GetGroupID($group);
// If they have access, then mark it and break out
if( $feu_module->MemberOfGroup($feu_uid, $feu_gid) ) {
$access_allowed = true ;
break ;
}
}
// If access not allowed, we delete the node completed so it doesn't get passed into smarty at all
if (!$access_allowed) {
unset($nodelist[$nodeid]) ; // Remove this bad boy so it won't be seen
}
}
// End of hack
Hack to MenuManager to easier Menu Navigation control based on FEU Groups
Re: Hack to MenuManager to easier Menu Navigation control based on FEU Groups
Since i am on a roll, I also found a need to reverse the access. Meaning, if you are part of a group, I want to NOT show the Menu Item. The format in the Title Attribute field for the content page would be:
access:~Subscribers
This means if you are a member of the Subscribers group it will not show you the menu item. The exception is if the user is a member of the Subscribers and some other group that would other wise allow access, the higher access right is granted. For example:
access:~Subscribers,Manager
Would allow managers access, even if they are also a member of the Subscribers group as well.
Here's the modified code to include a small fix to do a case-insentive search on the access: string:
foreach ($nodelist as $nodeid => $node) {
// See if we have the special access:x,y,z tag in tite attribute, if so grab it, if not, skip
if (!preg_match('/access:\s*(.*)?\s*/i',$node->titleattribute, $matches)) {
// Nothing here to see ... keep moving along folks
continue ;
}
$access_allowed = false ; // Assume the worst
// We have a winner ...
// Before we forget, remove the nonstandard access: stuff from the title attribute field
$nodelist[$nodeid]->titleattribute = preg_replace('/access:.*?\s*/i','',$node->titleattribute) ;
// split out the access as csv and check each group against our access list
$groups = explode(',',$matches[1]) ;
// Logic is to loop until we find a match, once we do we set a good flag and break out
foreach ($groups as $group) {
// Check to see if we are negating the group, if so we switch the logic so that we deny access
if ($group = preg_replace('/^~/','',$group)) {
$access_group = false ;
} else {
$access_group = true ;
}
$feu_gid = $feu_module->GetGroupID($group);
// If they have access, then mark it and break out
if( $feu_module->MemberOfGroup($feu_uid, $feu_gid) && $access_group ) {
$access_allowed = true ;
}
}
// If access not allowed, we delete the node completed so it doesn't get passed into smarty at all
if (!$access_allowed) {
unset($nodelist[$nodeid]) ; // Remove this bad boy so it won't be seen
}
}
My next thought is that it may be easy to extend this a little further to also modify the content rendering logic to do a similar check so that if a link is given to someone to visit, they would not be allowed in either. Just a good place to consolidate all the logic with access controls by group instead of embedding on every page...
access:~Subscribers
This means if you are a member of the Subscribers group it will not show you the menu item. The exception is if the user is a member of the Subscribers and some other group that would other wise allow access, the higher access right is granted. For example:
access:~Subscribers,Manager
Would allow managers access, even if they are also a member of the Subscribers group as well.
Here's the modified code to include a small fix to do a case-insentive search on the access: string:
foreach ($nodelist as $nodeid => $node) {
// See if we have the special access:x,y,z tag in tite attribute, if so grab it, if not, skip
if (!preg_match('/access:\s*(.*)?\s*/i',$node->titleattribute, $matches)) {
// Nothing here to see ... keep moving along folks
continue ;
}
$access_allowed = false ; // Assume the worst
// We have a winner ...
// Before we forget, remove the nonstandard access: stuff from the title attribute field
$nodelist[$nodeid]->titleattribute = preg_replace('/access:.*?\s*/i','',$node->titleattribute) ;
// split out the access as csv and check each group against our access list
$groups = explode(',',$matches[1]) ;
// Logic is to loop until we find a match, once we do we set a good flag and break out
foreach ($groups as $group) {
// Check to see if we are negating the group, if so we switch the logic so that we deny access
if ($group = preg_replace('/^~/','',$group)) {
$access_group = false ;
} else {
$access_group = true ;
}
$feu_gid = $feu_module->GetGroupID($group);
// If they have access, then mark it and break out
if( $feu_module->MemberOfGroup($feu_uid, $feu_gid) && $access_group ) {
$access_allowed = true ;
}
}
// If access not allowed, we delete the node completed so it doesn't get passed into smarty at all
if (!$access_allowed) {
unset($nodelist[$nodeid]) ; // Remove this bad boy so it won't be seen
}
}
My next thought is that it may be easy to extend this a little further to also modify the content rendering logic to do a similar check so that if a link is given to someone to visit, they would not be allowed in either. Just a good place to consolidate all the logic with access controls by group instead of embedding on every page...
Re: Hack to MenuManager to easier Menu Navigation control based on FEU Groups
One last update after a lot more testing. The negating logic needed to be rethought. If you have 'access:~managers' or 'access:~managers,sponsors' - both of these now mean that the entire list of groups are negated, indicating that anyone who is a member of any listed groups after the ~ sign are NOT going to see the nav menu for the associated content page. This is primarily used by myself to remove nav elements after someone logs in to help reduce clutter and/or remove sub-nav elements they have yet to see.
New code below:
if (isset($rootnode) && $getchildren)
$this->GetChildNodes($rootnode, $nodelist, $gCms, $prevdepth, $count, $params, $origdepth, $showparents);
// Hack by DML - add access control - if the access: xxxx is on the titleattribute for the node, then restrict access
// First setup an ability to access the FEU module to look at groups
$feu_module =& $this->GetModuleInstance('FrontEndUsers');
$feu_uid = $feu_module->LoggedInId();
foreach ($nodelist as $nodeid => $node) {
// See if we have the special access:x,y,z tag in tite attribute, if so grab it, if not, skip
if (!preg_match('/access:\s*(.*)?\s*/i',$node->titleattribute, $matches)) {
// Nothing here to see ... keep moving along folks
continue ;
}
// We have a winner ...
// Before we forget, remove the nonstandard access: stuff from the title attribute field
$nodelist[$nodeid]->titleattribute = preg_replace('/access:.*?\s*/i','',$node->titleattribute) ;
// Check to see if this is a negated access list (everyone assumed access unless member of a listed group)
// Denoted by having a leading ~ e.g., access:~managers,sponsors means managers and sponsors are NOT allowed
// This is used primarily to remove nav elements after someone logs in who is a member of such a group
$groups_csv = preg_replace('/^~/','',trim($matches[1]),-1,$count) ;
if ($count > 0) {
$access_allowed = true ; // Since we are negated, assume the best
$access_negated = true ; // Let the logic below know that we are negating access rules
} else {
$access_allowed = false ; // Assume the worst if not negating access
$access_negated = false ; // Make it clear we are not negating access
}
// split out the access as csv and check each group against our access list
$groups = explode(',',$groups_csv) ;
// Logic is to loop until we find a match, once we do we set a good flag and break out
foreach ($groups as $group) {
// Get group id so we can check access
$feu_gid = $feu_module->GetGroupID($group);
// If are member of the group, then check to see if we have a negated access ...
if( $feu_module->MemberOfGroup($feu_uid, $feu_gid) ) {
// If we are negating access check, mark it false, otherwise, mark it as true
if ($access_negated) $access_allowed = false ;
else $access_allowed = true ;
}
}
// If access not allowed, we delete the node completely so it doesn't get passed into smarty at all
if (!$access_allowed) {
unset($nodelist[$nodeid]) ; // Remove this bad boy so it won't be seen
}
}
New code below:
if (isset($rootnode) && $getchildren)
$this->GetChildNodes($rootnode, $nodelist, $gCms, $prevdepth, $count, $params, $origdepth, $showparents);
// Hack by DML - add access control - if the access: xxxx is on the titleattribute for the node, then restrict access
// First setup an ability to access the FEU module to look at groups
$feu_module =& $this->GetModuleInstance('FrontEndUsers');
$feu_uid = $feu_module->LoggedInId();
foreach ($nodelist as $nodeid => $node) {
// See if we have the special access:x,y,z tag in tite attribute, if so grab it, if not, skip
if (!preg_match('/access:\s*(.*)?\s*/i',$node->titleattribute, $matches)) {
// Nothing here to see ... keep moving along folks
continue ;
}
// We have a winner ...
// Before we forget, remove the nonstandard access: stuff from the title attribute field
$nodelist[$nodeid]->titleattribute = preg_replace('/access:.*?\s*/i','',$node->titleattribute) ;
// Check to see if this is a negated access list (everyone assumed access unless member of a listed group)
// Denoted by having a leading ~ e.g., access:~managers,sponsors means managers and sponsors are NOT allowed
// This is used primarily to remove nav elements after someone logs in who is a member of such a group
$groups_csv = preg_replace('/^~/','',trim($matches[1]),-1,$count) ;
if ($count > 0) {
$access_allowed = true ; // Since we are negated, assume the best
$access_negated = true ; // Let the logic below know that we are negating access rules
} else {
$access_allowed = false ; // Assume the worst if not negating access
$access_negated = false ; // Make it clear we are not negating access
}
// split out the access as csv and check each group against our access list
$groups = explode(',',$groups_csv) ;
// Logic is to loop until we find a match, once we do we set a good flag and break out
foreach ($groups as $group) {
// Get group id so we can check access
$feu_gid = $feu_module->GetGroupID($group);
// If are member of the group, then check to see if we have a negated access ...
if( $feu_module->MemberOfGroup($feu_uid, $feu_gid) ) {
// If we are negating access check, mark it false, otherwise, mark it as true
if ($access_negated) $access_allowed = false ;
else $access_allowed = true ;
}
}
// If access not allowed, we delete the node completely so it doesn't get passed into smarty at all
if (!$access_allowed) {
unset($nodelist[$nodeid]) ; // Remove this bad boy so it won't be seen
}
}