Skip to main content

The objectpolicy package makes it easy to override the default zope.securitypolicy.zopepolicy on an object by object basis.

The objectpolicy package makes it easy to override the default zope.securitypolicy.zopepolicy on an object by object basis.

By default all objects use the zopepolicy. Objects that want to have their own policy should have a marker interface IObjectPolicyMarker and have an adapter to IObjectPolicy.

Levels

There are two levels supported.

  • The low level is the SecurityMap.getCell level. Here are the permissions stored by principal or role. This works also with ZopePolicy as the security policy. Uses Allow, Deny, Unset values. Permissions descend (with ZopePolicy) to child objects or views. See:

    • IObjectPolicy.getPrincipalPermission

    • IObjectPolicy.getRolePermission

    • lowlevel.txt

    Installation: Drop the z3c.objectpolicy-configure.zcml in the instance/etc folder.

  • The high level is the ISecurityPolicy.checkPermission level. Here the permission is usually summarized for the principal by it’s roles, groups and object parent/child relations. ZopePolicy has to be overridden by the ObjectsPolicy security policy. Permissions do not decend to child objects or views. Uses True – access, False – no access values. See:

    • IObjectPolicy.checkPermission

    • highlevel.txt

    Installation: Override ZopePolicy in the instance/etc/securitypolicy.zcml

Basic Setup (for high level tests)

Good but not perfect example is the the user needs to be able to modify it’s own properties problem.

>>> from zope import interface, component
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> from zope.container.interfaces import IContained
>>> from zope.container.contained import Contained
>>> from z3c.objectpolicy.interfaces import IObjectPolicy
>>> from z3c.objectpolicy.interfaces import IObjectPolicyMarker
>>> class IPerson(interface.Interface):
...     """a person interface for a person class"""
...
>>> class Person(Contained):
...     interface.implements(
...         IObjectPolicyMarker,
...         IAttributeAnnotatable,
...         IPerson)
...     def __init__(self, id, name):
...         self.id = id
...         self.name = name
...         self.groups = []
...
>>> class otherKlass(object):
...     #This class does NOT implement IObjectPolicyMarker
...     interface.implements(
...         IAttributeAnnotatable)
...     def __init__(self, id):
...         self.id = id

These permissions will be allowed for the principal on the Person object if the current principal == Person

>>> ALLOW_FOR_SELF = ["zope.View",
...                   "zope.app.dublincore.view",
...                   "zope.ManageContent"]

Counter to see how many times the adapter fires

>>> TRIP_WIRE = 0

This is the custom policy adapter which determines the permission. Watch out, this is just a little bit different from the lowlevel example!

>>> from z3c.objectpolicy.objectpolicy import DefaultObjectPolicyAdapter
>>> class PersonPolicy(DefaultObjectPolicyAdapter):
...     component.adapts(IPerson)
...     interface.implements(IObjectPolicy)
...
...     def __init__(self, context):
...         #context is a Person
...         self.context = context
...
...     def checkPermission(self, manager, permissionid):
...         #print permissionid, str(self.context)
...         return self.checkPermissionForParticipation(manager, permissionid)
...
...     def checkPermissionForParticipant(self, manager, principal, permissionid):
...         global TRIP_WIRE
...         TRIP_WIRE += 1
...         if principal.id == self.context.id:
...             #we have the same Person in the participation
...             if permissionid in ALLOW_FOR_SELF:
...                 #we have the Person and the Permission
...                 return True
...
...         #no Person or Permission found
...         #return the Z3 default permissions
...         return super(PersonPolicy, self).checkPermissionForParticipant(
...             manager, principal, permissionid)
...
>>> component.provideAdapter(PersonPolicy)

Install the ObjectPolicy, setup for testing.

>>> from z3c.objectpolicy.objectpolicy import ObjectPrincipalPermissionManager
>>> from z3c.objectpolicy.objectpolicy import ObjectRolePermissionManager
>>> from z3c.objectpolicy.objectpolicy import ObjectPolicy
>>> component.provideAdapter(ObjectPrincipalPermissionManager)
>>> component.provideAdapter(ObjectRolePermissionManager)
>>> bela = Person('b-id', 'bela')
>>> joe = Person('j-id', 'joe')
>>> class Participation:
...     interaction = None
>>> participation = Participation()
>>> participation.principal = joe
>>> import zope.security.management
>>> oldPolicy = zope.security.management.setSecurityPolicy(ObjectPolicy)
>>> zope.security.management.endInteraction()
>>> zope.security.management.newInteraction(participation)
>>> interaction = zope.security.management.getInteraction()

Let’s see a simple permission check

joe has ManageContent access to joe without granting any permission

>>> interaction.checkPermission('zope.ManageContent', joe)
True
>>> TRIP_WIRE
1

joe has no SomePermission access to joe because that’s not listed in ALLOW_FOR_SELF

>>> interaction.checkPermission('myapp.SomePermission', joe)
False
>>> TRIP_WIRE
2

joe has NO ManageContent access to bela

>>> interaction.checkPermission('zope.ManageContent', bela)
False
>>> TRIP_WIRE
3
>>> from zope.securitypolicy.interfaces import IPrincipalPermissionManager
>>> prinperBela = IPrincipalPermissionManager(bela)
>>> prinperJoe = IPrincipalPermissionManager(joe)
>>> prinperBela.grantPermissionToPrincipal('zope.ManageContent', 'j-id')

When we grant permission joe to bela, joe has ManageContent access to bela

>>> interaction.checkPermission('zope.ManageContent', bela)
True
>>> TRIP_WIRE
4

Granting permission works for any arbitrary permission also

>>> prinperJoe.grantPermissionToPrincipal('myapp.SomePermission', 'j-id')
>>> interaction.checkPermission('myapp.SomePermission', joe)
True
>>> TRIP_WIRE
5

Objects without IObjectPolicyMarker behave as before. Without granting – no permission

>>> otherObject = otherKlass('o-id')
>>> prinperOther = IPrincipalPermissionManager(otherObject)
>>> interaction.checkPermission('zope.ManageContent', otherObject)
False
>>> TRIP_WIRE
5
>>> prinperOther.grantPermissionToPrincipal('zope.ManageContent', 'j-id')
>>> interaction.checkPermission('zope.ManageContent', otherObject)
True
>>> TRIP_WIRE
5

Check what’s up when the marker is there, but no adapter

>>> class otherKlassWOadapter(object):
...     #This class does NOT implement IObjectPolicyMarker
...     interface.implements(
...         IAttributeAnnotatable,
...         IObjectPolicyMarker)
...     def __init__(self, id):
...         self.id = id
>>> otherObjectWO = otherKlassWOadapter('oa-id')
>>> interaction.checkPermission('zope.ManageContent', otherObjectWO)
False

No permission, maybe something should be written to the log?

Now a more complicated, parent-child setup

>>> from zope.container.sample import SampleContainer
>>> from zope.location.location import locate
>>> class IPersonContainer(interface.Interface):
...     """a person container interface"""
...
>>> class PersonContainer(SampleContainer):
...     interface.implements(
...         IAttributeAnnotatable,
...         IPersonContainer)
...     def __init__(self, id):
...         self.id = id
...         super(PersonContainer, self).__init__()
...
>>> class BrowserView(object):
...     interface.implements(
...         IContained)
...
The layout is:
users(PersonContainer)
jack(Person)

editJack(BrowserView)

jane(Person)

editJane(BrowserView)

>>> users = PersonContainer('users')
>>> jack = Person('jack-id','jack')
>>> users['jack'] = jack
>>> locate(jack, users, 'jack')
>>> jane = Person('jane-id','jane')
>>> users['jane'] = jane
>>> locate(jane, users, 'jane')
>>> editJack = BrowserView()
>>> locate(editJack, jack, None)
>>> editJane = BrowserView()
>>> locate(editJane, jane, None)
>>> prinperUsers = IPrincipalPermissionManager(users)
>>> prinperJack = IPrincipalPermissionManager(jack)
>>> prinperJane = IPrincipalPermissionManager(jane)
>>> participation = Participation()

The principal acting is jack

>>> participation.principal = jack
>>> zope.security.management.endInteraction()
>>> zope.security.management.newInteraction(participation)
>>> interaction = zope.security.management.getInteraction()

When we don’t grant permission, only jack has permission to itself and to it’s editView.

>>> interaction.checkPermission('zope.ManageContent', users)
False
>>> interaction.checkPermission('zope.ManageContent', jack)
True
>>> interaction.checkPermission('zope.ManageContent', editJack)
False
>>> interaction.checkPermission('zope.ManageContent', jane)
False
>>> interaction.checkPermission('zope.ManageContent', editJane)
False

When we grant jane permission, jack still has the same.

>>> prinperUsers.grantPermissionToPrincipal('zope.ManageContent', 'jane-id')
>>> interaction.checkPermission('zope.ManageContent', users)
False
>>> interaction.checkPermission('zope.ManageContent', jack)
True
>>> interaction.checkPermission('zope.ManageContent', editJack)
False
>>> interaction.checkPermission('zope.ManageContent', jane)
False
>>> interaction.checkPermission('zope.ManageContent', editJane)
False

When we grant jack permission, he will have permission for the whole pack.

>>> prinperUsers.grantPermissionToPrincipal('zope.ManageContent', 'jack-id')
>>> interaction.checkPermission('zope.ManageContent', users)
True
>>> interaction.checkPermission('zope.ManageContent', jack)
True
>>> interaction.checkPermission('zope.ManageContent', editJack)
True
>>> interaction.checkPermission('zope.ManageContent', jane)
True
>>> interaction.checkPermission('zope.ManageContent', editJane)
True

Cleanup

We clean up the changes we made in these examples:

>>> zope.security.management.endInteraction()
>>> ignore = zope.security.management.setSecurityPolicy(oldPolicy)

Basic Setup (for low level tests)

Good but not perfect example is the the user needs to be able to modify it’s own properties problem.

>>> from zope import interface, component
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> from zope.container.interfaces import IContained
>>> from zope.container.contained import Contained
>>> from z3c.objectpolicy.interfaces import IObjectPolicy
>>> from z3c.objectpolicy.interfaces import IObjectPolicyMarker
>>> class IPerson(interface.Interface):
...     """a person interface for a person class"""
...
>>> class Person(Contained):
...     interface.implements(
...         IObjectPolicyMarker,
...         IAttributeAnnotatable,
...         IPerson)
...     def __init__(self, id, name):
...         self.id = id
...         self.name = name
...         self.groups = []
...
>>> class otherKlass(object):
...     #This class does NOT implement IObjectPolicyMarker
...     interface.implements(
...         IAttributeAnnotatable)
...     def __init__(self, id):
...         self.id = id

These permissions will be allowed for the principal on the Person object if the current principal == Person

>>> ALLOW_FOR_SELF = ["zope.View",
...                   "zope.app.dublincore.view",
...                   "zope.ManageContent"]

Counter to see how many times the adapter fires

>>> TRIP_WIRE = 0

This is the custom policy adapter which determines the permission.

>>> from zope.securitypolicy.interfaces import Allow, Deny, Unset
>>> from z3c.objectpolicy.objectpolicy import DefaultObjectPolicyAdapter
>>> class PersonPolicy(DefaultObjectPolicyAdapter):
...     component.adapts(IPerson)
...     interface.implements(IObjectPolicy)
...
...     def __init__(self, context):
...         #context is a Person
...         self.context = context
...
...     def getPrincipalPermission(self, manager, permissionid, principalid, default):
...         global TRIP_WIRE
...         TRIP_WIRE += 1
...         if principalid == self.context.id:
...             #we have the same Person in the participation
...             if permissionid in ALLOW_FOR_SELF:
...                 #we have the Person and the Permission
...                 return Allow
...
...         #no Person or Permission found
...         #return the Z3 default permissions
...         return super(PersonPolicy, self).getPrincipalPermission(
...             manager, permissionid, principalid, default)
...
>>> component.provideAdapter(PersonPolicy)

Install the ObjectPolicy, setup for testing.

>>> from z3c.objectpolicy.objectpolicy import ObjectPrincipalPermissionManager
>>> from z3c.objectpolicy.objectpolicy import ObjectRolePermissionManager
>>> component.provideAdapter(ObjectPrincipalPermissionManager)
>>> component.provideAdapter(ObjectRolePermissionManager)
>>> bela = Person('b-id', 'bela')
>>> joe = Person('j-id', 'joe')
>>> class Participation:
...     interaction = None
>>> participation = Participation()
>>> participation.principal = joe
>>> import zope.security.management
>>> from zope.securitypolicy.zopepolicy import ZopeSecurityPolicy
>>> oldPolicy = zope.security.management.setSecurityPolicy(ZopeSecurityPolicy)
>>> zope.security.management.endInteraction()
>>> zope.security.management.newInteraction(participation)
>>> interaction = zope.security.management.getInteraction()

Let’s see a simple permission check

joe has ManageContent access to joe without granting any permission

>>> interaction.checkPermission('zope.ManageContent', joe)
True
>>> TRIP_WIRE
1

joe has no SomePermission access to joe because that’s not listed in ALLOW_FOR_SELF

>>> interaction.checkPermission('myapp.SomePermission', joe)
False
>>> TRIP_WIRE
2

joe has NO ManageContent access to bela

>>> interaction.checkPermission('zope.ManageContent', bela)
False
>>> TRIP_WIRE
3
>>> from zope.securitypolicy.interfaces import IPrincipalPermissionManager
>>> prinperBela = IPrincipalPermissionManager(bela)
>>> prinperJoe = IPrincipalPermissionManager(joe)
>>> prinperBela.grantPermissionToPrincipal('zope.ManageContent', 'j-id')

When we grant permission joe to bela, joe has ManageContent access to bela

>>> interaction.checkPermission('zope.ManageContent', bela)
True
>>> TRIP_WIRE
4

Granting permission works for any arbitrary permission also

>>> prinperJoe.grantPermissionToPrincipal('myapp.SomePermission', 'j-id')
>>> interaction.checkPermission('myapp.SomePermission', joe)
True
>>> TRIP_WIRE
5

Objects without IObjectPolicyMarker behave as before. Without granting – no permission

>>> otherObject = otherKlass('o-id')
>>> prinperOther = IPrincipalPermissionManager(otherObject)
>>> interaction.checkPermission('zope.ManageContent', otherObject)
False
>>> TRIP_WIRE
5
>>> prinperOther.grantPermissionToPrincipal('zope.ManageContent', 'j-id')
>>> interaction.checkPermission('zope.ManageContent', otherObject)
True
>>> TRIP_WIRE
5

Check what’s up when the marker is there, but no adapter

>>> class otherKlassWOadapter(object):
...     #This class does NOT implement IObjectPolicyMarker
...     interface.implements(
...         IAttributeAnnotatable,
...         IObjectPolicyMarker)
...     def __init__(self, id):
...         self.id = id
>>> otherObjectWO = otherKlassWOadapter('oa-id')
>>> interaction.checkPermission('zope.ManageContent', otherObjectWO)
False

No permission, maybe something should be written to the log?

Now a more complicated, parent-child setup

>>> from zope.container.sample import SampleContainer
>>> from zope.location.location import locate
>>> class IPersonContainer(interface.Interface):
...     """a person container interface"""
...
>>> class PersonContainer(SampleContainer):
...     interface.implements(
...         IAttributeAnnotatable,
...         IPersonContainer)
...     def __init__(self, id):
...         self.id = id
...         super(PersonContainer, self).__init__()
...
>>> class BrowserView(object):
...     interface.implements(
...         IContained)
...
The layout is:
users(PersonContainer)
jack(Person)

editJack(BrowserView)

jane(Person)

editJane(BrowserView)

>>> users = PersonContainer('users')
>>> jack = Person('jack-id','jack')
>>> users['jack'] = jack
>>> locate(jack, users, 'jack')
>>> jane = Person('jane-id','jane')
>>> users['jane'] = jane
>>> locate(jane, users, 'jane')
>>> editJack = BrowserView()
>>> locate(editJack, jack, None)
>>> editJane = BrowserView()
>>> locate(editJane, jane, None)
>>> prinperUsers = IPrincipalPermissionManager(users)
>>> prinperJack = IPrincipalPermissionManager(jack)
>>> prinperJane = IPrincipalPermissionManager(jane)
>>> participation = Participation()

The principal acting is jack

>>> participation.principal = jack
>>> zope.security.management.endInteraction()
>>> zope.security.management.newInteraction(participation)
>>> interaction = zope.security.management.getInteraction()

When we don’t grant permission, only jack has permission to itself and to it’s editView.

>>> interaction.checkPermission('zope.ManageContent', users)
False
>>> interaction.checkPermission('zope.ManageContent', jack)
True
>>> interaction.checkPermission('zope.ManageContent', editJack)
True
>>> interaction.checkPermission('zope.ManageContent', jane)
False
>>> interaction.checkPermission('zope.ManageContent', editJane)
False

When we grant jane permission, jack still has the same.

>>> prinperUsers.grantPermissionToPrincipal('zope.ManageContent', 'jane-id')
>>> interaction.checkPermission('zope.ManageContent', users)
False
>>> interaction.checkPermission('zope.ManageContent', jack)
True
>>> interaction.checkPermission('zope.ManageContent', editJack)
True
>>> interaction.checkPermission('zope.ManageContent', jane)
False
>>> interaction.checkPermission('zope.ManageContent', editJane)
False

When we grant jack permission, he will have permission for the whole pack.

>>> prinperUsers.grantPermissionToPrincipal('zope.ManageContent', 'jack-id')
>>> interaction.checkPermission('zope.ManageContent', users)
True
>>> interaction.checkPermission('zope.ManageContent', jack)
True
>>> interaction.checkPermission('zope.ManageContent', editJack)
True
>>> interaction.checkPermission('zope.ManageContent', jane)
True
>>> interaction.checkPermission('zope.ManageContent', editJane)
True

Cleanup

We clean up the changes we made in these examples:

>>> zope.security.management.endInteraction()
>>> ignore = zope.security.management.setSecurityPolicy(oldPolicy)

CHANGES

0.1 (2010-08-10)

  • Initial release.

Metadata

Release files for z3c.objectpolicy 0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for z3c.objectpolicy 0.1
File Size Uploaded Provenance
z3c.objectpolicy-0.1.tar.gz 16.2 kB Without provenance Details

Release files / z3c.objectpolicy-0.1.tar.gz

Download URL z3c.objectpolicy-0.1.tar.gz
Size 16.2 kB
Tags Source
SHA-256 checksum
How to use checksums
be202c5b8e1798d3981b3108f8f35ae4d6cce10b8dee30c5f902a88ce7a7abc7
BLAKE2b-256 checksum
How to use checksums
e89926e87f3ec2c63ea86f9db6078fda12ac3497062af17494dd1c7f4bcc3ebb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Security for z3c.objectpolicy 0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page