2013-10-15 52 views
1

我忙於在我的應用程序內的Class + Field(classFieldAce)級別實現ACL。似乎一切正常,但我從ACL的isFieldGranted()方法獲得意外的行爲。這裏是我的代碼:Symfony 2 acl isFieldGranted拋出異常

// setup ACL 
$className  = 'Acme\Model\Junk'; 
$oid    = new ObjectIdentity('class', $className); 

try { 
    $acl = $aclProvider->findAcl($oid); 
} catch (Exception $e) { 
    $acl = $aclProvider->createAcl($oid); 

    $roleUser = new RoleSecurityIdentity('ROLE_USER'); 
    $mask  = new MaskBuilder(4); // 4 = EDIT 

    $acl->insertclassFieldAce('name', $roleUser, $mask->get()); 
} 

$aclProvider->updateAcl($acl); 

迄今爲止好。我將角色「ROLE_USER」分配給我的用戶。現在我想運行一些檢查(手動創建服務)。這裏是檢查代碼(內部控制器現在):

// check the ACL 
$className  = 'Acme\Model\Junk'; 
$oid    = new ObjectIdentity('class', $className); 
$aclProvider  = $this->get('security.acl.provider'); 

try { 
    $acl    = $aclProvider->findAcl($oid); 
} catch (...) 

都好。現在我想檢查的東西:

$sids = array(); 
foreach ($this->getUser()->getRoles() as $role) { 
    $sids[] = new RoleSecurityIdentity($role); 
} 
$masks = array(); 
$masks[] = MaskBuilder::MASK_EDIT; 

if ($acl->isFieldGranted('name', $masks, $sids)) { 
    echo "OK"; 
} else { 
    echo "NOT ALLOWED"; 
} 

在這一點上一切正常,我得到輸出「OK」。我唯一不確定的是將$ sids發送給支票的非常迂迴的方式 - 所以我的第一個問題是如果除了手動構建列表之外還有更快的方法。

事情剛開始走「錯」(如意外),當我嘗試檢查一個較高的面膜:

$sids = array(); 
foreach ($this->getUser()->getRoles() as $role) { 
    $sids[] = new RoleSecurityIdentity($role); 
} 
$masks = array(); 
$masks[] = MaskBuilder::MASK_OWNER; 

if ($acl->isFieldGranted('name', $masks, $sids)) { 
    echo "OK"; 
} else { 
    echo "NOT ALLOWED"; 
} 

,而不是返回false,$ ACL的> isFieldGranted拋出一個NoAceFoundException。

我是否正在進行野外檢查,或者我應該在這裏找出例外情況?

更新:加入日誌:

校驗碼更改爲:

$this->get('logger')->debug('XX: ACL retrieved, checking field grants'); 
    try { 
     if ($acl->isFieldGranted('name', $masks, $sids, true)) { 
      $this->get('logger')->debug('XX: ACL OK for field :name:'); 
     } 
    } catch (NoAceFoundException $e) { 
     $this->get('logger')->debug('XX: ACL NOT OK for field :name: NoAceFoundException thrown'); 
    } 

當檢查成功,日誌如下:

DEBUG - SELECT o.id as acl_id, o.object_identifier, o.parent_object_identity_id, 
o.entries_inheriting, c.class_type, e.id as ace_id, e.object_identity_id, e.field_name, 
e.ace_order, e.mask, e.granting, e.granting_strategy, e.audit_success, e.audit_failure, 
s.username, s.identifier as security_identifier FROM acl_object_identities o INNER JOIN 
acl_classes c ON c.id = o.class_id LEFT JOIN acl_entries e ON (e.class_id = o.class_id AND 
(e.object_identity_id = o.id OR e.object_identity_id IS NULL)) 
LEFT JOIN acl_security_identities s ON (s.id = e.security_identity_id) WHERE (o.id =16) 

DEBUG - SELECT t0.name AS name1, t0.roles AS roles2, t0.id AS id3 FROM staff_group t0 
INNER JOIN rel_staff_staff_group ON t0.id = rel_staff_staff_group.group_id 
WHERE rel_staff_staff_group.staff_id = ? Context: ["242"] 

DEBUG - XX: ACL retrieved, checking field grants 

DEBUG - XX: ACL OK for field :name: 

當檢查失敗,唯一的變化是這條線(我比較了兩個瀏覽器標籤中的日誌)

DEBUG - XX: ACL NOT OK for field :name: NoAceFoundException thrown 

$acl->isFieldGranted('name', $masks, $sids) 

$acl->isFieldGranted('name', $masks, $sids, true) 

更新2之間的日誌記錄沒有任何區別:

我的Symfony開了一個錯誤報告,它已經解決了https://github.com/symfony/symfony/issues/9433

+0

@freetrace感謝您的建議;更新的問題,但沒有得到太多的日誌 – mogoman

+0

好吧。嘗試在你的'$ acl-> isFieldGranted('name',$ masks,$ sids)''之前插入'var_dump($ acl-> getClassFieldAces('name'));''。 – sergekv

+0

這裏你去http://pastebin.com/RPddrX4P。 – mogoman

回答

0

看來你必須趕上NoAceFoundException在你的代碼,並拋出AccessDeniedException

try{ 
    if (!$acl->isFieldGranted('name', $masks, $sids)) { 
     throw new Symfony\Component\Security\Core\Exception\AccessDeniedException(); 
    } 
} catch (NoAceFoundException $e) { 
    throw new Symfony\Component\Security\Core\Exception\AccessDeniedException(); 
} 

因爲:

第一個適用的ACE將針對
權限/身份相結合的最終決定。如果它正在授予,該方法將 返回true,如果它拒絕,則該方法將繼續檢查下一個權限/身份組合。重複此過程 ,直到找到授予的ACE,或者沒有權限/身份 組合。最後,我們將拋出一個 NoAceFoundException或拒絕訪問。

因此,如果MaskBuilder::MASK_OWNER/RoleSecurityIdentity($role)組合未找到NoAceFoundException將被拋出。詳情請參閱this 137行。

+0

感謝您的研究。說實話,我發現它很奇怪,因爲布爾TRUE/FALSE比TRY/CATCH塊更快檢查。 – mogoman

+0

@mogoman我同意你的意見。這很奇怪,我不明白他們爲什麼拋出一個Exception,而不是簡單的FALSE。 – sergekv