| name | oro-security |
| description | Use when configuring OroCommerce v6.1 ACL, permissions, and access control — setting up entity permissions (acls.yml), ownership types, Acl/AclAncestor PHP attributes on controllers, custom permissions, field-level ACL, access rules for query filtering, or debugging permission issues. Relevant when the user mentions 'ACL', 'permissions', 'access control', 'ownership', 'security', 'acls.yml', 'field ACL', 'access rules', or any OroCommerce authorization task. |
OroCommerce v6.1 Security & ACL Configuration
Entity ACL Configuration
Place in Resources/config/oro/acls.yml:
acls:
acme_demo_document_view:
type: entity
class: Acme\Bundle\DemoBundle\Entity\Document
permission: VIEW
description: View documents
acme_demo_document_edit:
type: entity
class: Acme\Bundle\DemoBundle\Entity\Document
permission: EDIT
Key structure: type: entity, class (FQCN), permission (VIEW, CREATE, EDIT, DELETE, ASSIGN, EXECUTE).
PHP 8 Acl Attribute
Declare ACL requirements directly on controller methods:
use Oro\Bundle\SecurityBundle\Attribute\Acl;
class DocumentController
{
#[Acl(
id: 'acme_demo_document_view',
type: 'entity',
class: 'Acme\Bundle\DemoBundle\Entity\Document',
permission: 'VIEW'
)]
public function viewAction(Document $document)
{
}
}
Attributes are preferred over YAML bindings — they're colocated with the code they protect and type-safe.
Ownership and Organization
Ownership determines who can access an entity. Four scopes: USER, BUSINESS_UNIT, ORGANIZATION, GLOBAL.
CRITICAL: If ownership is USER or BUSINESS_UNIT, the entity MUST have an organization field. Missing it causes permission checks to fail silently.
Define in Resources/config/oro/entity.yml:
entities:
Acme\Bundle\DemoBundle\Entity\Document:
ownership:
owner_type: USER
owner_field_name: owner
organization_field_name: organization
AclHelper: Query Filtering
ACL checks do NOT happen automatically on queries. You must explicitly apply filtering:
class DocumentRepository
{
public function findApprovedDocuments(User $user)
{
$qb = $this->createQueryBuilder('d')
->where('d.status = :status')
->setParameter('status', 'approved');
$this->aclHelper->apply($qb);
return $qb->getQuery()->getResult();
}
}
Without $aclHelper->apply($qb), the query returns all entities regardless of permissions.
For custom access rules (AccessRuleInterface), see security-patterns.md.
Key Pitfalls
-
Query filtering is not automatic: Must call $aclHelper->apply($qb) explicitly. Common mistake: fetching all entities and filtering in PHP rather than at DB level.
-
AclAncestor skips object-level checks: Use AclAncestor only for class-level permission verification (list pages). For specific objects, use full Acl attributes or isGranted().
-
Organization field is mandatory for USER/BUSINESS_UNIT ownership: Omitting it causes permission checks to return false unexpectedly.
For AclAncestor details, custom permissions, field-level ACL, common patterns, debugging, and additional pitfalls, see security-patterns.md.
Version Notes
See permission-matrix.md for the full permission/ownership matrix and v6.1 notes.