[Checkins] SVN: zdgbook/trunk/ stx to rst

Baiju M baiju.m.mail at gmail.com
Tue Feb 17 22:02:05 EST 2009


Log message for revision 96661:
  stx to rst
  

Changed:
  D   zdgbook/trunk/Security.stx
  A   zdgbook/trunk/source/Security.rst
  U   zdgbook/trunk/source/index.rst

-=-
Deleted: zdgbook/trunk/Security.stx
===================================================================
--- zdgbook/trunk/Security.stx	2009-02-18 02:26:31 UTC (rev 96660)
+++ zdgbook/trunk/Security.stx	2009-02-18 03:02:05 UTC (rev 96661)
@@ -1,1693 +0,0 @@
-Chapter 6: Security
-
-  Introduction
-
-    A typical web application needs to be securely managed.  Different
-    types of users need different kinds of access to the components
-    that make up an application. To this end, Zope includes a
-    comprehensive set of security features.  This chapter's goal is to
-    shed light on Zope security in the context of Zope Product
-    development.  For a more fundamental overview of Zope security,
-    you may wish to refer to the *Zope Book*, Chapter 6, Users and
-    Security.
-    Before diving into this chapter, you should have a basic
-    understanding of how to build Zope Products as well as an
-    understanding of how the Zope object publisher works. These topics
-    are covered in Chapter 2 and Chapter 3, respectively.
-
-      % Anonymous User - Sep. 12, 2002 11:30 am:
-       Our web-page is designed in a way to allow specific user groups access to certain parts of it. In order to
-       check this function we created in a lower hierarchy of the parent folder a new folder (test folder). Access
-       to the new folder has been restricted by cancelling all acquire permission settings.
-       The manager however obtains all rights to access and administrate the web-site. Another self-defined user
-       group shall only be able to view the defined pages.
-       When the web-site is reloaded in a new Internet Explorer Window the access is denied in general.
-       No matter whether this is attempted by the manager itself or some restricted user, who has been given
-       permission to enter specific parts of our web-pages. Unfortunately this is not the expected result. Has
-       anybody got a clue what is wrong ? What could be done to access a limited part of our system ?
-       contact: gis at nordschwarzwald-region.de
-
-      % Anonymous User - May 7, 2004 7:38 am:
-       This will make all lines very long, thus rendering the page almost useless. This will make all lines very
-       long, thus rendering the page almost useless. This will make all lines very long, thus rendering the page
-       almost useless. This will make all lines very long, thus rendering the page almost useless. This will make
-       all lines very long, thus rendering the page almost useless. This will make all lines very long, thus
-       rendering the page almost useless. This will make all lines very long, thus rendering the page almost
-       useless. This will make all lines very long, thus rendering the page almost useless. This will make all lines
-       very long, thus rendering the page almost useless. This will make all lines very long, thus rendering the
-       page almost useless. This will make all lines very long, thus rendering the page almost useless. This will
-       make all lines very long, thus rendering the page almost useless. This will make all lines very long, thus
-       rendering the page almost useless. This will make all lines very long, thus rendering the page almost
-       useless. This will make all lines very long, thus rendering the page almost useless. This will make all lines
-       very long, thus rendering the page almost useless. This will make all lines very long, thus rendering the
-       page almost useless. This will make all lines very long, thus rendering the page almost useless.
-
-      % Anonymous User - May 7, 2004 7:44 am:
-       While trying to read though the documentation at
-       http://zope.org/Documentation/Books/ZDG/current/Security.stx, I
-       noticed some very strange problems regarding the HTML.
-       The main problem is that the text in the <pre> tags are not 
-       automatically wrapped at 76 or 80 characters/columns. Therefore the 
-       containing element gets rendered as wide as the lines (user comments!) 
-       are long. 
-       I would recommend to wrap all user contributed text at 80 columns so 
-       that users don't have to scroll horizontal all the time.
-       Other problems regard XHTML-syntax, but I'll leave that to the 
-       page(-template) designers.
-       Regards,
-       Ronald van Engelen <zope-doc at lacocina.nl>
-
-  Security Architecture
-
-    The Zope security architecture is built around a *security
-    policy*, which you can think of as the "access control philosophy"
-    of Zope. This policy arbitrates the decisions Zope makes about
-    whether to allow or deny access to any particular object defined
-    within the system.
-
-    How The Security Policy Relates to Zope's Publishing Machinery
-
-      When access to Zope is performed via HTTP, WebDAV, or FTP,
-      Zope's publishing machinery consults the security policy in
-      order to determine whether to allow or deny access to a visitor
-      for a particular object.  For example, when a user visits the
-      root 'index_html' object of your site via HTTP, the security
-      policy is consulted by 'ZPublisher' to determine whether the user
-      has permission to view the 'index_html' object itself.  For more
-      information on this topic, see Chapter 3, 
-      "Object Publishing".
-
-      The Zope security policy is consulted when an object is accessed
-      the publishing machinery, for example when a web request
-      is submitted.
-
-        % Anonymous User - Oct. 1, 2002 9:49 am:
-         when an object is accessed the publishing machinery/when an object is accessed BY the publishing machinery
-
-    How The Security Policy Relates to Restricted Code
-
-      *Restricted code* is generally any sort of logic that may be
-      edited remotely (through the Web, FTP, via WebDAV or by other
-      means). DTML Methods, SQLMethods, Python Scripts and Perl
-      Scripts are examples of restricted code.
-
-        % Anonymous User - Aug. 4, 2004 6:00 pm:
-         this applies to some but not to others
-
-      When restricted code runs, any access to objects integrated with
-      Zope security is arbitrated by the security policy. For example
-      if you write a bit of restricted code with a line that attempts
-      to manipulate an object you don't have sufficient permission to
-      use, the security policy will deny you access to the object.
-      This generally is accomplished by raising an 'Unauthorized'
-      exception, which is a Python string exception caught by a User
-      Folder which signifies that Zope should attempt to get user
-      credentials before obeying the request.  The particular code
-      used to attempt to obtain the credentials is determined by the
-      User Folder "closest" (folder-wise) to the object being
-      accessed.
-
-      The Zope security policy is consulted when an object is accessed
-      by restricted code.
-
-    'Unauthorized' Exceptions and Through-The-Web Code
-
-      The security policy infrastructure will raise an 'Unauthorized'
-      exception automatically when access to an object is denied.
-      When an 'Unauthorized' exception is raised within Zope, it is
-      handled in a sane way by Zope, generally by having the User
-      Folder prompt the user for login information.  Using this
-      functionality, it's possible to protect Zope objects through
-      access control, only prompting the user for authentication when
-      it is necessary to perform an action which requires privilege.
-
-      An example of this behavior can be witnessed within the Zope
-      Management interface itself.  The management interface prompts
-      you to log in when visiting, for example, the '/manage' method
-      of any Zope object.  This is due to the fact that an anonymous
-      user does not generally possess the proper credentials to use the
-      management interface.  If you're using Zope in the default
-      configuration with the default User Folder, it prompts you to
-      provide login information via an HTTP basic authentication
-      dialog.
-
-    How The Security Policy Relates To Unrestricted Code
-
-      There are also types of *unrestricted code* in Zope, where the
-      logic is not constrained by the security policy. Examples of
-      unrestricted code are the methods of Python classes that
-      implement the objects in Python file-based add-on components.
-      Another example of unrestricted code can be found in External
-      Method objects, which are defined in files on the filesystem.
-      These sorts of code are allowed to run "unrestricted" because
-      access to the file system is required to define such logic.
-      Zope assumes that code defined on the filesystem is "trusted",
-      while code defined "through the web" is not.  All
-      filesystem-based code in Zope is unrestricted code.
-
-      We'll see later that while the security policy does not
-      constrain what your unrestricted code does, it can and should be
-      used to control the ability to *call* your unrestricted code
-      from within a restricted-code environment.
-
-      The Zope security policy is *not* consulted when unrestricted
-      code is run.
-
-    Details Of The Default Zope Security Policy
-
-      In short, the default Zope security policy
-      ensures the following:
-
-       - access to an object which does not have any associated security
-         information is always denied.
-
-       - if an object is associated with a permission, access is
-         granted or denied based on the user's roles.  If a user has a
-         role which has been granted the permission in question, access
-         is granted.  If the user does not possess a role that has been
-         granted the permission in question, access is denied.
-
-       - if the object has a security assertion declaring it *public* ,
-         then access will be granted.
-
-       - if the object has a security assertion declaring it *private*,
-         then access will be denied.
-
-       - accesses to objects that have names beginning with the 
-         underscore character '_' are always denied.
-
-      As we delve further into Zope security within this chapter,
-      we'll see exactly what it means to associate security
-      information with an object.
-
-        % zigg - Feb. 12, 2002 11:40 am - What about object__roles__?
-
-        % mcdonc - Mar. 2, 2002 4:45 pm - That's how roles are implemented at the bottom of the Zope security implementation, but "low level" stuff like this is unfortunately not covered in this guide.  Indeed, it's probably not comprehensively covered anywhere.
-
-        % Anonymous User - Apr. 17, 2002 5:54 am:
-         I think you should add here that access to methods without a docstring
-         is denied, too
-
-        % Anonymous User - Apr. 17, 2002 7:39 am:
-         If the user has the role 'Manager' he is allowed to access
-
-        % Anonymous User - Feb. 24, 2003 6:55 pm:
-         No, 'Manager' is not any kind of superuser.
-         Managers can remove permissions for Managers and then they will be denied!
-         Only the "emergency" users can override this.
-
-  Overview Of Using Zope Security Within Your Product
-
-    Of course, now that we know what the Zope security policy is, we
-    need to know how our Product can make use of it.  Zope developers
-    leverage the Zope security policy primarily by making security
-    declarations related to methods and objects within their Products.
-    Using security assertions, developers may deny or allow all types
-    of access to a particular object or method unilaterally, or they
-    may protect access to Zope objects more granularly by using
-    permissions to grant or deny access based on the roles of the
-    requesting user to the same objects or methods.
-
-      % Anonymous User - Nov. 19, 2001 10:22 am - what about getSecurityManager().getUser()?  I've heard a nasty unexpected API difference that  getSecurityManager().getUser().hasRole() is not preferred.  getSecurityManager().getUser().has_role() is preferred.  whats the beef?    will we get a getSecurityManager().getUser().isAuthenticated() ? I dont see this in the Basic User class.  or isAnonymous() ?  I dont see why this ease on the API couldnt be implemented as well as *desired*  we need to stop hardcoding 'Anonymous User' and 'Authenticated User' everywhere.  Please address this in this security section.    my realworld problem: I'm implemented under a 3rd party Product API in ZOPE, I need to short circuit a method if the user is not authenticated.  whats the blessed way of doing this?    george runyan
-
-      % mcdonc - Mar. 2, 2002 4:50 pm - There is no isAuthenticated method in the user API.  In Zopes after 2.4, just look for 'Authenticated' in the user's roles and switch based on that.  Finding out if a user is authenticated in Zopes prior to 2.4 is an exercise in making sure the user is not the 'Anonymous User' by checking the username. Use of hasRole is deprecated and has_role should be used.
-
-    For a more fundamental overview of Zope users, roles, and
-    permissions, see the section titled "Authorization and Managing
-    Security" in the Security
-    Chapter of
-    the *Zope Book*.
-
-    Security Declarations In Zope Products
-
-      Zope security declarations allow developers to make security
-      assertions about a Product-defined object and its methods.
-      Security declarations come in three basic forms.  These are:
-
-        public -- allow anybody to access the protected object
-        or method
-
-        private -- deny anyone access to the protected object or
-        method
-
-        protected -- protect access to the object or method via a
-        permission
-
-      We'll see how to actually "spell" these security assertions a
-      little later in this chapter.  In the meantime, just know that
-      security declarations are fundamental to Zope Product security,
-      and they can be used to protect access to an object by
-      associating it with a permission.  We will refer to security
-      declarations as "declarations" and "assertions" interchangeably
-      within this chapter.
-
-        % dudek - Apr. 28, 2002 12:10 pm:
-         Rather than "spell" which is colorful but potentiall clightly vague, maybe saying
-         "We'll see how to specify and manipulate these security asertions..."
-
-    Permissions In Zope Products
-
-      A permission is the smallest unit of access to an object in
-      Zope, roughly equivalent to the atomic permissions on files seen
-      in Windows NT or UNIX: R (Read), W(Write), X(Execute),
-      etc. However, unlike these types of mnemonic permissions shared
-      by all sorts of different file types in an operating system
-      product, in Zope, a permission usually describes a fine-grained
-      logical operation which takes place upon an object, such as
-      "View Management Screens" or "Add Properties".
-
-      Zope administrators associate these permissions with *roles*,
-      which they grant to Zope users.  Thus, declaring a protection
-      assertion on a method of "View management screens" ensures that
-      only users who possess roles which have been granted the "View
-      management screens" permission are able to perform the action
-      that the method defines.
-
-      It is important to note that Zope's security architecture
-      dictates that roles and users remain the domain of
-      administrators, while permissions remain the domain of
-      developers.  Developers of Products should not attempt to define
-      roles or users, although they may (and usually must) define
-      permissions.  Most importantly, a Zope administrator who makes
-      use of your product should have the "last word" as regards which
-      roles are granted which permissions, allowing her to protect her
-      site in a manner that fits her business goals.
-
-      Permission names are strings, and these strings are currently
-      arbitrary.  There is no permission hierarchy, or list of
-      "approved permissions".  Developers are encouraged to reuse Zope
-      core permissions (e.g. "View", "Access contents information")
-      when appropriate, or they may create their own as the need
-      arises.  It is generally wise to reuse existing Zope permission
-      names unless you specifically need to define your own.  For a
-      list of existing Zope core permissions, see Appendix A, "Zope Core
-      Permissions".
-
-      Permissions are often tied to method declarations in Zope.  Any
-      number of method declarations may share the same permission.
-      It's useful to declare the same permission on a set of methods
-      which can logically be grouped together.  For example, two
-      methods which return management forms for the object can be
-      provided with the same permission, "View management screens".
-      Likewise, two entirely different objects can share a permission
-      name to denote that the operation that's being protected is
-      fundamentally similar.  For instance, most Product-defined
-      objects reuse the Zope "View" permission, because most Zope
-      objects need to be viewed in a web browser.  If you create an
-      addable Zope class named 'MyObject', it doesn't make much sense
-      to create a permission "View MyObject", because the generic
-      "View" permission may be reused for this action.
-
-      There is an exception to the "developers should not try to
-      define roles" rule inasmuch as Zope allows developers to assign
-      "default roles" to a permission.  This is primarily for the
-      convenience of the Zope administrator, as default roles for a
-      permission cause the Zope security machinery to provide a
-      permission to a role *by default* when instances of a Product
-      class are encountered during security operations.  For example,
-      if your Product defines a permission "Add Poll Objects", this
-      permission may be associated with a set of default roles,
-      perhaps "Manager".  Default roles in Products should not be used
-      against roles other than "Manager", "Anonymous", "Owner", and
-      "Authenticated" (the four default Zope roles), as other roles
-      are not guaranteed to exist in every Zope installation.
-
-      Using security assertions in Zope is roughly analogous to
-      assigning permission bit settings and ownership information to
-      files in a UNIX or Windows filesystem.  Protecting objects via
-      permissions allows developers and administrators to secure Zope
-      objects independently of statements made in application code.
-
-  Implementing Security In Python Products
-
-    Security Assertions
-
-      You may make several kinds of security assertions at the Python
-      level.  You do this to declare accessibility of methods and
-      subobjects of your classes. Three of the most common assertions
-      that you'll want to make on your objects are:
-
-       - this object is **public** (always accessible)
-
-       - this object is **private** (not accessible by restricted 
-         code or by URL traversal)
-
-       - this object is **protected** by a specific permission
-
-      There are a few other kinds of security assertions that are 
-      much less frequently used but may be needed in some cases:
-
-       - asserting that access to subobjects that do not have explicit
-         security information should be allowed rather than denied.
-
-       - asserting what sort of protection should be used when 
-         determining access to an *object itself* rather than 
-         a particular method of the object
-
-      It is important to understand that security assertions made in
-      your Product code *do not* limit the ability of the code that
-      the assertion protects.  Assertions only protect *access to this
-      code*.  The code which constitutes the body of a protected,
-      private, or public method of a class defined in a Zope
-      disk-based Product runs completely unrestricted, and is not
-      subject to security constraints of any kind within Zope.  An
-      exception to this rule occurs when disk-based-Product code calls
-      a "through the web" method such as a Python Script or a DTML
-      Method.  In this case, the security constraints imposed by these
-      objects respective to the current request are obeyed.
-
-    When Should I Use Security Assertions?
-
-      If you are building an object that will be used from DTML or
-      other restricted code, or that will be accessible directly
-      through the web (or other remote protocols such as FTP or
-      WebDAV) then you need to define security information for your
-      object.
-
-    Making Security Assertions
-
-      As a Python developer, you make security assertions in your
-      Python classes using 'SecurityInfo' objects. A 'SecurityInfo'
-      object provides the interface for making security assertions
-      about an object in Zope.
-
-      The convention of placing security declarations inside Python
-      code may at first seem a little strange if you're used to "plain
-      old Python" which has no notion at all of security declarations.
-      But because Zope provides the ability to make these security
-      assertions at such a low level, the feature is ubiquitous
-      throughout Zope, making it easy to make these declarations once
-      in your code, usable site-wide without much effort.
-
-  Class Security Assertions
-
-    The most common kind of 'SecurityInfo' you will use as a component
-    developer is the 'ClassSecurityInfo' object.  You use
-    'ClassSecurityInfo' objects to make security assertions about
-    methods on your classes.
-
-    Classes that need security assertions are any classes that define
-    methods that can be called "through the web".  This means any
-    methods that can be called directly with URL traversal, from DTML
-    Methods, or from Python-based Script objects.
-
-    Declaring Class Security
-
-      When writing the classes in your product, you create a
-      'ClassSecurityInfo' instance *within each class that needs to
-      play with the security model*. You then use the
-      'ClassSecurityInfo' object to make assertions about your class,
-      its subobjects and its methods.
-
-      The 'ClassSecurityInfo' class is defined in the 'AccessControl'
-      package of the Zope framework. To declare class security
-      information create a 'ClassSecurityInfo' class attribute named
-      'security'.  The name 'security' is used for consistency and for
-      the benefit of new component authors, who often learn from
-      looking at other people's code. You do not have to use the
-      name 'security' for the security infrastructure to recognize
-      your assertion information, but it is recommended as a
-      convention.  For example::
-
-        from AccessControl import ClassSecurityInfo
-
-        class Mailbox(ObjectManager):
-          """A mailbox object that contains mail message objects."""
-
-          # Create a SecurityInfo for this class. We will use this 
-          # in the rest of our class definition to make security 
-          # assertions.
-          security = ClassSecurityInfo()
-
-          # Here is an example of a security assertion. We are 
-          # declaring that access to messageCount is public.
-          security.declarePublic('messageCount')
-
-          def messageCount(self):
-            """Return a count of messages."""
-            return len(self._messages)
-
-        % Anonymous User - Jan. 23, 2003 9:54 am:
-         How is security.declarePublic('messageCount') different from 
-         messageCount__roles__=None ? Or is the latter way obsolete?
-
-        % Anonymous User - May 13, 2003 4:25 pm:
-         From looking at the source (and doing some debugging), I've concluded that ClassSecurityInfo is just another
-         indirection the Zope folks have decided to place on us. If you look in the method apply() in
-         AccessControl/SecurityInfo.py around line 220, you'll notice that it pretty much automates the creation of
-         FooBar__roles__ attributes and the __ac_permissions__ .
-         I don't see any Unit Tests for any of that code though, so I wouldn't bother with ClassSecurityInfo unless
-         you're really into Zope voodoo and want your applications security to be automagically munged and then
-         injected back into your object.
-
-      Note that in the example above we called the 'declarePublic'
-      method of the 'ClassSecurityInfo' instance to declare that
-      access to the 'messageCount' method be public. To make security
-      assertions for your object, you just call the appropriate
-      methods of the 'ClassSecurityInfo' object, passing the
-      appropriate information for the assertion you are making.
-
-      'ClassSecurityInfo' approach has a number of benefits. A major
-      benefit is that it is very explicit, it allows your security
-      assertions to appear in your code near the objects they protect,
-      which makes it easier to assess the state of protection of your
-      code at a glance. The 'ClassSecurityInfo' interface also allows
-      you as a component developer to ignore the implementation
-      details in the security infrastructure and protects you from
-      future changes in those implementation details.
-
-      Let's expand on the example above and see how to make the most
-      common security assertions using the 'SecurityInfo' interface.
-
-      To assert that a method is *public* (anyone may call it) you may
-      call the 'declarePublic' method of the 'SecurityInfo' object,
-      passing the name of the method or subobject that you are making
-      the assertion on::
-
-        security.declarePublic(methodName)
-
-      To assert that a method is *private* you call the
-      'declarePrivate' method of the 'SecurityInfo' object, passing
-      the name of the method or subobject that you are making the
-      assertion on::
-
-        security.declarePrivate(methodName)
-
-      To assert that a method or subobject is *protected* by a
-      particular permission, you call the 'declareProtected' method of
-      the 'SecurityInfo' object, passing a permission name and the
-      name of a method to be protected by that permission::
-
-        security.declareProtected(permissionName, methodName)
-
-      If you have lots of methods you want to protect under the same
-      permission, you can pass as many methodNames ase you want::
-
-        security.declareProtected(permissionName, methodName1,
-        methodName2, methodName3, ...)
-
-      Passing multiple names like this works for all of the 'declare'
-      security methods ('declarePublic', 'declarePrivate', and
-      'declareProtected').
-
-    Deciding To Use 'declareProtected' vs. 'declarePublic' or 'declarePrivate'
-
-      If the method you're making the security declaration against is
-      innocuous, and you're confident that its execution will not
-      disclose private information nor make inappropriate changes to
-      system state, you should declare the method public.
-
-      If a method should never be run under any circumstances via
-      traversal or via through-the-web code, the method should be
-      declared private.  This is the default if a method has no
-      security assertion, so you needn't explicitly protect
-      unprotected methods unless you've used 'setDefaultAccess' to set
-      the object's default access policy to 'allow' (detailed in
-      *Other Assertions*, below).
-
-      If the method should only be executable by a certain class of
-      users, you should declare the method protected.
-
-    A Class Security Example
-
-      Let's look at an expanded version of our 'Mailbox' example that 
-      makes use of each of these types of security assertions::
-
-        from AccessControl import ClassSecurityInfo
-        import Globals
-
-        class Mailbox(ObjectManager):
-          """A mailbox object."""
-
-        # Create a SecurityInfo for this class
-          security = ClassSecurityInfo()
-
-          security.declareProtected('View management screens', 'manage')
-          manage=HTMLFile('mailbox_manage', globals())
-
-          security.declarePublic('messageCount')
-          def messageCount(self):
-            """Return a count of messages."""
-            return len(self._messages)
-
-          # protect 'listMessages' with the 'View Mailbox' permission
-          security.declareProtected('View Mailbox', 'listMessages')
-
-          def listMessages(self):
-            """Return a sequence of message objects."""
-            return self._messages[:]
-
-          security.declarePrivate('getMessages')
-          def getMessages(self):
-            self._messages=GoGetEm()
-            return self._messages
-
-        # call this to initialize framework classes, which
-        # does the right thing with the security assertions.
-        Globals.InitializeClass(Mailbox)
-
-      Note the last line in the example.  In order for security
-      assertions to be correctly applied to your class, you must call
-      the global class initializer ('Globals.InitializeClass') for all
-      classes that have security information. This is very important -
-      the global initializer does the "dirty work" required to ensure
-      that your object is protected correctly based on the security
-      assertions that you have made. If you don't run it on the
-      classes that you've protected with security assertions, the
-      security assertions will not be effective.
-
-    Deciding Permission Names For Protected Methods
-
-      When possible, you should make use of an existing Zope
-      permission within a 'declareProtected' assertion.  A list of the
-      permissions which are available in a default Zope installation
-      is available within Appendix A.  When it's not possible to reuse
-      an existing permission, you should choose a permission name
-      which is a verb or a verb phrase.
-
-    Object Assertions
-
-      Often you will also want to make a security assertion on the
-      *object itself*. This is important for cases where your objects
-      may be accessed in a restricted environment such as
-      DTML. Consider the example DTML code::
-
-        <dtml-var expr="some_method(someObject)">
-
-      Here we are trying to call 'some_method', passing the object
-      'someObject'. When this is evaluated in the restricted DTML
-      environment, the security policy will attempt to validate access
-      to both 'some_method' and 'someObject'. We've seen how to make
-      assertions on methods - but in the case of 'someObject' we are
-      not trying to access any particular method, but rather the
-      *object itself* (to pass it to 'some_method'). Because the
-      security machinery will try to validate access to 'someObject',
-      we need a way to let the security machinery know how to handle
-      access to the object itself in addition to protecting its
-      methods.
-
-      To make security assertions that apply to the *object itself* 
-      you call methods on the 'SecurityInfo' object that are analogous 
-      to the three that we have already seen::
-
-        security.declareObjectPublic()
-
-        security.declareObjectPrivate()
-
-        security.declareObjectProtected(permissionName)
-
-      The meaning of these methods is the same as for the method 
-      variety, except that the assertion is made on the object itself. 
-
-    An Object Assertion Example
-
-      Here is the updated 'Mailbox' example, with the addition of a 
-      security assertion that protects access to the object itself 
-      with the 'View Mailbox' permission::
-
-        from AccessControl import ClassSecurityInfo
-        import Globals
-
-        class Mailbox(ObjectManager):
-          """A mailbox object."""
-
-          # Create a SecurityInfo for this class
-          security = ClassSecurityInfo()
-
-          # Set security for the object itself
-          security.declareObjectProtected('View Mailbox')
-
-          security.declareProtected('View management screens', 'manage')
-          manage=HTMLFile('mailbox_manage', globals())
-
-          security.declarePublic('messageCount')
-          def messageCount(self):
-            """Return a count of messages."""
-            return len(self._messages)
-
-          # protect 'listMessages' with the 'View Mailbox' permission
-          security.declareProtected('View Mailbox', 'listMessages')
-
-          def listMessages(self):
-            """Return a sequence of message objects."""
-            return self._messages[:]
-
-          security.declarePrivate('getMessages')
-          def getMessages(self):
-            self._messages=GoGetEm()
-            return self._messages
-
-        # call this to initialize framework classes, which
-        # does the right thing with the security assertions.
-        Globals.InitializeClass(Mailbox)
-
-    Other Assertions
-
-      The SecurityInfo interface also supports the less common
-      security assertions noted earlier in this document.
-
-      To assert that access to subobjects that do not have explicit
-      security information should be *allowed* rather than *denied* by
-      the security policy, use::
-
-        security.setDefaultAccess("allow")
-
-      This assertion should be used with caution. It will effectively
-      change the access policy to "allow-by-default" for all
-      attributes in your object instance (not just class attributes)
-      that are not protected by explicit assertions.  By default, the
-      Zope security policy flatly denies access to attributes and
-      methods which are not mentioned within a security assertion.
-      Setting the default access of an object to "allow" effectively
-      reverses this policy, allowing access to all attributes and
-      methods which are not explicitly protected by a security
-      assertion.
-
-      'setDefaultAccess' applies to attributes that are simple Python
-      types as well as methods without explicit protection. This is
-      important because some mutable Python types (lists, dicts) can
-      then be modified by restricted code. Setting default access to
-      "allow" also affects attributes that may be defined by the base
-      classes of your class, which can lead to security holes if you
-      are not sure that the attributes of your base classes are safe
-      to access.
-
-      Setting the default access to "allow" should only be done if you
-      are sure that all of the attributes of your object are safe to
-      access, since the current architecture does not support using
-      explicit security assertions on non-method attributes.
-
-    What Happens When You Make A Mistake Making 'SecurityInfo' Declarations?
-
-      It's possible that you will make a mistake when making
-      'SecurityInfo' declarations.  For example, it is not legal to
-      declare two conflicting permissions on a method::
-
-        class Foo(SimpleItem):
-            security = ClassSecurityInfo()
-
-            meta_type='Foo'
-
-            security.declareProtected('View foos', 'index_html')
-            def index_html(self):
-                """ make index_html web-publishable """
-                return "<html><body>hi!</body></html>"
-
-            security.declareProtected('View', 'index_html')
-            # whoops, declared a conflicting permission on index_html!
-
-      When you make a mistake like this, the security machinery will
-      accept the *first* declaration made in the code and will write
-      an error to the Zope debug log upon encountering the second and
-      following conflicting declarations during class initialization.
-      It's similarly illegal to declare a method both private and
-      public, or to declare a method both private and protected, or to
-      declare a method both public and protected. A similar error will
-      be raised in all of these cases.
-
-      Note that Zope *will not* warn you if you misspell the name of
-      a method in a declareProtected, declarePublic, or declarePrivate
-      assertion.  For instance, you try to protect the 'index_html'
-      method with the 'View' permission and make a mistake,
-      spelling the name 'index_html' as 'inde_html', like so::
-
-            security.declareProtected('View', 'inde_html')
-            # whoops, declared a permission assertion for 'inde_html'
-            # when I really wanted it to be 'index_html'!
-            def index_html(self):
-                """ make index_html web-publishable """
-                return "<html><body>hi!</body></html>"
-
-      You'll need to track down these kinds of problems yourself.
-
-    Setting Default Roles For Permissions
-
-      When defining operations that are protected by permissions, one
-      thing you commonly want to do is to arrange for certain roles to
-      be associated with a particular permission *by default* for
-      instances of your object.
-
-      For example, say you are creating a *News Item* object. You want
-      'Anonymous' users to have the ability to view news items by
-      default; you don't want the site manager to have to explicitly
-      change the security settings for each *News Item* just to give
-      the 'Anonymous" role 'View' permission.
-
-      What you want as a programmer is a way to specify that certain
-      roles should have certain permissions by default on instances of
-      your object, so that your objects have sensible and useful
-      security settings at the time they are created. Site managers
-      can always *change* those settings if they need to, but you can
-      make life easier for the site manager by setting up defaults
-      that cover the common case by default.
-
-      As we saw earlier, the 'SecurityInfo' interface provided a way
-      to associate methods with permissions. It also provides a way to
-      associate a permission with a set of default roles that should
-      have that permission on instances of your object.
-
-      To associate a permission with one or more roles, use the 
-      following::
-
-        security.setPermissionDefault(permissionName, rolesList)
-
-      The *permissionName* argument should be the name of a permission
-      that you have used in your object and *rolesList* should be a
-      sequence (tuple or list) of role names that should be associated
-      with *permissionName* by default on instances of your object.
-
-      Note that it is not always necessary to use this method. All
-      permissions for which you did not set defaults using
-      'setPermissionDefault' are assumed to have a single default role
-      of 'Manager'.  Notable exceptions to this rule include 'View'
-      and 'Access contents information', which always have the default
-      roles 'Manager' and 'Anonymous'.
-
-      The 'setPermissionDefault' method of the 'SecurityInfo' 
-      object should be called only once for any given permission 
-      name. 
-
-        % Anonymous User - Oct. 21, 2003 6:20 am:
-         SecurityInfo object should be called only once for any given permission name: 
-                 is that once per object ie many times if there are several classes is a product, or once per product?
-
-        % Anonymous User - Jan. 29, 2004 2:19 am:
-         This paragraph seems to conflict with the earlier example granting 'View' to 'Anonymous', as Zope will have
-         already granted default roles to builtin permissions.
-
-    An Example of Associating Default Roles With Permissions
-
-      Here is our  'Mailbox' example, updated to associate the 
-      'View Mailbox' permission with the roles 'Manager' and 
-      'Mailbox Owner' by default::
-
-        from AccessControl import ClassSecurityInfo
-        import Globals
-
-        class Mailbox(ObjectManager):
-          """A mailbox object."""
-
-          # Create a SecurityInfo for this class
-          security = ClassSecurityInfo()
-
-          # Set security for the object itself
-          security.declareObjectProtected('View Mailbox')
-
-          security.declareProtected('View management screens', 'manage')
-          manage=DTMLFile('mailbox_manage', globals())
-
-          security.declarePublic('messageCount')
-          def messageCount(self):
-            """Return a count of messages."""
-            return len(self._messages)
-
-          security.declareProtected('View Mailbox', 'listMessages')
-          def listMessages(self):
-            """Return a sequence of message objects."""
-            return self._messages[:]
-
-          security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
-
-        # call this to initialize framework classes, which
-        # does the right thing with the security assertions.
-        Globals.InitializeClass(Mailbox)
-
-    What Happens When You Make A Mistake Declaring Default Roles?
-
-      It's possible that you will make a mistake when making default
-      roles declarations.  For example, it is not legal to declare two
-      conflicting default roles for a permission::
-
-        class Foo(SimpleItem):
-            security = ClassSecurityInfo()
-
-            meta_type='Foo'
-
-            security.declareProtected('View foos', 'index_html')
-            def index_html(self):
-                """ """
-                return "<html><body>hi!</body></html>"
-
-            security.setPermissionDefault('View foos', ('Manager',))
-
-            security.setPermissionDefault('View foos', ('Anonymous',))
-            # whoops, conflicting permission defaults!
-
-      When you make a mistake like this, the security machinery will
-      accept the *first* declaration made in the code and will write
-      an error to the Zope debug log about the second and following
-      conflicting declarations upon class initialization.
-
-    What Can (And Cannot) Be Protected By Class Security Info?
-
-      It is important to note what can and cannot be protected using
-      the 'ClassSecurityInfo' interface. First, the security policy
-      relies on *Acquisition* to aggregate access control information,
-      so any class that needs to work in the security policy must have
-      either 'Acquisition.Implicit' or 'Acquisition.Explicit' in its
-      base class hierarchy.
-
-        % Anonymous User - Nov. 9, 2002 12:37 pm:
-         Here a document or reference to listing base class hierarchies 
-         of zopes built-in classes might be wellcome.
-
-      The current security policy supports protection of methods and
-      protection of subobjects that are instances. It does *not*
-      currently support protection of simple attributes of basic
-      Python types (strings, ints, lists, dictionaries). For
-      instance::
-
-        from AccessControl import ClassSecurityInfo
-        import Globals
-
-        # We subclass ObjectManager, which has Acquisition in its
-        # base class hierarchy, so we can use SecurityInfo.
-
-        class MyClass(ObjectManager):
-          """example class"""
-
-          # Create a SecurityInfo for this class
-          security = ClassSecurityInfo()
-
-          # Set security for the object itself
-          security.declareObjectProtected('View')
-
-          # This is ok, because subObject is an instance
-          security.declareProtected('View management screens', 'subObject')
-          subObject=MySubObject()
-
-          # This is ok, because sayHello is a method
-          security.declarePublic('sayHello')
-          def sayHello(self):
-            """Return a greeting."""
-            return "hello!"
-
-          # This will not work, because foobar is not a method
-          # or an instance - it is a standard Python type
-          security.declarePublic('foobar')
-          foobar='some string'
-
-      Keep this in mind when designing your classes. If you need
-      simple attributes of your objects to be accessible (say via
-      DTML), then you need to use the 'setDefaultAccess' method of
-      'SecurityInfo' in your class to allow this (see the note above
-      about the security implications of this). In general, it is
-      always best to expose the functionality of your objects through
-      methods rather than exposing attributes directly.
-
-      Note also that the actual 'ClassSecurityInfo' instance you use to
-      make security assertions is implemented such that it is *never*
-      accessible from restricted code or through the Web (no action on
-      the part of the programmer is required to protect it).
-
-    Inheritance And Class Security Declarations
-
-      Python inheritance can prove confusing in the face of security
-      declarations.
-
-        % rboylan - July 20, 2002 2:14 am:
-         This comment extends beyond security to all the meta information (e.g., meta_type) that Zope embeds in the
-         class declarations. It seems that, in general, that information is not inherited as one would expect.
-         If this is so, it would probably be worth discussing it explicitly somewhere to alert people to this. Even
-         better would be to get inheritance to work "normally" with this information as well. This is one of the
-         elements of cognitive friction that slows down acquisition of Zope (pun intended).
-
-      If a base class which has already been run through
-      "InitializeClass" is inherited by a superclass, nothing special
-      needs to be done to protect the base class' methods within the
-      superclass unless you wish to modify the declarations made in
-      the base class.  The security declarations "filter down" into
-      the superclass.
-
-        % rboylan - July 20, 2002 2:10 am:
-         I really hope all occurrences of "superclass" in the preceding paragraph should be "subclass", or else I'm
-         very confused.
-
-        % jhohm - Sep. 5, 2002 7:40 pm:
-         That's the trouble with "superclass" and "subclass". The author intended that "superclass" indicate the
-         derived class that inherits from the "subclass", so the "superclass" has features that are a superset of the
-         "subclass". Others tend to look at things the opposite way. I propose using "base class" and "derived class"
-         consistently, as they are commonly understood.
-
-        % Anonymous User - Oct. 3, 2002 7:12 am:
-         That's just plain wrong. "superclass" and "subclass" are well-defined object-oriented programming terms,
-         which the author is using wrongly here. You can't "look at it the opposite way".
-
-      On the other hand, if a base class hasn't been run through the
-      global class initializer ('InitializeClass'), you need to proxy
-      its security declarations in the superclass if you wish to
-      access any of its methods within through-the-web code or via URL
-      traversal.
-
-      In other words, security declarations that you make using
-      'ClassSecurityInfo' objects effect instances of the class upon
-      which you make the declaration. You only need to make security
-      declarations for the methods and subobjects that your class
-      actually *defines*. If your class inherits from other classes,
-      the methods of the base classes are protected by the security
-      declarations made in the base classes themselves. The only time
-      you would need to make a security declaration about an object
-      defined by a base class is if you needed to *redefine* the
-      security information in a base class for instances of your own
-      class. An example below redefines a security assertion in a
-      subclass::
-
-        from AccessControl import ClassSecurityInfo
-        import Globals
-
-        class MailboxBase(ObjectManager):
-          """A mailbox base class."""
-
-          # Create a SecurityInfo for this class
-          security = ClassSecurityInfo()
-
-          security.declareProtected('View Mailbox', 'listMessages')
-          def listMessages(self):
-            """Return a sequence of message objects."""
-            return self._messages[:]
-
-          security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
-
-        Globals.InitializeClass(MailboxBase)
-
-        class MyMailbox(MailboxBase):
-          """A mailbox subclass, where we want the security for 
-            listMessages to be public instead of protected (as 
-            defined in the base class)."""
-
-          # Create a SecurityInfo for this class
-          security = ClassSecurityInfo()
-
-          security.declarePublic('listMessages')
-
-        Globals.InitializeClass(MyMailbox)
-
-        % Anonymous User - June 25, 2002 6:13 am:
-         "If your class inherits from other classes, the methods of the base classes are protected by the security
-         declarations made in the base classes themselves. "
-         Maybe this is true for non-static methods, however I have contradicting experience with static methods:
-         class base:
-           index_html = Globals.DTMLFile('dtml/index_html',globals())
-           security.declarePrivate('index_html')
-         class derived(base):
-           pass # index_html *is* accessible here ...
-         Regards
-         dvadasz _at_ amadeus _dot_ net
-
-        % rboylan - July 20, 2002 2:07 am:
-         There is a lot of ambiguity in this whole section.  I have summarized 
-         Chris McDonough's responses in [].
-         1. If a subclass redefines a base class method, does the subclass need
-         to do a security declaration on it?  The document says "You only need
-         to make security declarations for methods .... your class actually
-         defines.  If your class inherits from other classes, the methods of
-         the base classes are protected by the security declarations made in
-         the base classes."  The first sentence seems to indicate a security
-         declaration is necessary (since you define the method); the second
-         sentence suggests its not.  It depends partly on the meaning of
-         "define" and also "method" (that is, is redefinition considered
-         definition?  does method refer to a name or to a specific classes
-         implementation of that name?). [Yes, you do need to redeclare security.]
-         2. Does a subclass need to have
-            security = ClassSecurityInfo()
-         in it if the base class does?  Judging from the example, yes. [yes]
-         3. Under what circumstances is the declaration in 2 necessary?  For
-         example, only if new method names are introduced and protected?  Or
-         any reference to security in the subclass?  It seems the latter, from
-         the example. [any time a class references the security object it should define
-         a new one with security = ClassSecurityInfo().]
-         4. Suppose we wanted to change the security of a base class method
-         without otherwise redefining it.  What's necessary then?
-         [You need to have a security = ... statement and you need to do
-         an InitializeClass.]
-         5. Under what conditions is InitializeClass necessary for the subclass
-         when the base class has been through InitializeClass?  (The guide only
-         addresses the case when the base class has not been so processed.  It
-         also says the declarations "filter down", but the implication of this
-         for new method is unclear.)
-         [Anytime you have a security = you should do an InitializeClass.
-         You can never cause trouble by doing an InitializeClass]
-         This section has a lot of explicit discussion of odd cases (no
-         security in superclass, redefining permissions on existing methods
-         without changing them) and not enough about the normal cases (my
-         subclass extends some base class methods and defines some new ones).
-         [A later response indicated it might be possible to get away without some of these activities, but it is
-         definitely safe to do them.]
-         RossBoylan at stanfordalumni.org
-
-        % Anonymous User - July 20, 2002 2:44 pm:
-         Let's do some investigation.  This is going to be sublimely painful, I'm sure. ;-)
-         Let's define a simple Product named SecurityTest.
-         Its __init__.py is this:
-           import SecurityTest
-           from Products.Transience import Transience
-           form = SecurityTest.constructSecurityTestForm
-           constructor = SecurityTest.constructSecurityTest
-           def initialize(context):
-               context.registerClass(
-                   SecurityTest.SecurityTest,
-                   constructors=(form, constructor),
-                   )
-         We define a module named SecurityTest in the Product, which is initially just the following:
-           from Products.Transience.Transience import TransientObjectContainer
-           from Globals import HTMLFile, InitializeClass
-           from AccessControl import ClassSecurityInfo
-           class SecurityTest(TransientObjectContainer):
-               meta_type = 'Security Test'
-           constructSecurityTestForm = HTMLFile(
-               'dtml/addSecurityTest', globals())
-           def constructSecurityTest(self, id, title='', timeout_mins=20,
-               addNotification=None, delNotification=None, limit=0, REQUEST=None):
-               """ """
-               ob = SecurityTest(id, title, timeout_mins,
-                       addNotification, delNotification, limit=limit)
-               self._setObject(id, ob)
-               if REQUEST is not None:
-                   return self.manage_main(self, REQUEST, update_menu=1)
-         The HTMLFile instance is just a copy of the constructTransientObjectContainer form in the Transience product
-         modified with the right target to create a SecurityTest instance. Note that we don't run the SecurityTest
-         class through InitializeClass, nor do we allow it to make any of its own security declarations.
-         Then we fire up Zope, log in as the admin user and call the URL
-         http://localhost:8080/security_test/foo/getSubobjectLimit .
-         Note that we didn't declare any security assertions on the SecurityTest class and we didn't run the
-         SecurityTest class through InitializeClass, and we can still view the getSubobjectLimit method, which is
-         defined in the base class and protected by the 'View management screens' permission in the base class. So we
-         know we don't have to run InitializeClass on a subclass of a security-aware class which doesn't override any
-         of its superclass' methods.
-         Let's go override the getObjectLimit method in the SecurityTest subclass.
-           class SecurityTest(TransientObjectContainer):
-               meta_type = 'Security Test'
-               def getSubobjectLimit(self):
-                   """ """
-                   return 100
-         When calling the same URL, we find that we can still call the getSubobjectLimit method while logged in as the
-         admin user, even though we didn't give it any security declarations of its own (its security declaration was
-         inherited from the base class). So we know we don't need to declare security assertions on methods of classes
-         which inherit from base classes which have security assertions unless we want to change those assertions.
-         So now let's go modify the base class, declaring the getSubobjectLimit method private by changing the class:
-             #security.declareProtected(MGMT_SCREEN_PERM, 'getSubobjectLimit')
-             security.declarePrivate('getSubobjectLimit')
-             def getSubobjectLimit(self):
-                 """ """
-                 return self._limit
-         In either the case where we override the security declaration in the SecurityTest subclass or we remove the
-         method from the subclass, we are not able to access the method any longer via its URL. So we are really,
-         definitely, positively sure that we inherit security declarations from our base class.
-         Then let's make our own security declaration on the getSubobjectLimit method in the subclass, but we won't
-         run the class through InitializeClass:
-           class SecurityTest(TransientObjectContainer):
-               meta_type = 'Security Test'
-               security = ClassSecurityInfo()
-               security.declarePublic('getSubobjectLimit')
-               def getSubobjectLimit(self):
-                   """ """
-                   return 100
-         In the base class, the getSubobjectLimit method is still declared private. But we find that even though we
-         didn't run the SecurityTest class through InitializeClass, the getSubobjectLimit method is now accessible! This
-         leads us to believe that we needn't run InitializeClass on our subclass if one of its base classes has
-         already been run through InitializeClass. How this security declaration gets applied to our class, I don't
-         know. ;-) That's the job of InitializeClass, but it's apparently unnecessary in subclasses of classes that
-         are already run through InitializeClass.
-         Let's run the SecurityTest class through InitializeClass now:
-           class SecurityTest(TransientObjectContainer):
-               meta_type = 'Security Test'
-               security = ClassSecurityInfo()
-               security.declarePublic('getSubobectLimit')
-               def getSubobjectLimit(self):
-                   """ """
-                   return 100
-           InitializeClass(SecurityTest)
-         This works, of course, and the method is still public.
-         Now, lets go pare out our method declaration and our security assertions from our subclass, but we'll still
-         run the class through InitializeClass:
-           class SecurityTest(TransientObjectContainer):
-               meta_type = 'Security Test'
-           #    security = ClassSecurityInfo()
-           #    security.declarePublic('getSubobjectLimit')
-           #    def getSubobjectLimit(self):
-           #        """ """
-           #       return 100
-           InitializeClass(SecurityTest)
-         We also go back and change our TransientObjectContainer base class' security declarations back to standard:
-             security.declareProtected(MGMT_SCREEN_PERM, 'getSubobjectLimit')
-             #security.declarePrivate('getSubobjectLimit')
-             def getSubobjectLimit(self):
-                 """ """
-                 return self._limit
-         We find that we can still access getSubobjectLimit, which is what I would expect.
-         So, the (somewhat suprising) morals of the story are:
-           - you needn't use InitializeClass on classes which inherit
-             from a base class which has security assertions
-             and has itself been run through InitializeClass if
-             a) you don't add any methods to the subclass and b)
-             you're willing to accept the base class' security
-             assertions.  Not suprising.
-           - You needn't declare security assertions on overriding methods
-             of subclasses of security-aware base classes unless you want
-             to change those assertions.  Not suprising.
-           - It's always safe to run a class through InitializeClass even
-             if it does not have security declarations of its own.  Not
-             suprising.
-           - If you declare differing security assertions in your subclass,
-             you do not need to run the subclass through InitializeClass
-             for those security assertions to have an effect.  Why this
-             is the case is still somewhat a mystery.  Surprising.
-         I'm sort of stumped as to how the subclass' assertions are applied in the absence of InitializeClass! This is
-         not what I expected, I would have thought that differing assertions would only be applied if InitializeClass
-         was called on the subclass. There's some magic going on here that I don't understand.
-         But in a nutshell, if you don't want to think about any of this (and god knows I don't):
-          - declare security assertions for each method that you define,
-            even if there is an existing security declaration for
-            the method in a superclass.  It's always clear what the
-            intention of your code is then, and you won't piss off
-            any of your coworkers. ;-)
-          - always run your classes through InitializeClass
-         - C
-
-        % Anonymous User - July 20, 2002 8:43 pm:
-         Florent Guillaume clears things up:
-         > The magic is that Persistent has a __class_init__ that calls
-         > InitializeClass for you. (This attribute is actually set by
-         > App.PersistentExtra, called from Globals.)
-         This is why it's not necessary to run an inherited subclass through InitializeClass (if it inherits from
-         Persistent).
-
-        % mcdonc - Mar. 8, 2004 4:18 am:
-         From Collector issue 270:
-           I dont seem to be able to inherit security declarations for names beginning with "manage", see
-           the test product attached.  default__class_init (in App/class_init.py), ca. line 119 seems to hint
-           that names beginning with "manage" are treated differentlyIf this is intended behaviour I think it
-           should be documented in the DevGuide, under "Inheritance And Class Security Declarations" (is it
-           documented somewhere?)
-         It is now. ;-) If there is not a security assertion associated directly in the class in which they are
-         defined, methods that begin with "manage_" will automatically be protected with assertions that allow only
-         users with the 'Manager' role to call them.
-
-    Class Security Assertions In Non-Product Code (External Methods/Python Scripts)
-
-      Objects that are returned from Python Scripts or External
-      Methods need to have assertions declared for themselves before
-      they can be used in restricted code.  For example, assume you
-      have an External Method that returns instances of a custom
-      'Book' class. If you want to call this External Method from
-      DTML, and you'd like your DTML to be able to use the returned
-      'Book' instances, you will need to ensure that your class
-      supports Acquisition, and you'll need to make security
-      assertions on the 'Book' class and initialize it with the global
-      class initializer (just as you would with a class defined in a
-      Product). For example::
-
-        # an external method that returns Book instances
-
-        from AccessControl import ClassSecurityInfo
-        from Acquistion import Implicit
-        import Globals
-
-        class Book(Implicit):
-
-          def __init__(self, title):
-            self._title=title
-
-          # Create a SecurityInfo for this class
-          security = ClassSecurityInfo()
-          security.declareObjectPublic()
-
-          security.declarePublic('getTitle')
-          def getTitle(self):
-            return self._title
-
-        Globals.InitializeClass(Book)
-
-        # The actual external method
-        def GetBooks(self):
-          books=[]
-          books.append(Book('King Lear').__of__(self))
-          books.append(Book('Romeo and Juliet').__of__(self))
-          books.append(Book('The Tempest').__of__(self))
-          return books
-
-        % Anonymous User - Dec. 3, 2003 11:29 pm:
-         typo error in the above source code, line 3, missing 'i' for Acquisition:
-                                                                            ^
-           from Acquistion import Implicit
-                     ^
-
-      Note that we *wrap* the book instances by way of their __of__
-      methods to obtain a security context before returning them.
-
-        % slinkp - Sep. 19, 2005 1:17 pm:
-         This is important. If you do not wrap all your instances, all your security declarations are useless and
-         you'll get Unauthorized errors. I seem to
-         forget to do this periodically.
-         The alternative is to use allow_class() together with 
-         ModuleSecurityInfo().declarePublic() as described in a comment below,
-         under "Utility Functions For Allowing Import of Modules By Through The Web Code".
-         This is quick and expedient, but maybe gives you less control.
-
-      Note that this particular example is slightly dangerous.  You
-      need to be careful that classes defined in external methods not
-      be made persistent, as this can cause Zope object database
-      inconsistencies.  In terms of this example, this would mean that
-      you would need to be careful to not attach the Book object
-      returned from the 'GetBook' method to a persistent object within
-      the ZODB. See Chapter 4, "ZODB Persistent Components" for more
-      information.  Thus it's generally a good idea to define the Book
-      class in a Product if you want books to be persistent.  It's
-      also less confusing to have all of your security declarations in
-      Products.
-
-      However, one benefit of the 'SecurityInfo' approach is that it
-      is relatively easy to subclass and add security info to classes
-      that you did not write. For example, in an External Method, you
-      may want to return instances of 'Book' although 'Book' is
-      defined in another module out of your direct control. You can
-      still use 'SecurityInfo' to define security information for the
-      class by using::
-
-        # an external method that returns Book instances
-
-        from AccessControl import ClassSecurityInfo
-        from Acquisition import Implicit
-        import bookstuff
-        import Globals
-
-        class Book(Implicit, bookstuff.Book):
-          security = ClassSecurityInfo()
-          security.declareObjectPublic()
-          security.declarePublic('getTitle')
-
-        Globals.InitializeClass(Book)
-
-        # The actual external method
-        def GetBooks(self):
-          books=[]
-          books.append(Book('King Lear'))
-          books.append(Book('Romeo and Juliet'))
-          books.append(Book('The Tempest'))
-          return books
-
-  Module Security Assertions
-
-    Another kind of 'SecurityInfo' object you will use as a
-    component developer is the 'ModuleSecurityInfo' object.
-
-    'ModuleSecurityInfo' objects do for objects defined in modules
-    what 'ClassSecurityInfo' objects do for methods defined in
-    classes.  They allow module-level objects (generally functions) to
-    be protected by security assertions.  This is most useful when
-    attempting to allow through-the-web code to 'import' objects
-    defined in a Python module.
-
-    One major difference between 'ModuleSecurityInfo' objects and
-    ClassSecurityInfo objects is that 'ModuleSecurityInfo' objects
-    cannot be declared 'protected' by a permission.  Instead,
-    ModuleSecurityInfo objects may only declare that an object is
-    'public' or 'private'.  This is due to the fact that modules are
-    essentially "placeless", global things, while permission
-    protection depends heavily on "place" within Zope.
-
-    Declaring Module Security
-
-      In order to use a filesystem Python module from restricted code
-      such as Python Scripts, the module must have Zope security
-      declarations associated with functions within it.  There are a
-      number of ways to make these declarations:
-
-        - By embedding the security declarations in the target module.
-          A module that is written specifically for Zope may do so,
-          whereas a module not specifically written for Zope may
-          not be able to do so.
-
-        - By creating a wrapper module and embedding security
-          declarations within it.  In many cases it is difficult,
-          impossible, or simply undesirable to edit the target module.
-          If the number of objects in the module that you want to
-          protect or make public is small, you may wish to simply
-          create a wrapper module.  The wrapper module imports objects
-          from the wrapped module and provides security declarations
-          for them.
-
-        - By placing security declarations in a filesystem Product.
-          Filesystem Python code, such as the '__init__.py' of a
-          Product, can make security declarations on behalf of an
-          external module.  This is also known as an "external"
-          module security info declaration.
-
-      The 'ModuleSecurityInfo' class is defined in the 'AccessControl'
-      package of the Zope framework. 
-
-    Using ModuleSecurityInfo Objects
-
-      Instances of 'ModuleSecurityInfo' are used in two different
-      situations.  In embedded declarations, inside the module they
-      affect.  And in external declarations, made on behalf of a
-      module which may never be imported.
-
-    Embedded ModuleSecurityInfo Declarations
-
-      An embedded ModuleSecurityInfo declaration causes an object in its
-      module to be importable by through-the-web code.
-
-        % mcdonc - June 3, 2002 10:12 am:
-         Note that the code that calls ModuleSecurityInfo must be *run* at some point before these security
-         declarations will take effect. The easiest way to make sure that this happens is to put the declarations in
-         your Product's __init__.py.
-
-      Here's an example of an embedded declaration::
-
-        from AccessControl import ModuleSecurityInfo
-        modulesecurity = ModuleSecurityInfo()
-        modulesecurity.declarePublic('foo')
-
-        def foo():
-            return "hello"
-            # foo
-
-        modulesecurity.apply(globals())
-
-      When making embedded ModuleSecurityInfo declarations, you should
-      instantiate a ModuleSecurityInfo object and assign it to a name.
-      It's wise to use the recommended name 'modulesecurity' for
-      consistency's sake.  You may then use the modulesecurity
-      object's 'declarePublic' method to declare functions inside of
-      the current module as public.  Finally, appending the last line
-      ("modulesecurity.apply(globals())") is an important step.  It's
-      necessary in order to poke the security machinery into action.
-      The above example declares the 'foo' function public.
-
-      The name 'modulesecurity' is used for consistency and for the
-      benefit of new component authors, who often learn from looking
-      at other people's code.  You do not have to use the name
-      'modulesecurity' for the security infrastructure to recognize
-      your assertion information, but it is recommended as a
-      convention.
-
-    External ModuleSecurityInfo Declarations
-
-      By creating a ModuleSecurityInfo instance with a module name
-      argument, you can make declarations on behalf of a module
-      without having to edit or import the module.
-
-      Here's an example of an external declaration::
-
-         from AccessControl import ModuleSecurityInfo
-         # protect the 'foo' function within (yet-to-be-imported) 'foomodule'
-         ModuleSecurityInfo('foomodule').declarePublic('foo')
-
-      This declaration will cause the following code to work within
-      PythonScripts::
-
-         from foomodule import foo
-
-      When making external ModuleSecurityInfo declarations, you
-      needn't use the "modulesecurity.apply(globals())" idiom
-      demonstrated in the embedded declaration section above.  As a
-      result, you needn't assign the ModuleSecurityInfo object to the
-      name 'modulesecurity'.
-
-    Providing Access To A Module Contained In A Package
-
-      Note that if you want to provide access to a module inside of a
-      package which lives in your PYTHONPATH, you'll need to provide
-      security declarations for *all of the the packages and
-      sub-packages along the path used to access the module.*
-
-      For example, assume you have a function foo, which lives inside
-      a module named 'module', which lives inside a package named
-      'package2', which lives inside a package named 'package1' You
-      might declare the 'foo' function public via this chain of
-      declarations::
-
-        ModuleSecurityInfo('package1').declarePublic('package2')
-        ModuleSecurityInfo('package1.package2').declarePublic('module')
-        ModuleSecurityInfo('package1.package2.module').declarePublic('foo')
-
-      Note that in the code above we took 
-      the following steps:
-
-       - make a ModuleSecurityInfo object for 'package1'
-
-       - call the declarePublic method of the 'package1'
-         ModuleSecurityInfo object, specifying 'package2' as what
-         we're declaring public.  This allows through the web code to
-         "see" package2 inside package1.
-
-       - make a ModuleSecurityInfo object for 'package1.package2'.
-
-       - call the declarePublic method of the 'package1.package2'
-         ModuleSecurityInfo object, specifying 'module' as what we're
-         declaring public.  This allows through the web code to "see"
-         'package1.package2.module'.
-
-       - declare 'foo' public inside the ModuleSecurityInfo for
-         'package1.package2.module'. 
-
-       Through-the-web code may now perform an import ala: 'import
-       package1.package2.module.foo'
-
-       Beware that Zope is buggy from 2.3 to 2.5.0b3.  If you make
-       module security declarations in more than one Product, only one
-       of the Products' security assertions will actually take effect.
-       This is repaired in Zope 2.5.0 and beyond.
-
-       % anonymous user - Note also that from 2.5b4, you can
-        use
-        ModuleSecurityInfo('Products.Catalog').declarePublic('CatalogError')
-        You do not need multiple declarations to traverse packages
-        anymore.
-
-       Many people who use Zope will be concerned with using
-       ModuleSecurityInfo to make declarations on modules which live
-       within Zope's Products directory.  This is just an example of
-       declaring module security on a module within a package.  Here
-       is an example of using ModuleSecurityInfo to make security
-       declarations on behalf of the 'CatalogError' class in the
-       'ZCatalog.py' module.  This could be placed, for instance,
-       within the any Product's '__init__.py' module::
-
-        from AccessControl import ModuleSecurityInfo
-        ModuleSecurityInfo('Products').declarePublic('Catalog')
-        ModuleSecurityInfo('Products.Catalog').declarePublic('CatalogError')
-
-         % Anonymous User - Apr. 5, 2002 1:56 pm:
-          shouldn't it be ZCatalog, not Catalog?
-
-    Declaring Module Security On Modules Implemented In C
-
-      Certain modules, such as the standard Python 'sha' module,
-      provide extension types instead of classes, as the 'sha' module
-      is implemented in C. Security declarations typically cannot be
-      added to extension types, so the only way to use this sort of
-      module is to write a Python wrapper class, or use External
-      Methods.
-
-    Default Module Security Info Declarations
-
-      Through-the-web Python Scripts are by default able to import a
-      small number of Python modules for which there are security
-      declarations. These include 'string', 'math', and 'random'. The
-      only way to make other Python modules available for import is to
-      add security declarations to them in the filesystem.
-
-    Utility Functions For Allowing Import of Modules By Through The Web Code
-
-      Instead of manually providing security declarations for each
-      function in a module, the utility function "allow_class" and
-      "allow_module" have been created to help you declare the entire
-      contents of a class or module as public.
-
-      You can handle a module, such as base64, that contains only safe
-      functions by writing 'allow_module("module_name")'.  For
-      instance::
-
-        from Products.PythonScripts.Utility import allow_module
-        allow_module("base64")
-
-      This statement declares all functions in the 'base64' module
-      ( 'encode', 'decode', 'encodestring', and 'decodestring' ) as
-      public, and from a script you will now be able to perform an
-      import statement such as "from base64 import encodestring".
-
-        % slinkp - Sep. 19, 2005 1:06 pm:
-         allow_class(foo.Foo) allows you to import Foo in untrusted code, but
-         if the class doesn't have security declarations, you'll get Unauthorized errors
-         when you try to call methods on instances of Foo. You can avoid that by doing:
-         ModuleSecurityInfo('foo').declarePublic('Foo')
-         I find this very useful for simple record-type classes and things from third-party code that aren't worth the
-         effort to wrap in a full security-declared Zope product,
-         especially if it isn't convenient to ensure that my instances are acquisition-wrapped.
-
-      To allow access to only some names in a module, you can eschew
-      the allow_class and allow_module functions for the lessons you
-      learned in the previous section and do the protection
-      "manually"::
-
-        from AccessControl import ModuleSecurityInfo
-        ModuleSecurityInfo('module_name').declarePublic('name1','name2', ...)
-
-  Making Permission Assertions On A Constructor
-
-    When you develop a Python disk-based product, you will generally
-    be required to make "constructor" methods for the objects which
-    you wish to make accessible via the Zope management interface by
-    users of your Product.  These constructors are usually defined
-    within the modules which contain classes which are intended to be
-    turned into Zope instances.  For more information on how
-    constructors are used in Zope with security, see Chapter 3 "Zope
-    Products".
-
-    The Zope Product machinery "bootstraps" Product-based classes with
-    proper constructors into the namespace of the Zope management
-    interface "Add" list at Zope startup time.  This is done as a
-    consequence of registering a class by way of the Product's
-    '__init__.py' 'intialize' function.  If you want to make, for
-    example, the imaginary 'FooClass' in your Product available from
-    the "Add" list, you may construct an '__init__.py' file that looks
-    much like this::
-
-      from FooProduct import FooClass
-
-      def initialize(context):
-          """ Initialize classes in the FooProduct module """
-          context.registerClass(
-              FooProduct.FooClass, # the class object
-              permission='Add FooClasses',
-              constructors=(FooProduct.manage_addFooClassForm,
-                            FooProduct.manage_addFooClass),
-              icon='foo.gif'
-              )
-
-      % Anonymous User - Nov. 9, 2002 2:12 pm:
-       /imaginary FooClass in your Product/imaginary FooClass Product/
-       you mean the ZMI [Add list], not the products. Assume FooClass has no Add list. blf
-
-    The line of primary concern to us above is the one which says
-    "permission='Add FooClasses'".  This is a permission declaration
-    which, thanks to Zope product initialization, restricts the adding
-    of FooClasses to those users who have the 'Add FooClasses'
-    permission by way of a role association determined by the system
-    administrator.
-
-    If you do not include a 'permission' argument to 'registerClass',
-    then Zope will create a default permission named 'Add
-    [meta-type]s'.  So, for example, if your object had a meta_type of
-    'Animal', then Zope would create a default permission, 'Add
-    Animals'.  For the most part, it is much better to be explicit
-    then to rely on Zope to take care of security details for you, so
-    be sure to specify a permission for your object.
-
-  Designing For Security
-
-    "Security is hard." -- Jim Fulton.
-
-    When you're under a deadline, and you "just want it to work",
-    dealing with security can be difficult.  As a component developer,
-    following these basic guidelines will go a long way toward
-    avoiding problems with security integration. They also make a good
-    debugging checklist!
-
-      - Ensure that any class that needs to work with security has 
-        'Acquisition.Implicit' or 'Acquisition.Explicit' somewhere 
-        in its base class hierarchy.
-
-      - Design the interface to your objects around methods; don't
-        expect clients to access instance attributes directly.
-
-      - Ensure that all methods meant for use by restricted code 
-        have been protected with appropriate security assertions.
-
-      - Ensure that you called the global class initializer on 
-        all classes that need to work with security.
-
-  Compatibility
-
-    The implementation of the security assertions and 'SecurityInfo'
-    interfaces described in this document are available in Zope 2.3
-    and higher.
-
-    Older Zope Products do not use the 'SecurityInfo' interfaces for
-    security assertions, because these interfaces didn't exist at the
-    time.  These Zope products will continue to work without modification
-    until further notice.
-
-  Using The RoleManager Base Class With Your Zope Product
-
-    After your Product is deployed, system managers and other users of
-    your Product often must deal with security settings on instances
-    they make from your classes.
-
-    Product classes which inherit Zope's standard RoleManager base
-    class allow instances of the class to present a security
-    interface.  This security interface allows managers and developers
-    of a site to control an instance's security settings via the Zope
-    management interface.
-
-    The user interface is exposed via the *Security* management view.
-    From this view, a system administrator may secure instances of
-    your Product's class by associating roles with permissions and by
-    asserting that your object instance contains "local roles".  It
-    also allows them to create "user-defined roles" within the Zope
-    management framework in order to associate these roles with the
-    permissions of your product and with users.  This user interface
-    and its usage patterns are explained in more detail within the
-    Zope Book's security
-    chapter.
-
-      % Anonymous User - Nov. 9, 2002 2:20 pm:
-       More current: http://www.zope.org/Documentation/Books/ZopeBook/current/Security.stx
-       http://www.zope.org/Documentation/Books/ZopeBook/2_6Edition/Security.stx
-
-    If your Product's class does not inherit from 'RoleManager', its
-    methods will still retain the security assertions associated with
-    them, but you will be unable to allow users to associate roles
-    with the permissions you've defined respective to instances of
-    your class.  Your objects will also not allow local role
-    definitions.  Note that objects which inherit from the
-    'SimpleItem.SimpleItem' mixin class already inherit from
-    'RoleManager'.
-
-  Conclusion
-
-    Zope security is based upon roles and permissions. Users have
-    roles. Security policies map permissions to roles. Classes
-    protect methods with permissions. As a developer you main job is
-    to protect your classes by associating methods with
-    permissions. Of course there are many other details such as
-    protecting modules and functions, creating security user
-    interfaces, and initializing security settings.
-
-      % Anonymous User - Jan. 4, 2002 4:14 pm - This from Dieter Maurer --    The basic security mechanism uses the attribute "m__roles__" in order  to protect "m". If this attribute it "None", then "m" is public.  Otherwise, it is expected to be a sequence of roles that are allowed  to use "m".    But, "ExtensionsClass" brings with it computed attributes. This allows  "m__roles__" to be not a sequence but a method returning a sequence.  When you protect "m" with a permission "p", then  "m__roles__" is set to "PermissionRole(p)". This instance dynamically  evaluates into a sequence of roles by crawling up the "aq_container"  (which is correctly "aq_parent" after "aq_inner") chain and translating  "p" into roles by interpreting the "permission-to-role" mapping  it finds on its way to the application object.    Therefore, "declarePublic" works for non-wrapped instances while  "declareProtected" requires the wrapping.
-
-      % Anonymous User - May 3, 2002 4:47 am:
-       From Julian Munoz -- I don't find any reference to security and object properties.
-
-      % d.maurer - Aug. 22, 2002 4:04 am:
-       I would like to learn details about __guarded_getattr__,
-       __guarded_setattr__ and friends.
-       What is their semantics?
-       Are they expected to do their own security checks (I
-       expect a "yes" to this question)?
-       Is it usually safe to implement "__guarded_getattr__"
-       by:
-         result= getattr(self,key)
-         if not getSecurityManager().validate(accessed=self,
-                                              name=key,
-                                              value= result)
-           raise 'Unauthorized', attr
-         return result
-
-      % d.maurer - Aug. 22, 2002 4:29 am:
-       I would like to learn about the details of
-       "validate", at least for the ZopeSecurityPolicy.
-       What precisely are "accessed" and "container".
-       "ZopeSecurityPolicy.validate" contains several
-       mysterious instances of
-               if accessedbase is containerbase:
-                  raise Unauthorized
-       What is the purpose for this. I cannot understand
-       the accompanying comment.
-       Why does it not "return 0" but raises "Unauthorizred"?
-       What about a succint semantics for
-       "ZopeSecurityPolicy.validate". It should describe
-       when the function returns "1", "0" and raises an
-       exception.

Copied: zdgbook/trunk/source/Security.rst (from rev 96659, zdgbook/trunk/Security.stx)
===================================================================
--- zdgbook/trunk/source/Security.rst	                        (rev 0)
+++ zdgbook/trunk/source/Security.rst	2009-02-18 03:02:05 UTC (rev 96661)
@@ -0,0 +1,1300 @@
+########
+Security
+########
+
+Introduction
+============
+
+A typical web application needs to be securely managed.  Different
+types of users need different kinds of access to the components that
+make up an application. To this end, Zope includes a comprehensive
+set of security features.  This chapter's goal is to shed light on
+Zope security in the context of Zope Product development.  For a more
+fundamental overview of Zope security, you may wish to refer to the
+*Zope Book*, Chapter 6, Users and Security.  Before diving into this
+chapter, you should have a basic understanding of how to build Zope
+Products as well as an understanding of how the Zope object publisher
+works. These topics are covered in Chapter 2 and Chapter 3,
+respectively.
+
+
+Security Architecture
+=====================
+
+The Zope security architecture is built around a *security policy*,
+which you can think of as the "access control philosophy" of
+Zope. This policy arbitrates the decisions Zope makes about whether
+to allow or deny access to any particular object defined within the
+system.
+
+How The Security Policy Relates to Zope's Publishing Machinery
+--------------------------------------------------------------
+
+When access to Zope is performed via HTTP, WebDAV, or FTP, Zope's
+publishing machinery consults the security policy in order to
+determine whether to allow or deny access to a visitor for a
+particular object.  For example, when a user visits the root
+'index_html' object of your site via HTTP, the security policy is
+consulted by 'ZPublisher' to determine whether the user has
+permission to view the 'index_html' object itself.  For more
+information on this topic, see Chapter 3, "Object Publishing".
+
+The Zope security policy is consulted when an object is accessed the
+publishing machinery, for example when a web request is submitted.
+
+
+How The Security Policy Relates to Restricted Code
+--------------------------------------------------
+
+*Restricted code* is generally any sort of logic that may be edited
+remotely (through the Web, FTP, via WebDAV or by other means). DTML
+Methods, SQLMethods, Python Scripts and Perl Scripts are examples of
+restricted code.
+
+When restricted code runs, any access to objects integrated with Zope
+security is arbitrated by the security policy. For example if you
+write a bit of restricted code with a line that attempts to
+manipulate an object you don't have sufficient permission to use, the
+security policy will deny you access to the object.  This generally
+is accomplished by raising an 'Unauthorized' exception, which is a
+Python string exception caught by a User Folder which signifies that
+Zope should attempt to get user credentials before obeying the
+request.  The particular code used to attempt to obtain the
+credentials is determined by the User Folder "closest" (folder-wise)
+to the object being accessed.
+
+The Zope security policy is consulted when an object is accessed by
+restricted code.
+
+'Unauthorized' Exceptions and Through-The-Web Code
+--------------------------------------------------
+
+The security policy infrastructure will raise an 'Unauthorized'
+exception automatically when access to an object is denied.  When an
+'Unauthorized' exception is raised within Zope, it is handled in a
+sane way by Zope, generally by having the User Folder prompt the user
+for login information.  Using this functionality, it's possible to
+protect Zope objects through access control, only prompting the user
+for authentication when it is necessary to perform an action which
+requires privilege.
+
+An example of this behavior can be witnessed within the Zope
+Management interface itself.  The management interface prompts you to
+log in when visiting, for example, the '/manage' method of any Zope
+object.  This is due to the fact that an anonymous user does not
+generally possess the proper credentials to use the management
+interface.  If you're using Zope in the default configuration with
+the default User Folder, it prompts you to provide login information
+via an HTTP basic authentication dialog.
+
+How The Security Policy Relates To Unrestricted Code
+----------------------------------------------------
+
+There are also types of *unrestricted code* in Zope, where the logic
+is not constrained by the security policy. Examples of unrestricted
+code are the methods of Python classes that implement the objects in
+Python file-based add-on components.  Another example of unrestricted
+code can be found in External Method objects, which are defined in
+files on the filesystem.  These sorts of code are allowed to run
+"unrestricted" because access to the file system is required to
+define such logic.  Zope assumes that code defined on the filesystem
+is "trusted", while code defined "through the web" is not.  All
+filesystem-based code in Zope is unrestricted code.
+
+We'll see later that while the security policy does not constrain
+what your unrestricted code does, it can and should be used to
+control the ability to *call* your unrestricted code from within a
+restricted-code environment.
+
+The Zope security policy is *not* consulted when unrestricted code is
+run.
+
+Details Of The Default Zope Security Policy
+-------------------------------------------
+
+In short, the default Zope security policy ensures the following:
+
+- access to an object which does not have any associated security
+  information is always denied.
+
+- if an object is associated with a permission, access is granted or
+  denied based on the user's roles.  If a user has a role which has
+  been granted the permission in question, access is granted.  If the
+  user does not possess a role that has been granted the permission
+  in question, access is denied.
+
+- if the object has a security assertion declaring it *public* , then
+  access will be granted.
+
+- if the object has a security assertion declaring it *private*, then
+  access will be denied.
+
+- accesses to objects that have names beginning with the underscore
+  character '_' are always denied.
+
+As we delve further into Zope security within this chapter, we'll see
+exactly what it means to associate security information with an
+object.
+
+
+Overview Of Using Zope Security Within Your Product
+---------------------------------------------------
+
+Of course, now that we know what the Zope security policy is, we need
+to know how our Product can make use of it.  Zope developers leverage
+the Zope security policy primarily by making security declarations
+related to methods and objects within their Products.  Using security
+assertions, developers may deny or allow all types of access to a
+particular object or method unilaterally, or they may protect access
+to Zope objects more granularly by using permissions to grant or deny
+access based on the roles of the requesting user to the same objects
+or methods.
+
+
+For a more fundamental overview of Zope users, roles, and
+permissions, see the section titled "Authorization and Managing
+Security" in the Security Chapter of the *Zope Book*.
+
+Security Declarations In Zope Products
+--------------------------------------
+
+Zope security declarations allow developers to make security
+assertions about a Product-defined object and its methods.
+Security declarations come in three basic forms.  These are:
+
+- public -- allow anybody to access the protected object
+  or method
+
+- private -- deny anyone access to the protected object or
+  method
+
+- protected -- protect access to the object or method via a
+  permission
+
+We'll see how to actually "spell" these security assertions a
+little later in this chapter.  In the meantime, just know that
+security declarations are fundamental to Zope Product security,
+and they can be used to protect access to an object by
+associating it with a permission.  We will refer to security
+declarations as "declarations" and "assertions" interchangeably
+within this chapter.
+
+
+Permissions In Zope Products
+============================
+
+A permission is the smallest unit of access to an object in Zope,
+roughly equivalent to the atomic permissions on files seen in Windows
+NT or UNIX: R (Read), W(Write), X(Execute), etc. However, unlike
+these types of mnemonic permissions shared by all sorts of different
+file types in an operating system product, in Zope, a permission
+usually describes a fine-grained logical operation which takes place
+upon an object, such as "View Management Screens" or "Add
+Properties".
+
+Zope administrators associate these permissions with *roles*, which
+they grant to Zope users.  Thus, declaring a protection assertion on
+a method of "View management screens" ensures that only users who
+possess roles which have been granted the "View management screens"
+permission are able to perform the action that the method defines.
+
+It is important to note that Zope's security architecture dictates
+that roles and users remain the domain of administrators, while
+permissions remain the domain of developers.  Developers of Products
+should not attempt to define roles or users, although they may (and
+usually must) define permissions.  Most importantly, a Zope
+administrator who makes use of your product should have the "last
+word" as regards which roles are granted which permissions, allowing
+her to protect her site in a manner that fits her business goals.
+
+Permission names are strings, and these strings are currently
+arbitrary.  There is no permission hierarchy, or list of "approved
+permissions".  Developers are encouraged to reuse Zope core
+permissions (e.g. "View", "Access contents information") when
+appropriate, or they may create their own as the need arises.  It is
+generally wise to reuse existing Zope permission names unless you
+specifically need to define your own.  For a list of existing Zope
+core permissions, see Appendix A, "Zope Core Permissions".
+
+Permissions are often tied to method declarations in Zope.  Any
+number of method declarations may share the same permission.  It's
+useful to declare the same permission on a set of methods which can
+logically be grouped together.  For example, two methods which return
+management forms for the object can be provided with the same
+permission, "View management screens".  Likewise, two entirely
+different objects can share a permission name to denote that the
+operation that's being protected is fundamentally similar.  For
+instance, most Product-defined objects reuse the Zope "View"
+permission, because most Zope objects need to be viewed in a web
+browser.  If you create an addable Zope class named 'MyObject', it
+doesn't make much sense to create a permission "View MyObject",
+because the generic "View" permission may be reused for this action.
+
+There is an exception to the "developers should not try to define
+roles" rule inasmuch as Zope allows developers to assign "default
+roles" to a permission.  This is primarily for the convenience of the
+Zope administrator, as default roles for a permission cause the Zope
+security machinery to provide a permission to a role *by default*
+when instances of a Product class are encountered during security
+operations.  For example, if your Product defines a permission "Add
+Poll Objects", this permission may be associated with a set of
+default roles, perhaps "Manager".  Default roles in Products should
+not be used against roles other than "Manager", "Anonymous", "Owner",
+and "Authenticated" (the four default Zope roles), as other roles are
+not guaranteed to exist in every Zope installation.
+
+Using security assertions in Zope is roughly analogous to assigning
+permission bit settings and ownership information to files in a UNIX
+or Windows filesystem.  Protecting objects via permissions allows
+developers and administrators to secure Zope objects independently of
+statements made in application code.
+
+Implementing Security In Python Products
+========================================
+
+Security Assertions
+-------------------
+
+You may make several kinds of security assertions at the Python
+level.  You do this to declare accessibility of methods and
+subobjects of your classes. Three of the most common assertions that
+you'll want to make on your objects are:
+
+- this object is **public** (always accessible)
+
+- this object is **private** (not accessible by restricted code or by
+  URL traversal)
+
+- this object is **protected** by a specific permission
+
+There are a few other kinds of security assertions that are 
+much less frequently used but may be needed in some cases:
+
+- asserting that access to subobjects that do not have explicit
+  security information should be allowed rather than denied.
+
+- asserting what sort of protection should be used when determining
+  access to an *object itself* rather than a particular method of the
+  object
+
+It is important to understand that security assertions made in your
+Product code *do not* limit the ability of the code that the
+assertion protects.  Assertions only protect *access to this code*.
+The code which constitutes the body of a protected, private, or
+public method of a class defined in a Zope disk-based Product runs
+completely unrestricted, and is not subject to security constraints
+of any kind within Zope.  An exception to this rule occurs when
+disk-based-Product code calls a "through the web" method such as a
+Python Script or a DTML Method.  In this case, the security
+constraints imposed by these objects respective to the current
+request are obeyed.
+
+When Should I Use Security Assertions?
+--------------------------------------
+
+If you are building an object that will be used from DTML or other
+restricted code, or that will be accessible directly through the web
+(or other remote protocols such as FTP or WebDAV) then you need to
+define security information for your object.
+
+Making Security Assertions
+--------------------------
+
+As a Python developer, you make security assertions in your Python
+classes using 'SecurityInfo' objects. A 'SecurityInfo' object
+provides the interface for making security assertions about an object
+in Zope.
+
+The convention of placing security declarations inside Python code
+may at first seem a little strange if you're used to "plain old
+Python" which has no notion at all of security declarations.  But
+because Zope provides the ability to make these security assertions
+at such a low level, the feature is ubiquitous throughout Zope,
+making it easy to make these declarations once in your code, usable
+site-wide without much effort.
+
+Class Security Assertions
+=========================
+
+The most common kind of 'SecurityInfo' you will use as a component
+developer is the 'ClassSecurityInfo' object.  You use
+'ClassSecurityInfo' objects to make security assertions about methods
+on your classes.
+
+Classes that need security assertions are any classes that define
+methods that can be called "through the web".  This means any methods
+that can be called directly with URL traversal, from DTML Methods, or
+from Python-based Script objects.
+
+Declaring Class Security
+------------------------
+
+When writing the classes in your product, you create a
+'ClassSecurityInfo' instance *within each class that needs to play
+with the security model*. You then use the 'ClassSecurityInfo' object
+to make assertions about your class, its subobjects and its methods.
+
+The 'ClassSecurityInfo' class is defined in the 'AccessControl'
+package of the Zope framework. To declare class security information
+create a 'ClassSecurityInfo' class attribute named 'security'.  The
+name 'security' is used for consistency and for the benefit of new
+component authors, who often learn from looking at other people's
+code. You do not have to use the name 'security' for the security
+infrastructure to recognize your assertion information, but it is
+recommended as a convention.  For example::
+
+  from AccessControl import ClassSecurityInfo
+
+  class Mailbox(ObjectManager):
+    """A mailbox object that contains mail message objects."""
+
+    # Create a SecurityInfo for this class. We will use this 
+    # in the rest of our class definition to make security 
+    # assertions.
+    security = ClassSecurityInfo()
+
+    # Here is an example of a security assertion. We are 
+    # declaring that access to messageCount is public.
+    security.declarePublic('messageCount')
+
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+
+Note that in the example above we called the 'declarePublic' method
+of the 'ClassSecurityInfo' instance to declare that access to the
+'messageCount' method be public. To make security assertions for your
+object, you just call the appropriate methods of the
+'ClassSecurityInfo' object, passing the appropriate information for
+the assertion you are making.
+
+'ClassSecurityInfo' approach has a number of benefits. A major
+benefit is that it is very explicit, it allows your security
+assertions to appear in your code near the objects they protect,
+which makes it easier to assess the state of protection of your code
+at a glance. The 'ClassSecurityInfo' interface also allows you as a
+component developer to ignore the implementation details in the
+security infrastructure and protects you from future changes in those
+implementation details.
+
+Let's expand on the example above and see how to make the most common
+security assertions using the 'SecurityInfo' interface.
+
+To assert that a method is *public* (anyone may call it) you may call
+the 'declarePublic' method of the 'SecurityInfo' object, passing the
+name of the method or subobject that you are making the assertion
+on::
+
+  security.declarePublic(methodName)
+
+To assert that a method is *private* you call the 'declarePrivate'
+method of the 'SecurityInfo' object, passing the name of the method
+or subobject that you are making the assertion on::
+
+  security.declarePrivate(methodName)
+
+To assert that a method or subobject is *protected* by a particular
+permission, you call the 'declareProtected' method of the
+'SecurityInfo' object, passing a permission name and the name of a
+method to be protected by that permission::
+
+  security.declareProtected(permissionName, methodName)
+
+If you have lots of methods you want to protect under the same
+permission, you can pass as many methodNames ase you want::
+
+  security.declareProtected(permissionName, methodName1,
+  methodName2, methodName3, ...)
+
+Passing multiple names like this works for all of the 'declare'
+security methods ('declarePublic', 'declarePrivate', and
+'declareProtected').
+
+Deciding To Use 'declareProtected' vs. 'declarePublic' or 'declarePrivate'
+--------------------------------------------------------------------------
+
+      If the method you're making the security declaration against is
+      innocuous, and you're confident that its execution will not
+      disclose private information nor make inappropriate changes to
+      system state, you should declare the method public.
+
+      If a method should never be run under any circumstances via
+      traversal or via through-the-web code, the method should be
+      declared private.  This is the default if a method has no
+      security assertion, so you needn't explicitly protect
+      unprotected methods unless you've used 'setDefaultAccess' to set
+      the object's default access policy to 'allow' (detailed in
+      *Other Assertions*, below).
+
+      If the method should only be executable by a certain class of
+      users, you should declare the method protected.
+
+A Class Security Example
+------------------------
+
+Let's look at an expanded version of our 'Mailbox' example that makes
+use of each of these types of security assertions::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+  # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declareProtected('View management screens', 'manage')
+    manage=HTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    # protect 'listMessages' with the 'View Mailbox' permission
+    security.declareProtected('View Mailbox', 'listMessages')
+
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.declarePrivate('getMessages')
+    def getMessages(self):
+      self._messages=GoGetEm()
+      return self._messages
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+Note the last line in the example.  In order for security assertions
+to be correctly applied to your class, you must call the global class
+initializer ('Globals.InitializeClass') for all classes that have
+security information. This is very important - the global initializer
+does the "dirty work" required to ensure that your object is
+protected correctly based on the security assertions that you have
+made. If you don't run it on the classes that you've protected with
+security assertions, the security assertions will not be effective.
+
+Deciding Permission Names For Protected Methods
+-----------------------------------------------
+
+When possible, you should make use of an existing Zope permission
+within a 'declareProtected' assertion.  A list of the permissions
+which are available in a default Zope installation is available
+within Appendix A.  When it's not possible to reuse an existing
+permission, you should choose a permission name which is a verb or a
+verb phrase.
+
+Object Assertions
+-----------------
+
+Often you will also want to make a security assertion on the *object
+itself*. This is important for cases where your objects may be
+accessed in a restricted environment such as DTML. Consider the
+example DTML code::
+
+  <dtml-var expr="some_method(someObject)">
+
+Here we are trying to call 'some_method', passing the object
+'someObject'. When this is evaluated in the restricted DTML
+environment, the security policy will attempt to validate access to
+both 'some_method' and 'someObject'. We've seen how to make
+assertions on methods - but in the case of 'someObject' we are not
+trying to access any particular method, but rather the *object
+itself* (to pass it to 'some_method'). Because the security machinery
+will try to validate access to 'someObject', we need a way to let the
+security machinery know how to handle access to the object itself in
+addition to protecting its methods.
+
+To make security assertions that apply to the *object itself* you
+call methods on the 'SecurityInfo' object that are analogous to the
+three that we have already seen::
+
+  security.declareObjectPublic()
+
+  security.declareObjectPrivate()
+
+  security.declareObjectProtected(permissionName)
+
+The meaning of these methods is the same as for the method variety,
+except that the assertion is made on the object itself.
+
+An Object Assertion Example
+---------------------------
+
+Here is the updated 'Mailbox' example, with the addition of a
+security assertion that protects access to the object itself with the
+'View Mailbox' permission::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View Mailbox')
+
+    security.declareProtected('View management screens', 'manage')
+    manage=HTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    # protect 'listMessages' with the 'View Mailbox' permission
+    security.declareProtected('View Mailbox', 'listMessages')
+
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.declarePrivate('getMessages')
+    def getMessages(self):
+      self._messages=GoGetEm()
+      return self._messages
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+Other Assertions
+----------------
+
+The SecurityInfo interface also supports the less common
+security assertions noted earlier in this document.
+
+To assert that access to subobjects that do not have explicit
+security information should be *allowed* rather than *denied* by
+the security policy, use::
+
+  security.setDefaultAccess("allow")
+
+This assertion should be used with caution. It will effectively
+change the access policy to "allow-by-default" for all
+attributes in your object instance (not just class attributes)
+that are not protected by explicit assertions.  By default, the
+Zope security policy flatly denies access to attributes and
+methods which are not mentioned within a security assertion.
+Setting the default access of an object to "allow" effectively
+reverses this policy, allowing access to all attributes and
+methods which are not explicitly protected by a security
+assertion.
+
+'setDefaultAccess' applies to attributes that are simple Python
+types as well as methods without explicit protection. This is
+important because some mutable Python types (lists, dicts) can
+then be modified by restricted code. Setting default access to
+"allow" also affects attributes that may be defined by the base
+classes of your class, which can lead to security holes if you
+are not sure that the attributes of your base classes are safe
+to access.
+
+Setting the default access to "allow" should only be done if you
+are sure that all of the attributes of your object are safe to
+access, since the current architecture does not support using
+explicit security assertions on non-method attributes.
+
+What Happens When You Make A Mistake Making 'SecurityInfo' Declarations?
+------------------------------------------------------------------------
+
+It's possible that you will make a mistake when making 'SecurityInfo'
+declarations.  For example, it is not legal to declare two
+conflicting permissions on a method::
+
+  class Foo(SimpleItem):
+      security = ClassSecurityInfo()
+
+      meta_type='Foo'
+
+      security.declareProtected('View foos', 'index_html')
+      def index_html(self):
+          """ make index_html web-publishable """
+          return "<html><body>hi!</body></html>"
+
+security.declareProtected('View', 'index_html')
+# whoops, declared a conflicting permission on index_html!
+
+When you make a mistake like this, the security machinery will
+accept the *first* declaration made in the code and will write
+an error to the Zope debug log upon encountering the second and
+following conflicting declarations during class initialization.
+It's similarly illegal to declare a method both private and
+public, or to declare a method both private and protected, or to
+declare a method both public and protected. A similar error will
+be raised in all of these cases.
+
+Note that Zope *will not* warn you if you misspell the name of
+a method in a declareProtected, declarePublic, or declarePrivate
+assertion.  For instance, you try to protect the 'index_html'
+method with the 'View' permission and make a mistake,
+spelling the name 'index_html' as 'inde_html', like so::
+
+  security.declareProtected('View', 'inde_html')
+  # whoops, declared a permission assertion for 'inde_html'
+  # when I really wanted it to be 'index_html'!
+  def index_html(self):
+      """ make index_html web-publishable """
+      return "<html><body>hi!</body></html>"
+
+You'll need to track down these kinds of problems yourself.
+
+Setting Default Roles For Permissions
+-------------------------------------
+
+When defining operations that are protected by permissions, one thing
+you commonly want to do is to arrange for certain roles to be
+associated with a particular permission *by default* for instances of
+your object.
+
+For example, say you are creating a *News Item* object. You want
+'Anonymous' users to have the ability to view news items by default;
+you don't want the site manager to have to explicitly change the
+security settings for each *News Item* just to give the 'Anonymous"
+role 'View' permission.
+
+What you want as a programmer is a way to specify that certain roles
+should have certain permissions by default on instances of your
+object, so that your objects have sensible and useful security
+settings at the time they are created. Site managers can always
+*change* those settings if they need to, but you can make life easier
+for the site manager by setting up defaults that cover the common
+case by default.
+
+As we saw earlier, the 'SecurityInfo' interface provided a way to
+associate methods with permissions. It also provides a way to
+associate a permission with a set of default roles that should have
+that permission on instances of your object.
+
+To associate a permission with one or more roles, use the following::
+
+  security.setPermissionDefault(permissionName, rolesList)
+
+The *permissionName* argument should be the name of a permission that
+you have used in your object and *rolesList* should be a sequence
+(tuple or list) of role names that should be associated with
+*permissionName* by default on instances of your object.
+
+Note that it is not always necessary to use this method. All
+permissions for which you did not set defaults using
+'setPermissionDefault' are assumed to have a single default role of
+'Manager'.  Notable exceptions to this rule include 'View' and
+'Access contents information', which always have the default roles
+'Manager' and 'Anonymous'.
+
+The 'setPermissionDefault' method of the 'SecurityInfo' object should
+be called only once for any given permission name.
+
+
+An Example of Associating Default Roles With Permissions
+--------------------------------------------------------
+
+Here is our 'Mailbox' example, updated to associate the 'View
+Mailbox' permission with the roles 'Manager' and 'Mailbox Owner' by
+default::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View Mailbox')
+
+    security.declareProtected('View management screens', 'manage')
+    manage=DTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    security.declareProtected('View Mailbox', 'listMessages')
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+What Happens When You Make A Mistake Declaring Default Roles?
+-------------------------------------------------------------
+
+It's possible that you will make a mistake when making default roles
+declarations.  For example, it is not legal to declare two
+conflicting default roles for a permission::
+
+  class Foo(SimpleItem):
+      security = ClassSecurityInfo()
+
+      meta_type='Foo'
+
+      security.declareProtected('View foos', 'index_html')
+      def index_html(self):
+          """ """
+          return "<html><body>hi!</body></html>"
+
+      security.setPermissionDefault('View foos', ('Manager',))
+
+      security.setPermissionDefault('View foos', ('Anonymous',))
+      # whoops, conflicting permission defaults!
+
+When you make a mistake like this, the security machinery will accept
+the *first* declaration made in the code and will write an error to
+the Zope debug log about the second and following conflicting
+declarations upon class initialization.
+
+What Can (And Cannot) Be Protected By Class Security Info?
+----------------------------------------------------------
+
+It is important to note what can and cannot be protected using the
+'ClassSecurityInfo' interface. First, the security policy relies on
+*Acquisition* to aggregate access control information, so any class
+that needs to work in the security policy must have either
+'Acquisition.Implicit' or 'Acquisition.Explicit' in its base class
+hierarchy.
+
+The current security policy supports protection of methods and
+protection of subobjects that are instances. It does *not* currently
+support protection of simple attributes of basic Python types
+(strings, ints, lists, dictionaries). For instance::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  # We subclass ObjectManager, which has Acquisition in its
+  # base class hierarchy, so we can use SecurityInfo.
+
+  class MyClass(ObjectManager):
+    """example class"""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View')
+
+    # This is ok, because subObject is an instance
+    security.declareProtected('View management screens', 'subObject')
+    subObject=MySubObject()
+
+    # This is ok, because sayHello is a method
+    security.declarePublic('sayHello')
+    def sayHello(self):
+      """Return a greeting."""
+      return "hello!"
+
+    # This will not work, because foobar is not a method
+    # or an instance - it is a standard Python type
+    security.declarePublic('foobar')
+    foobar='some string'
+
+Keep this in mind when designing your classes. If you need simple
+attributes of your objects to be accessible (say via DTML), then you
+need to use the 'setDefaultAccess' method of 'SecurityInfo' in your
+class to allow this (see the note above about the security
+implications of this). In general, it is always best to expose the
+functionality of your objects through methods rather than exposing
+attributes directly.
+
+Note also that the actual 'ClassSecurityInfo' instance you use to
+make security assertions is implemented such that it is *never*
+accessible from restricted code or through the Web (no action on the
+part of the programmer is required to protect it).
+
+Inheritance And Class Security Declarations
+-------------------------------------------
+
+Python inheritance can prove confusing in the face of security
+declarations.
+
+If a base class which has already been run through "InitializeClass"
+is inherited by a superclass, nothing special needs to be done to
+protect the base class' methods within the superclass unless you wish
+to modify the declarations made in the base class.  The security
+declarations "filter down" into the superclass.
+
+On the other hand, if a base class hasn't been run through the global
+class initializer ('InitializeClass'), you need to proxy its security
+declarations in the superclass if you wish to access any of its
+methods within through-the-web code or via URL traversal.
+
+In other words, security declarations that you make using
+'ClassSecurityInfo' objects effect instances of the class upon which
+you make the declaration. You only need to make security declarations
+for the methods and subobjects that your class actually *defines*. If
+your class inherits from other classes, the methods of the base
+classes are protected by the security declarations made in the base
+classes themselves. The only time you would need to make a security
+declaration about an object defined by a base class is if you needed
+to *redefine* the security information in a base class for instances
+of your own class. An example below redefines a security assertion in
+a subclass::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class MailboxBase(ObjectManager):
+    """A mailbox base class."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declareProtected('View Mailbox', 'listMessages')
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
+
+  Globals.InitializeClass(MailboxBase)
+
+  class MyMailbox(MailboxBase):
+    """A mailbox subclass, where we want the security for 
+      listMessages to be public instead of protected (as 
+      defined in the base class)."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declarePublic('listMessages')
+
+  Globals.InitializeClass(MyMailbox)
+
+Class Security Assertions In Non-Product Code (External Methods/Python Scripts)
+-------------------------------------------------------------------------------
+
+Objects that are returned from Python Scripts or External Methods
+need to have assertions declared for themselves before they can be
+used in restricted code.  For example, assume you have an External
+Method that returns instances of a custom 'Book' class. If you want
+to call this External Method from DTML, and you'd like your DTML to
+be able to use the returned 'Book' instances, you will need to ensure
+that your class supports Acquisition, and you'll need to make
+security assertions on the 'Book' class and initialize it with the
+global class initializer (just as you would with a class defined in a
+Product). For example::
+
+  # an external method that returns Book instances
+
+  from AccessControl import ClassSecurityInfo
+  from Acquisition import Implicit
+  import Globals
+
+  class Book(Implicit):
+
+    def __init__(self, title):
+      self._title=title
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+    security.declareObjectPublic()
+
+    security.declarePublic('getTitle')
+    def getTitle(self):
+      return self._title
+
+  Globals.InitializeClass(Book)
+
+  # The actual external method
+  def GetBooks(self):
+    books=[]
+    books.append(Book('King Lear').__of__(self))
+    books.append(Book('Romeo and Juliet').__of__(self))
+    books.append(Book('The Tempest').__of__(self))
+    return books
+
+Note that we *wrap* the book instances by way of their __of__ methods
+to obtain a security context before returning them.
+
+Note that this particular example is slightly dangerous.  You need to
+be careful that classes defined in external methods not be made
+persistent, as this can cause Zope object database inconsistencies.
+In terms of this example, this would mean that you would need to be
+careful to not attach the Book object returned from the 'GetBook'
+method to a persistent object within the ZODB. See Chapter 4, "ZODB
+Persistent Components" for more information.  Thus it's generally a
+good idea to define the Book class in a Product if you want books to
+be persistent.  It's also less confusing to have all of your security
+declarations in Products.
+
+However, one benefit of the 'SecurityInfo' approach is that it is
+relatively easy to subclass and add security info to classes that you
+did not write. For example, in an External Method, you may want to
+return instances of 'Book' although 'Book' is defined in another
+module out of your direct control. You can still use 'SecurityInfo'
+to define security information for the class by using::
+
+  # an external method that returns Book instances
+
+  from AccessControl import ClassSecurityInfo
+  from Acquisition import Implicit
+  import bookstuff
+  import Globals
+
+  class Book(Implicit, bookstuff.Book):
+    security = ClassSecurityInfo()
+    security.declareObjectPublic()
+    security.declarePublic('getTitle')
+
+  Globals.InitializeClass(Book)
+
+  # The actual external method
+  def GetBooks(self):
+    books=[]
+    books.append(Book('King Lear'))
+    books.append(Book('Romeo and Juliet'))
+    books.append(Book('The Tempest'))
+    return books
+
+Module Security Assertions
+==========================
+
+Another kind of 'SecurityInfo' object you will use as a
+component developer is the 'ModuleSecurityInfo' object.
+
+'ModuleSecurityInfo' objects do for objects defined in modules
+what 'ClassSecurityInfo' objects do for methods defined in
+classes.  They allow module-level objects (generally functions) to
+be protected by security assertions.  This is most useful when
+attempting to allow through-the-web code to 'import' objects
+defined in a Python module.
+
+One major difference between 'ModuleSecurityInfo' objects and
+ClassSecurityInfo objects is that 'ModuleSecurityInfo' objects
+cannot be declared 'protected' by a permission.  Instead,
+ModuleSecurityInfo objects may only declare that an object is
+'public' or 'private'.  This is due to the fact that modules are
+essentially "placeless", global things, while permission
+protection depends heavily on "place" within Zope.
+
+Declaring Module Security
+-------------------------
+
+In order to use a filesystem Python module from restricted code such
+as Python Scripts, the module must have Zope security declarations
+associated with functions within it.  There are a number of ways to
+make these declarations:
+
+- By embedding the security declarations in the target module.  A
+  module that is written specifically for Zope may do so, whereas a
+  module not specifically written for Zope may not be able to do so.
+
+- By creating a wrapper module and embedding security declarations
+  within it.  In many cases it is difficult, impossible, or simply
+  undesirable to edit the target module.  If the number of objects in
+  the module that you want to protect or make public is small, you
+  may wish to simply create a wrapper module.  The wrapper module
+  imports objects from the wrapped module and provides security
+  declarations for them.
+
+- By placing security declarations in a filesystem Product.
+  Filesystem Python code, such as the '__init__.py' of a Product, can
+  make security declarations on behalf of an external module.  This
+  is also known as an "external" module security info declaration.
+
+The 'ModuleSecurityInfo' class is defined in the 'AccessControl'
+package of the Zope framework.
+
+Using ModuleSecurityInfo Objects
+--------------------------------
+
+  Instances of 'ModuleSecurityInfo' are used in two different
+  situations.  In embedded declarations, inside the module they
+  affect.  And in external declarations, made on behalf of a
+  module which may never be imported.
+
+Embedded ModuleSecurityInfo Declarations
+----------------------------------------
+
+An embedded ModuleSecurityInfo declaration causes an object in its
+module to be importable by through-the-web code.
+
+Here's an example of an embedded declaration::
+
+  from AccessControl import ModuleSecurityInfo
+  modulesecurity = ModuleSecurityInfo()
+  modulesecurity.declarePublic('foo')
+
+  def foo():
+      return "hello"
+      # foo
+
+  modulesecurity.apply(globals())
+
+When making embedded ModuleSecurityInfo declarations, you should
+instantiate a ModuleSecurityInfo object and assign it to a name.
+It's wise to use the recommended name 'modulesecurity' for
+consistency's sake.  You may then use the modulesecurity object's
+'declarePublic' method to declare functions inside of the current
+module as public.  Finally, appending the last line
+("modulesecurity.apply(globals())") is an important step.  It's
+necessary in order to poke the security machinery into action.  The
+above example declares the 'foo' function public.
+
+The name 'modulesecurity' is used for consistency and for the benefit
+of new component authors, who often learn from looking at other
+people's code.  You do not have to use the name 'modulesecurity' for
+the security infrastructure to recognize your assertion information,
+but it is recommended as a convention.
+
+External ModuleSecurityInfo Declarations
+----------------------------------------
+
+By creating a ModuleSecurityInfo instance with a module name
+argument, you can make declarations on behalf of a module without
+having to edit or import the module.
+
+Here's an example of an external declaration::
+
+   from AccessControl import ModuleSecurityInfo
+   # protect the 'foo' function within (yet-to-be-imported) 'foomodule'
+   ModuleSecurityInfo('foomodule').declarePublic('foo')
+
+This declaration will cause the following code to work within
+PythonScripts::
+
+   from foomodule import foo
+
+When making external ModuleSecurityInfo declarations, you needn't use
+the "modulesecurity.apply(globals())" idiom demonstrated in the
+embedded declaration section above.  As a result, you needn't assign
+the ModuleSecurityInfo object to the name 'modulesecurity'.
+
+Providing Access To A Module Contained In A Package
+---------------------------------------------------
+
+Note that if you want to provide access to a module inside of a
+package which lives in your PYTHONPATH, you'll need to provide
+security declarations for *all of the the packages and sub-packages
+along the path used to access the module.*
+
+For example, assume you have a function foo, which lives inside a
+module named 'module', which lives inside a package named 'package2',
+which lives inside a package named 'package1' You might declare the
+'foo' function public via this chain of declarations::
+
+  ModuleSecurityInfo('package1').declarePublic('package2')
+  ModuleSecurityInfo('package1.package2').declarePublic('module')
+  ModuleSecurityInfo('package1.package2.module').declarePublic('foo')
+
+Note that in the code above we took the following steps:
+
+- make a ModuleSecurityInfo object for 'package1'
+
+- call the declarePublic method of the 'package1'
+  ModuleSecurityInfo object, specifying 'package2' as what
+  we're declaring public.  This allows through the web code to
+  "see" package2 inside package1.
+
+- make a ModuleSecurityInfo object for 'package1.package2'.
+
+- call the declarePublic method of the 'package1.package2'
+  ModuleSecurityInfo object, specifying 'module' as what we're
+  declaring public.  This allows through the web code to "see"
+  'package1.package2.module'.
+
+- declare 'foo' public inside the ModuleSecurityInfo for
+  'package1.package2.module'. 
+
+Through-the-web code may now perform an import ala: 'import
+package1.package2.module.foo'
+
+Beware that Zope is buggy from 2.3 to 2.5.0b3.  If you make module
+security declarations in more than one Product, only one of the
+Products' security assertions will actually take effect.  This is
+repaired in Zope 2.5.0 and beyond.
+
+Many people who use Zope will be concerned with using
+ModuleSecurityInfo to make declarations on modules which live within
+Zope's Products directory.  This is just an example of declaring
+module security on a module within a package.  Here is an example of
+using ModuleSecurityInfo to make security declarations on behalf of
+the 'CatalogError' class in the 'ZCatalog.py' module.  This could be
+placed, for instance, within the any Product's '__init__.py' module::
+
+  from AccessControl import ModuleSecurityInfo
+  ModuleSecurityInfo('Products').declarePublic('Catalog')
+  ModuleSecurityInfo('Products.Catalog').declarePublic('CatalogError')
+
+Declaring Module Security On Modules Implemented In C
+-----------------------------------------------------
+
+Certain modules, such as the standard Python 'sha' module, provide
+extension types instead of classes, as the 'sha' module is
+implemented in C. Security declarations typically cannot be added to
+extension types, so the only way to use this sort of module is to
+write a Python wrapper class, or use External Methods.
+
+Default Module Security Info Declarations
+-----------------------------------------
+
+Through-the-web Python Scripts are by default able to import a small
+number of Python modules for which there are security
+declarations. These include 'string', 'math', and 'random'. The only
+way to make other Python modules available for import is to add
+security declarations to them in the filesystem.
+
+Utility Functions For Allowing Import of Modules By Through The Web Code
+------------------------------------------------------------------------
+
+Instead of manually providing security declarations for each function
+in a module, the utility function "allow_class" and "allow_module"
+have been created to help you declare the entire contents of a class
+or module as public.
+
+You can handle a module, such as base64, that contains only safe
+functions by writing 'allow_module("module_name")'.  For instance::
+
+  from Products.PythonScripts.Utility import allow_module
+  allow_module("base64")
+
+This statement declares all functions in the 'base64' module (
+'encode', 'decode', 'encodestring', and 'decodestring' ) as public,
+and from a script you will now be able to perform an import statement
+such as "from base64 import encodestring".
+
+
+To allow access to only some names in a module, you can eschew the
+allow_class and allow_module functions for the lessons you learned in
+the previous section and do the protection "manually"::
+
+  from AccessControl import ModuleSecurityInfo
+  ModuleSecurityInfo('module_name').declarePublic('name1','name2', ...)
+
+Making Permission Assertions On A Constructor
+---------------------------------------------
+
+When you develop a Python disk-based product, you will generally be
+required to make "constructor" methods for the objects which you wish
+to make accessible via the Zope management interface by users of your
+Product.  These constructors are usually defined within the modules
+which contain classes which are intended to be turned into Zope
+instances.  For more information on how constructors are used in Zope
+with security, see Chapter 3 "Zope Products".
+
+The Zope Product machinery "bootstraps" Product-based classes with
+proper constructors into the namespace of the Zope management
+interface "Add" list at Zope startup time.  This is done as a
+consequence of registering a class by way of the Product's
+'__init__.py' 'intialize' function.  If you want to make, for
+example, the imaginary 'FooClass' in your Product available from the
+"Add" list, you may construct an '__init__.py' file that looks much
+like this::
+
+      from FooProduct import FooClass
+
+      def initialize(context):
+          """ Initialize classes in the FooProduct module """
+          context.registerClass(
+              FooProduct.FooClass, # the class object
+              permission='Add FooClasses',
+              constructors=(FooProduct.manage_addFooClassForm,
+                            FooProduct.manage_addFooClass),
+              icon='foo.gif'
+              )
+
+The line of primary concern to us above is the one which says
+"permission='Add FooClasses'".  This is a permission declaration
+which, thanks to Zope product initialization, restricts the adding of
+FooClasses to those users who have the 'Add FooClasses' permission by
+way of a role association determined by the system administrator.
+
+If you do not include a 'permission' argument to 'registerClass',
+then Zope will create a default permission named 'Add [meta-type]s'.
+So, for example, if your object had a meta_type of 'Animal', then
+Zope would create a default permission, 'Add Animals'.  For the most
+part, it is much better to be explicit then to rely on Zope to take
+care of security details for you, so be sure to specify a permission
+for your object.
+
+Designing For Security
+======================
+
+"Security is hard." -- Jim Fulton.
+
+When you're under a deadline, and you "just want it to work", dealing
+with security can be difficult.  As a component developer, following
+these basic guidelines will go a long way toward avoiding problems
+with security integration. They also make a good debugging checklist!
+
+- Ensure that any class that needs to work with security has
+  'Acquisition.Implicit' or 'Acquisition.Explicit' somewhere in its
+  base class hierarchy.
+
+- Design the interface to your objects around methods; don't expect
+  clients to access instance attributes directly.
+
+- Ensure that all methods meant for use by restricted code have been
+  protected with appropriate security assertions.
+
+- Ensure that you called the global class initializer on all classes
+  that need to work with security.
+
+Compatibility
+=============
+
+The implementation of the security assertions and 'SecurityInfo'
+interfaces described in this document are available in Zope 2.3 and
+higher.
+
+Older Zope Products do not use the 'SecurityInfo' interfaces for
+security assertions, because these interfaces didn't exist at the
+time.  These Zope products will continue to work without modification
+until further notice.
+
+Using The RoleManager Base Class With Your Zope Product
+=======================================================
+
+After your Product is deployed, system managers and other users of
+your Product often must deal with security settings on instances they
+make from your classes.
+
+Product classes which inherit Zope's standard RoleManager base class
+allow instances of the class to present a security interface.  This
+security interface allows managers and developers of a site to
+control an instance's security settings via the Zope management
+interface.
+
+The user interface is exposed via the *Security* management view.
+From this view, a system administrator may secure instances of your
+Product's class by associating roles with permissions and by
+asserting that your object instance contains "local roles".  It also
+allows them to create "user-defined roles" within the Zope management
+framework in order to associate these roles with the permissions of
+your product and with users.  This user interface and its usage
+patterns are explained in more detail within the Zope Book's security
+chapter.
+
+If your Product's class does not inherit from 'RoleManager', its
+methods will still retain the security assertions associated with
+them, but you will be unable to allow users to associate roles with
+the permissions you've defined respective to instances of your class.
+Your objects will also not allow local role definitions.  Note that
+objects which inherit from the 'SimpleItem.SimpleItem' mixin class
+already inherit from 'RoleManager'.
+
+Conclusion
+==========
+
+Zope security is based upon roles and permissions. Users have
+roles. Security policies map permissions to roles. Classes protect
+methods with permissions. As a developer you main job is to protect
+your classes by associating methods with permissions. Of course there
+are many other details such as protecting modules and functions,
+creating security user interfaces, and initializing security
+settings.


Property changes on: zdgbook/trunk/source/Security.rst
___________________________________________________________________
Added: svn:mergeinfo
   + 

Modified: zdgbook/trunk/source/index.rst
===================================================================
--- zdgbook/trunk/source/index.rst	2009-02-18 02:26:31 UTC (rev 96660)
+++ zdgbook/trunk/source/index.rst	2009-02-18 03:02:05 UTC (rev 96661)
@@ -17,6 +17,7 @@
    Products.rst
    ZODBPersistentComponents.rst
    Acquisition.rst
+   Security.rst
    AppendixA.rst
    AppendixB.rst
 



More information about the Checkins mailing list