There is a document at plone.org suggesting to use plone 3.0 builtin "intranet" workflows, however this will not make a site absolutely private, i.e. force user to login before he can view anything. This is the use case for an extranet for example.
In the past we used to put something like tal:define="dummy here/rejectAnonymous" in global_defines.pt, rejectAnonymous was a skin script. Now with the help of events we can do far better, and it will work for any content/object within a plone site. As a consequence we must be careful about what is allowed to be retrievied anonymously, since anonymous should be able to see a themed login page.
The idea has been taken from plone.aftertraverse. An event is sent before traversal, but not immediatly after. The problem is that authentication is performed after traversal. Fortunately the request object accepts to register post traverse hooks, with arbitrary parameters.
The code, zcml part:
# -*- coding: utf-8 -*-
from zExceptions import Unauthorized
valid_subparts = set(('login.js', 'spinner.gif',
def rejectAnonymous(portal, request):
mtool = portal.portal_membership
url = request.physicalPathFromURL(request['URL'])
if url and not (url[-1] in ('login_form', 'require_login')
or [path for path in url
if path in valid_subparts]):
raise Unauthorized, "You must be authenticated"
def insertRejectAnonymousHook(portal, event):
event.request.post_traverse(rejectAnonymous, (portal, event.request))
The code checking for allowed path may not be the best, and it could certainly be more clever but for-me-it-worked(tm)