EntityPrivilege persistence_object_identifier and in operator

Hi,

we already have a couple of entity privilege constraints that work just fine, e.g.

privilegeTargets:
  'Neos\Flow\Security\Authorization\Privilege\Entity\Doctrine\EntityPrivilege':
    'Passcreator.Passcreator.Template':
      matcher: 'isType("Passcreator\Passcreator\Domain\Model\Template") && property("customer").equals("context.customerContext.customer")'

We now want to extend this in a way that a user has only access to certain objects of that type by checking the persistence_object_identifier against an array of identifiers (that will be dynamic later but not important for that part).

So what we did is this:

privilegeTargets:
  'Neos\Flow\Security\Authorization\Privilege\Entity\Doctrine\EntityPrivilege':
    'Passcreator.Passcreator.Template':
      matcher: 'isType("Passcreator\Passcreator\Domain\Model\Template") && property("customer").equals("context.customerContext.customer") && property("Persistence_Object_Identifier").in("context.customerContext.assignedTemplateIds")'

The context we have configured also implements the CacheAwareInterface and has a method called getAssignedTemplateIds which returns an array.
However that doesn’t seem to have any effect.
I also tried to leave out the second condition where we check the customer but without any effect. Also cleared caches.
Does anyone see what I’m doing wrong or did I miss something fundamental regarding the concept?

IIRC property only works for actual properties, i.e. fields with corresponding getters.
If you really want to refer to the technical identifier you should probably make that an explicit concept (i.e. add a getId() getter to your entity)

Ok, thanks. I think that part should work since the fieldMapping of the model is used here Packages/Libraries/doctrine/orm/lib/Doctrine/ORM/Mapping/DefaultQuoteStrategy.php to get the column and that includes “Persistence_Object_Identifier” (also with the uppercase letters).
I’ll dig deeper :wink:

1 Like

The strange thing is that this part doesn’t seem to have any effect at all. I found out that the SQL filters are generated as expected so there really seems to be a “where persistence_object_identifier in(‘abc’, ‘def’)” part in the query…

Need to find out why it still returns an object that is not in that array.

Mh, I would need to debug it myself… But what I can say is, that the following works for me:

'Neos\Flow\Security\Authorization\Privilege\Entity\Doctrine\EntityPrivilege':

  'Some.Package:Entities.Product.Foreign':
    matcher: 'isType("Some\Package\Some\Product") && !property("id").in("context.myContext.assignedProductIds")'

  'Some.Package:Entities.Product.Assigned':
    matcher: 'isType("Some\Package\Some\Product") && property("id").in("context.myContext.assignedProductIds")'

maybe that helps!?

…and then something like:

roles:
  'Some.Package:User':
    privileges:
      -
        privilegeTarget: 'Some.Package:Entities.Product.Assigned'
        permission: GRANT

  'Yeebase.Package:Administrator':
    parentRoles: ['Some.Package:User']
    privileges:
      -
        privilegeTarget: 'Some.Package:Entities.Product.Foreign'
        permission: GRANT

of course.

This should, however, work without the whole “Foreign” part

Technically you don’t even need the negated property in if you only want to grant the other privilege. So one privilege preventing general access and one that applies to the defined IDs.

yes, that’s what I wanted to say with the last phrase :slight_smile:

1 Like

Hmm that’s basically what I did but maybe the problem is that I have one more condition in my matcher (don’t think so but who know).

Quick update - I’ve enabled the query log and it seems that the query filter isn’t applied at all which is strange…
The SQL Filter class is called, however and also generates the correct constraint.
Don’t know why, yet.

Forget all I said - it works somehow :wink:
It works with either the customer condition or the in-operator but not both at the same time.
This means that I can’t do what is in my initial post but this works:

matcher: ‘isType(“Passcreator\Passcreator\Domain\Model\Pass”) && property(“Persistence_Object_Identifier”).in(“context.customerContext.assignedTemplateIds”)’

And this works:

matcher: 'isType(“Passcreator\Passcreator\Domain\Model\Pass”) && property(“customer”).equals(“context.customerContext.customer”)

But not this:

matcher: ‘isType(“Passcreator\Passcreator\Domain\Model\Pass”) && property(“customer”).equals(“context.customerContext.customer”) && property(“Persistence_Object_Identifier”).in(“context.customerContext.assignedTemplateIds”)’

I assumed the latter should work and will investigate more.

We ended up using EntityPrivileges like this one:

matcher: ‘isType(“Passcreator\Passcreator\Domain\Model\Pass”) && !property(“Persistence_Object_Identifier”).in(“context.customerContext.assignedTemplateIds”)’

This basically excludes all entities that are not part of the assignedTemplateIds array which is what we want (that privilege isn’t assigned to any role).
In addition to that we wanted to have roles that consist of MethodPrivileges which is why we created such thing on a database level. Currently we use an Aspect to GRANT access to a privilege that is assigned to a database-role and use lots of Caching.
We might change that to use something like this here later: https://github.com/sandstorm/NeosAcl