Strange caching behaviour on setting group combination permissions prevents from creating new group combinations

Permalink Browser Info Environment
Steps to reproduce the problem:
1. advanced permissions have to be enabled
2. create a page
3. create groups A, B, C
4. open "set permissions" dialog on the created page and select any permission type (e.g. "View versions")
5. open "add" in "Included" section
6. select "Group combination"
7. add groups A, B, C and save permission
8. repeat steps 4 to 6 (on any other permission type)
9. add groups A and B and save permission

The application applies group combination "A + B + C"

The application should apply the new group combination "A + B"

This seems to happen anytime when choosing a group combination whose members have been used in a previous combination. It does not matter on which page the other combination is set nor whether the first combination is not set anywhere anymore. If an previously unused group (e.g. "D") is set in combination with a used one, the permissions are applied correctly.

Status: New
alexr replied on at Permalink Reply
Actually I chose the wrong version, sorry. It affects the current version
jthijs replied on at Permalink Reply
We spotted the exact same behavior on our system. After some digging in the source code we found that the getOrCreate function from Concrete5_Model_GroupCombinationPermissionAccessEntity creates a query which does not correctly filter. It only tries to find AccessEntities with all given groups in it, however it does not check if other groups might be assigned to the AccessEntity as well. Which results in the described behavior.

For now we updated the GroupCombinationPermissionAccessEntity class to overwrite the getOrCreate function as follows:
public static function getOrCreate($groups) {
      $db = Loader::db();
      $petID = $db->GetOne('select petID from PermissionAccessEntityTypes where petHandle = \'group_combination\'');
      $q = 'select pae.peID from PermissionAccessEntities pae where petID = ? ';
      foreach($groups as $g) {
         $q .= 'and pae.peID in (select peID from PermissionAccessEntityGroups where gID = '. $g->getGroupID() .' ) ';
      $q .= 'and pae.peID not in (select peID from PermissionAccessEntityGroups where 1=1 ';
      foreach($groups as $g) {
         $q .= 'and gID <> '. $g->getGroupID() .' ';
      $q .= ')';
      $peID = $db->GetOne($q, array($petID));
      if (!$peID) {
         $db->Execute("insert into PermissionAccessEntities (petID) values (?)", array($petID));

concrete5 Environment Information

Kubuntu 12.04
Apache 2.2.x
PHP 5.3.17

Browser User-Agent String

Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0