Security in Plone Sites

Download code from here

More about securityFor a closer look at a variety of Plone-related security information, visit Erik Rose and Steve McMahon's excellent Plone Conference 2008 talk, visit

Restricting TCP/IP access to localhost or LAN host

One of the simplest things we can do to secure our system is to operate our Zope 2 instances only on the IP addresses that they are required to listen on.

In most cases, it is (or localhost, as it is commonly referred to) but it can also be a LAN host that is a private, non-routable IP address used only on your local area network (LAN).

In this article, we will not cover LAN hosts. However, we suggest you consider using them when you need to access instances from another host on the LAN; otherwise, just use localhost.

In the case of LAN hosts, once confgured, they will protect ports from being accessed by the outside world (that is Internet). However, it will allow them to be accessible from the LAN where you may want to confgure monitoring, for example via Munin , Zenoss (, and so on.

What we will cover is how to use the localhost IP address.

In 07-security-localhost.cfg, we have:

extends = 06-deployment-optimization-munin.cfg

http-address =

http-address =

You will notice we have re-configured the http-address parameter to include the entire HTTP address and not just the port number.

You will also notice we have used the private, non-routable localhost address

Now run Buildout:

$ bin/buildout -c 07-security-localhost.cfg

Afterward, in parts/instance1/etc/zope.conf, you should see:

# valid keys are "address" and "force-connection-close"
# force-connection-close on
# You can also use the WSGI interface between ZServer and
# use-wsgi on


This means that our instances will listen for connections only on; any attempt to connect from another host will fail.

More about localhostFor more information about how the localhost really works, visit For our purpose though, we can think of running the Plone site on localhost as "having a party that only your laptop or development workstation can join".

Managing IP addresses and ports effectively

As your production configuration grows, it may become more diffcult to manage a large number of IP addresses and ports.

As such, it is often helpful to have them defned in their own part.

In 07-security-ports.cfg, we have:

extends = 07-security-localhost.cfg

localhost =

instance1 = 8081
instance2 = 8082

Notice that we are not using these definitions for anything yet. But we can use them like this:


Effectively from now on, we have to change IP addresses and port numbers only in one place (assuming we change all static references such as to the new syntax).

Configuring the Zope 2 effective user dynamically

Another simple thing we can do to secure our system is to operate our Zope 2 instances with only those operating system users who have enough permission to execute the instances. In fact, Zope 2 will not run as root on UNIX-like systems.

However, we frequently forget to do this. More importantly, sometimes we want to be more explicit with our configuration. This is where the effective-user parameter comes in handy. If no effective user is set, then Zope 2 will run as whoever executes the process.

You could set the effective-user manually or you could use the gocept.recipe.env recipe ( to set it. In the case of manual configuration, you may find it tedious to test your production configuration on systems that do not have the desired effective user (or you may not; this is mostly subjective). In the case of no configuration, you may find it annoying to be reminded that you cannot run Zope 2 as root when you get to production (or you may not; this is also subjective).

In any event, we can formalize the configuration and automate the username selection process as follows.

In 07-security-effective-user.cfg, we have:

extends = 07-security-ports.cfg
parts += env

recipe = gocept.recipe.env

effective-user = ${env:USER}
effective-user = ${env:USER}

Now run Buildout.

$ bin/buildout -c 07-security-effective-user.cfg

Afterward, in parts/instance1/etc/zope.conf you should see:

effective-user aclark


This technique has several subtle, but important advantages over manual, or no configuration:

  • The effective user is always set, so even if you try to start Zope 2 as root, it will run as the effective user
  • The effective user is set to the user that runs the buildout, which means you can change the effective user easily
  • The ${env:USER} variable can be used to configure user settings for additional services such as Pound, Varnish, and so on.

Installing Cassandra to audit through the web (TTW) security

If you ask anyone familiar with Plone about the permissions settings in the Security part of the Zope Management Interface, you are likely to get the following response:


That is because with so many possible permutations of settings, it is almost impossible to manage them all effectively by pointing and clicking.

The next thing out of their mouth is likely to be:


That is because Plone's workfow feature provides a much better way to effectively manage large amounts of permission changes.

However, people do not always use workfow. They point and click away anyway, despite the warnings. You, however, have been warned. It is much better to manage permissions with workfow as compared to pointing and clicking on Permissions in the ZMI.

Permissions and roles in the ZMI

If you do not believe me, consider this.

If you browse to http://localhost:8080/Plone and click on Site Setup | Zope Management Interface | Security, you will see almost two hundred permissions that look like the following (first ten):

Security in Plone Sites

Next to each group of 10 permissions are checkboxes that correspond to the possiblerole assignments:

Security in Plone Sites

Hopefully, enough has been said. The point again is two-fold:

  • The ZMI opens the gateway to enormous complexity (categorically, not just with roles and permissions)
  • In the case of roles and permissions, managing this complexity is best left to workfow (in which case, role-to-permission mappings are configured by the state)

Roles and groups

Similarly, the same Plone folks will often remind you to assign roles to groups and not users, and put users in groups to enable them to perform various tasks.

They might say:


This may be followed by:


Why? This is because to manage intricacies such as which user can perform which tasks and where, you are better off using the right tool for the job, that is adding users to groups with proper role assignments.

Unfortunately, end users are still able to assign roles to individual users if they really want to via the Sharing tab or Local roles form in the ZMI. So, it is the site manager's responsibility to make sure they do not, to avoid having a site littered with individual role assignments.


For the task of auditing role assignments, we have Andreas Jung's Cassandra (

You can perform a local roles security audit by installing Cassandra and following the steps given below.

In 07-security-cassandra.cfg, we have:

extends = 07-security-effective-user.cfg

eggs +=
zcml =

Now run Buildout:

$ bin/buildout -c 07-security-cassandra.cfg

You should see:

$ bin/buildout -c 07-security-cassandra.cfg
Getting distribution for 'zopyx.plone.cassandra'.

Got zopyx.plone.cassandra 0.2.0.


Browse to http://localhost:8080/Plone, click on Site Setup | Add-on Products to install Cassandra, and then browse to http://localhost:8080/Plone/@@cassandra.

On a new site, you should get no results (because no roles have been shared):

Security in Plone Sites

On an actively used site, you will see results similar to the following, where we use data from as an example.

For demonstration purposes, we present the output of

In other words, we installed Cassandra on (a local copy of), browsed to http://localhost:8080/, clicked on Documentation | Manuals | Plone 3 User Manual, and then added @@cassandra to the end of the URL (in the URL toolbar of your browser).

In the permission report (that took several minutes to generate), we see the following:

Security in Plone Sites

Since the output is recursive, we see local role assignments for the Current folder and everything below it.

Here are the results for the adding content subfolder (that is, /documentation/manual/plone-3-user-manual/adding-content):

Security in Plone Sites

The results for the rest of the subfolders are exactly the same (except for the folder name, of course).

So what does this tell you? Several things:

  • The Plone documentation team is awesome! Many people have dedicated their time and energy to writing (and rewriting) Plone's documentation for the beneft of the Plone community at large. If you know any of these folks (by their username), take a minute to thank them!
  • Though the Plone documentation team members are our documentation heroes, they have (apparently) not done a good job of assigning roles to groups. Instead, they have assigned them directly to the users.
  • The Cassandra output is (apparently) incomplete, as there are no roles listed after each colon. This may be due to the fact that Plone Help Center (a target="_blank" href=""> adds additional permissions, not available in default Plone.
  • All of the folders in the user manual have the same sharing settings, that is the same users and groups are listed for each folder. This suggests that local role settings are confgured in a parent of the user manual folder, for example/documentation/manual or /documentation.

Applying security and bug fixes to Plone

Although it is extremely rare, vulnerabilities are found in Plone occasionally and fixes are released.

Less rare, but almost as important, are the occasional bug fx releases for various packages within the Plone software stack.

Here, we are referring to packages that contain bug fxes that were not released with a particular point release of Plone. They may also be a part of the next point release (for example, 3.3.6).

Often, you need those fixes now. Under such circumstances, it is the responsibility of all Plone site administrators to deploy these fixes to their production sites as soon as possible.

In some cases (for example with Python egg packages), the fix can be as simple as changing a package version and running Buildout to get the latest compatible release (which presumably addresses the security, or the bug issue).

In other cases, alternative methods are required.

Such was the case with the last known Zope 2 security issue, which occurred in early 2010 (

Since many of the affected Plone sites had old style (non-egg package) Zope 2 software installations, that is, Zope 2 was installed from the gzipped and tarred source archive instead of using a "versionable" egg (starting from Zope 2.12, Zope 2 is packaged as an egg), it was necessary to update the URL of the Zope 2 source distribution in the buildout.

Using a newer Zope 2 with an older release of Plone

To demonstrate this, we are going to run an older (unsupported) version of Plone (2.1) with a newer version of Zope 2 (much newer than the version of Zope 2 Plone 2.1 was originally released with).

In general, it is safe to use the newest point release in a series. At the time of writing this, the newest point release for each (actively-maintained) series of Zope 2 releases is as follows:

Hold on to your buildouts

Generally speaking, it is always a good idea to keep in mind that Buildout maintains its state. So whenever you execute Buildout, you are asking it to modify its state. Hopefully, you are giving it sensible instructions, but humans are often fawed; we make silly mistakes. The good news is that if you make a mistake, it is almost always easily undone simply by executing Buildout again with the correct configuration file.

A "modern" Plone 2.1 buildout

In 07-security-plone21.cfg, we have:

find-links =
versions = versions
parts =

recipe = plone.recipe.zope2install
url =

recipe =
url =
strip-top-level-dir = true

recipe = plone.recipe.zope2instance
zope2-location = ${zope2:location}
user = admin:admin
eggs =
products =
plone.recipe.zope2instance = 3.6

You will notice that we specify the version of Zope 2 to install by setting the value of the url parameter to the URL of the Zope 2 gzipped and tarred archive on

We use Zope 2.8.12 because it is the newest version of Zope 2 that will work with the very old release of Plone, Plone 2.1.4.

We demonstrate this for one very important reason—to empower you to upgrade your Zope 2 installations in the event that a security issue is discovered. If and when this happens, a subsequent new version of Zope 2 will be released to address the issue, and you will need to know how to install it.

In case of many other packages (that is, those which are packaged as eggs) as we mentioned earlier, getting a newer package is often just a matter of specifying which version you want to install in your buildout.


That is all for this article. Here you have learned:

  • How to restrict TCP/IP access to localhost only
  • How to manage IP addresses and ports effectively with Buildout parts
  • How to configure the Zope 2 effective user dynamically with gocept.recipe.env
  • How to audit Plone security settings with Cassandra
  • How to upgrade Zope 2 in the event of a security or bug fix release

If you have read this article you may be interested to view:

You've been reading an excerpt of:

Plone 3.3 Site Administration

Explore Title