Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Acl Sonata Admin Extension Bundle Laravel Package

tilleuls/acl-sonata-admin-extension-bundle

A Symfony bundle that extends Sonata Admin with ACL support, letting you control access to admin sections, actions, and objects through Symfony's ACL system for fine-grained, per-object permissions.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small, single-purpose bundle: it registers a global Sonata Admin extension that rewrites each admin's list query (configureQuery()) so the datagrid only shows objects on which the current user has a given ACL permission (typically VIEW). If an object has no ACE for the user, it does not appear in the list. That is the whole feature — everything else is Symfony ACL setup.

Minimal steps:

  1. composer require tilleuls/acl-sonata-admin-extension-bundle (last release 2017 — expect to stay on Symfony 2.8/3.x + Sonata Admin 3.x; on Symfony 3+ also require symfony/security-acl explicitly).
  2. Register CoopTilleuls\Bundle\AclSonataAdminExtensionBundle\CoopTilleulsAclSonataAdminExtensionBundle in AppKernel after SonataAdminBundle and SecurityBundle.
  3. Configure the ACL provider — the bundle depends on security.acl.provider:
    security:
        acl:
            connection: default
    
  4. Confirm Sonata's own security works first: $admin->isGranted('VIEW', $object) must return the expected result for a test object. The bundle filters the list; it does not replace object-level voters.
  5. First use case: pick one admin (e.g. ArticleAdmin), create one Article, grant a non-admin user MASK_VIEW on it, log in as that user, and check that the list contains exactly that row. If it is empty, the ACL was never created — see the gotcha below.

Where to look first: Admin/ (the extension class and its configureQuery implementation), DependencyInjection/ + Resources/config/services.xml (the sonata.admin.extension tag, global flag and target), then the README for the permission/config knob. The code is small enough to read end-to-end before trusting it.

Implementation Patterns

Create ACEs at write time, not read time. The bundle only reads ACLs; you must populate them. A Doctrine postPersist listener is the canonical place:

$oid = ObjectIdentity::fromDomainObject($entity);
$acl = $aclProvider->createAcl($oid);

// owner gets full control
$acl->insertObjectAce($entity->getOwner(), MaskBuilder::MASK_OWNER);

// a role gets read access
$acl->insertObjectAce(new RoleSecurityIdentity('ROLE_EDITOR'), MaskBuilder::MASK_VIEW);

$aclProvider->updateAcl($acl);

Wrap this in a transaction with the entity flush, and guard against re-creating the ACL (findAcl in a try/catch on AclNotFoundException).

Use the owner pattern for user-generated content. Store an owner on the entity, insert a MASK_OWNER ACE for that user, and insert MASK_VIEW/MASK_EDIT for roles. This keeps ACL rows small and makes "my articles" lists work without per-user grants.

Keep class-level ACLs for staff. Grant VIEW on the class object identity (new ObjectIdentity('class', Article::class)) to ROLE_ADMIN. Admins then see everything without creating an ACE per row; per-object ACLs remain for non-admin users. Check whether the bundle short-circuits on a class-level grant before you rely on this — verify with a small dataset.

Disable per admin when needed. The extension is registered globally. For admins that must never be filtered (audit logs, reference data, dashboards), either override the service definition with a guard in a subclass, or register your own sonata.admin.extension with a narrower target. Prefer the guard: it is one if in configureQuery() and survives bundle updates.

Respect extension ordering. If another extension joins the root alias or replaces it, ACL filtering (which typically adds id IN (SELECT object_identifier …)) must run against the same root alias. Control this with the priority attribute on sonata.admin.extension.

Treat it as list filtering only. Show/edit/delete still go through Sonata's isGranted() checks and the ACL voter. Do not assume a filtered list means the actions are protected; test direct URLs.

Gotchas and Tips

  • Empty lists are almost always missing ACLs, not a bundle bug. Default-deny is the semantics. Check first: SELECT * FROM acl_object_identities WHERE object_identifier = '<id>' and SELECT * FROM acl_entries WHERE object_identity_id = <oid>.
  • Super admins. Sonata bypasses checks for ROLE_SUPER_ADMIN; make sure your ACL filtering does the same or your super admin sees an empty list. Test with the real production role hierarchy.
  • Performance. The filter becomes a large IN (...) or subquery. On tables with tens of thousands of rows, keep the subquery scoped by class_id and index acl_entries(object_identity_id, security_identity_id) and acl_object_identities(class_id, object_identifier). Watch for implicit string→int casts: object_identifier is a string, so comparing to an integer column can kill the index in MySQL.
  • ACL cache. In production enable and warm the ACL cache; otherwise every list request hits acl_entries. Invalidate after changing ACEs.
  • Caching the list query yourself (HTTP cache, Sonata's own cache) will serve stale, over-permissive pages. Never cache a filtered admin list per-URL without varying on user/roles.
  • Count/pagination. Sonata's pager derives getCount() from the same query, so counts should match the filter. If an admin overrides getCount() or uses a custom data source, filtering silently breaks — check those admins.
  • Nested admins are not filtered. Child admins embedded in a parent show page, and relation widgets (ModelType, sonata_type_model_list), go through different queries.
  • Export and batch actions may use separate query paths. Verify that CSV/XLSX export and batchAction operate on the filtered set before shipping.
  • Anonymous tokens. ACL security identities require a user; requests without a token or with an anonymous token break resolution. Ensure the firewall always authenticates before the admin.
  • Legacy ceiling. The bundle is unmaintained (last release March 2017) and is tied to Sonata Admin 3 / the deprecated Symfony ACL component. On Sonata Admin 4/5 there is no compatible path; plan a replacement: a custom AbstractAdminExtension::configureQuery() backed by your own "viewable IDs" service (voter + repository query), or Symfony voters with a repository-level filter. The extension point itself is one method, so the migration is mechanical once you have an ACL source of truth.
  • Treat it as UX, not the security boundary. Keep the object-level voter checks as the authoritative gate; use this bundle to avoid leaking rows into lists and to keep pagination honest.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums