Metadata-Version: 1.0
Name: zope.app.security
Version: 3.5.3
Summary: Security Components for Zope 3 Applications
Home-page: http://cheeseshop.python.org/pypi/zope.app.security
Author: Zope Corporation and Contributors
Author-email: zope3-dev@zope.org
License: ZPL 2.1
Description: This package provides several components integrating the Zope security
        implementation into zope 3 applications.
        
        
        Detailed Dcoumentation
        ======================
        
        
        ===========================
        Global principal definition
        ===========================
        
        Global principals are defined via ZCML.  There are several kinds of
        principals that can be defined.
        
        Authenticated Users
        -------------------
        
        There are principals that can log in:
        
        >>> zcml("""
        ...    <configure
        ...        xmlns="http://namespaces.zope.org/zope"
        ...        >
        ...
        ...      <principal
        ...         id="zope.manager"
        ...         title="Manager"
        ...         description="System Manager"
        ...         login="admin"
        ...         password_manager="SHA1"
        ...         password="40bd001563085fc35165329ea1ff5c5ecbdbbeef"
        ...         />
        ...
        ...    </configure>
        ... """)
        
        >>> import pprint
        >>> from zope.app.security.principalregistry import principalRegistry
        >>> [p] = principalRegistry.getPrincipals('')
        >>> p.id, p.title, p.description, p.getLogin(), p.validate('123')
        ('zope.manager', u'Manager', u'System Manager', u'admin', True)
        
        The unauthenticated principal
        -----------------------------
        
        There is the unauthenticated principal:
        
        >>> zcml("""
        ...    <configure
        ...        xmlns="http://namespaces.zope.org/zope"
        ...        >
        ...
        ...      <unauthenticatedPrincipal
        ...         id="zope.unknown"
        ...         title="Anonymous user"
        ...         description="A person we don't know"
        ...         />
        ...
        ...    </configure>
        ... """)
        
        >>> p = principalRegistry.unauthenticatedPrincipal()
        >>> p.id, p.title, p.description
        ('zope.unknown', u'Anonymous user', u"A person we don't know")
        
        The unauthenticated principal will also be registered as a utility.
        This is to provide easy access to the data defined for the principal so
        that other (more featureful) principal objects can be created for the
        same principal.
        
        >>> from zope import component
        >>> from zope.app.security import interfaces
        >>> p = component.getUtility(interfaces.IUnauthenticatedPrincipal)
        >>> p.id, p.title, p.description
        ('zope.unknown', u'Anonymous user', u"A person we don't know")
        
        The unauthenticated group
        -------------------------
        
        An unauthenticated group can also be defined in ZCML:
        
        >>> zcml("""
        ...    <configure
        ...        xmlns="http://namespaces.zope.org/zope"
        ...        >
        ...
        ...      <unauthenticatedGroup
        ...         id="zope.unknowngroup"
        ...         title="Anonymous users"
        ...         description="People we don't know"
        ...         />
        ...
        ...    </configure>
        ... """)
        
        This directive creates a group and registers it as a utility providing
        IUnauthenticatedGroup:
        
        >>> g = component.getUtility(interfaces.IUnauthenticatedGroup)
        >>> g.id, g.title, g.description
        ('zope.unknowngroup', u'Anonymous users', u"People we don't know")
        
        The unauthenticatedGroup directive also updates the group of the
        unauthenticated principal:
        
        >>> p = principalRegistry.unauthenticatedPrincipal()
        >>> g.id in p.groups
        True
        >>> p = component.getUtility(interfaces.IUnauthenticatedPrincipal)
        >>> g.id in p.groups
        True
        
        If the unauthenticated principal is defined after the unauthenticated
        group, it will likewise have the group added to it:
        
        >>> reset()
        >>> zcml("""
        ...    <configure
        ...        xmlns="http://namespaces.zope.org/zope"
        ...        >
        ...
        ...      <unauthenticatedGroup
        ...         id="zope.unknowngroup2"
        ...         title="Anonymous users"
        ...         description="People we don't know"
        ...         />
        ...      <unauthenticatedPrincipal
        ...         id="zope.unknown2"
        ...         title="Anonymous user"
        ...         description="A person we don't know"
        ...         />
        ...
        ...    </configure>
        ... """)
        
        >>> g = component.getUtility(interfaces.IUnauthenticatedGroup)
        >>> g.id, g.title, g.description
        ('zope.unknowngroup2', u'Anonymous users', u"People we don't know")
        >>> p = principalRegistry.unauthenticatedPrincipal()
        >>> p.id, g.id in p.groups
        ('zope.unknown2', True)
        >>> p = component.getUtility(interfaces.IUnauthenticatedPrincipal)
        >>> p.id, g.id in p.groups
        ('zope.unknown2', True)
        
        The unauthenticated group shows up as a principal in the principal
        registry:
        
        >>> principalRegistry.getPrincipal(g.id) == g
        True
        
        >>> list(principalRegistry.getPrincipals("Anonymous")) == [g]
        True
        
        The authenticated group
        -----------------------
        
        There is an authenticated group:
        
        >>> reset()
        >>> zcml("""
        ...    <configure
        ...        xmlns="http://namespaces.zope.org/zope"
        ...        >
        ...
        ...      <unauthenticatedPrincipal
        ...         id="zope.unknown3"
        ...         title="Anonymous user"
        ...         description="A person we don't know"
        ...         />
        ...      <principal
        ...         id="zope.manager2"
        ...         title="Manager"
        ...         description="System Manager"
        ...         login="admin"
        ...         password="123"
        ...         />
        ...      <authenticatedGroup
        ...         id="zope.authenticated"
        ...         title="Authenticated users"
        ...         description="People we know"
        ...         />
        ...      <principal
        ...         id="zope.manager3"
        ...         title="Manager 3"
        ...         login="admin3"
        ...         password="123"
        ...         />
        ...
        ...    </configure>
        ... """)
        
        It defines an IAuthenticatedGroup utility:
        
        >>> g = component.getUtility(interfaces.IAuthenticatedGroup)
        >>> g.id, g.title, g.description
        ('zope.authenticated', u'Authenticated users', u'People we know')
        
        It also adds it self to the groups of any non-group principals already
        defined, and, when non-group principals are defined, they put
        themselves in the group if it's defined:
        
        >>> principals = list(principalRegistry.getPrincipals(''))
        >>> principals.sort(lambda p1, p2: cmp(p1.id, p2.id))
        >>> for p in principals:
        ...    print p.id, p.groups == [g.id]
        zope.authenticated False
        zope.manager2 True
        zope.manager3 True
        
        Excluding unauthenticated principals, of course:
        
        >>> p = principalRegistry.unauthenticatedPrincipal()
        >>> p.id, g.id in p.groups
        ('zope.unknown3', False)
        >>> p = component.getUtility(interfaces.IUnauthenticatedPrincipal)
        >>> p.id, g.id in p.groups
        ('zope.unknown3', False)
        
        
        The everybody group
        -------------------
        
        Finally, there is an everybody group:
        
        >>> reset()
        >>> zcml("""
        ...    <configure
        ...        xmlns="http://namespaces.zope.org/zope"
        ...        >
        ...
        ...      <unauthenticatedPrincipal
        ...         id="zope.unknown4"
        ...         title="Anonymous user"
        ...         description="A person we don't know"
        ...         />
        ...      <principal
        ...         id="zope.manager4"
        ...         title="Manager"
        ...         description="System Manager"
        ...         login="admin"
        ...         password="123"
        ...         />
        ...      <everybodyGroup
        ...         id="zope.everybody"
        ...         title="Everybody"
        ...         description="All People"
        ...         />
        ...      <principal
        ...         id="zope.manager5"
        ...         title="Manager 5"
        ...         login="admin5"
        ...         password="123"
        ...         />
        ...
        ...    </configure>
        ... """)
        
        The everybodyGroup directive defines an IEveryoneGroup utility:
        
        >>> g = component.getUtility(interfaces.IEveryoneGroup)
        >>> g.id, g.title, g.description
        ('zope.everybody', u'Everybody', u'All People')
        
        It also adds it self to the groups of any non-group principals already
        defined, and, when non-group principals are defined, they put
        themselves in the group if it's defined:
        
        >>> principals = list(principalRegistry.getPrincipals(''))
        >>> principals.sort(lambda p1, p2: cmp(p1.id, p2.id))
        >>> for p in principals:
        ...    print p.id, p.groups == [g.id]
        zope.everybody False
        zope.manager4 True
        zope.manager5 True
        
        Including unauthenticated principals, of course:
        
        >>> p = principalRegistry.unauthenticatedPrincipal()
        >>> p.id, g.id in p.groups
        ('zope.unknown4', True)
        >>> p = component.getUtility(interfaces.IUnauthenticatedPrincipal)
        >>> p.id, g.id in p.groups
        ('zope.unknown4', True)
        
        Note that it is up to IAuthentication implementations to associate
        these groups with their principals, as appropriate.
        
        
        The system_user
        ---------------
        
        There is also a system_user that is defined in the code.  It will be returned
        from the getPrincipal method of the registry.
        
        >>> import zope.security.management
        >>> import zope.app.security.principalregistry
        >>> auth = zope.app.security.principalregistry.PrincipalRegistry()
        >>> system_user = auth.getPrincipal(u'zope.security.management.system_user')
        >>> system_user is zope.security.management.system_user
        True
        
        
        ==============
        Logout Support
        ==============
        
        Logout support is defined by a simple interface ILogout:
        
        >>> from zope.app.security.interfaces import ILogout
        
        that has a single 'logout' method.
        
        The current use of ILogout is to adapt an IAuthentication component to ILogout
        To illustrate, we'll create a simple logout implementation that adapts
        IAuthentication:
        
        >>> class SimpleLogout(object):
        ...
        ...     adapts(IAuthentication)
        ...     implements(ILogout)
        ...
        ...     def __init__(self, auth):
        ...         pass
        ...
        ...     def logout(self, request):
        ...         print 'User has logged out'
        
        >>> provideAdapter(SimpleLogout)
        
        and something to represent an authentication utility:
        
        >>> class Authentication(object):
        ...
        ...     implements(IAuthentication)
        
        >>> auth = Authentication()
        
        To perform a logout, we adapt auth to ILogout and call 'logout':
        
        >>> logout = ILogout(auth)
        >>> logout.logout(TestRequest())
        User has logged out
        
        
        The 'NoLogout' Adapter
        ----------------------
        
        The class:
        
        >>> from zope.app.security import NoLogout
        
        can be registered as a fallback provider of ILogout for IAuthentication
        components that are not otherwise adaptable to ILogout. NoLogout's logout
        method is a no-op:
        
        >>> NoLogout(auth).logout(TestRequest())
        
        
        Logout User Interface
        ---------------------
        
        Because some authentication protocols do not formally support logout, it may
        not be possible for a user to logout once he or she has logged in. In such
        cases, it would be inappropriate to present a user interface for logging out.
        
        Because logout support is site-configurable, Zope provides an adapter that,
        when registered, indicates that the site is configured for logout:
        
        >>> from zope.app.security import LogoutSupported
        
        This class merely serves as a flag as it implements ILogoutSupported:
        
        >>> from zope.app.security.interfaces import ILogoutSupported
        >>> ILogoutSupported.implementedBy(LogoutSupported)
        True
        
        For more information on login/logout UI, see
        zope/app/security/browser/loginlogout.txt.
        
        
        ===========================================
        The Query View for Authentication Utilities
        ===========================================
        
        A regular authentication service will not provide the `ISourceQueriables`
        interface, but it is a queriable itself, since it provides the simple
        `getPrincipals(name)` method:
        
        >>> class Principal:
        ...     def __init__(self, id):
        ...         self.id = id
        
        >>> class MyAuthUtility:
        ...     data = {'jim': Principal(42), 'don': Principal(0),
        ...             'stephan': Principal(1)}
        ...
        ...     def getPrincipals(self, name):
        ...         return [principal
        ...                 for id, principal in self.data.items()
        ...                 if name in id]
        
        Now that we have our queriable, we create the view for it:
        
        >>> from zope.app.security.browser.auth import AuthUtilitySearchView
        >>> from zope.publisher.browser import TestRequest
        >>> request = TestRequest()
        >>> view = AuthUtilitySearchView(MyAuthUtility(), request)
        
        This allows us to render a search form.
        
        >>> print view.render('test') # doctest: +NORMALIZE_WHITESPACE
        <h4>principals.zcml</h4>
        <div class="row">
        <div class="label">
        Search String
        </div>
        <div class="field">
        <input type="text" name="test.searchstring" />
        </div>
        </div>
        <div class="row">
        <div class="field">
        <input type="submit" name="test.search" value="Search" />
        </div>
        </div>
        
        If we ask for results:
        
        >>> view.results('test')
        
        We don't get any, since we did not provide any. But if we give input:
        
        >>> request.form['test.searchstring'] = 'n'
        
        we still don't get any:
        
        >>> view.results('test')
        
        because we did not press the button. So let's press the button:
        
        >>> request.form['test.search'] = 'Search'
        
        so that we now get results (!):
        
        >>> ids = list(view.results('test'))
        >>> ids.sort()
        >>> ids
        [0, 1]
        
        
        ====================
        Login/Logout Snippet
        ====================
        
        The class LoginLogout:
        
        >>> from zope.app.security.browser.auth import LoginLogout
        
        is used as a view to generate an HTML snippet suitable for logging in or
        logging out based on whether or not the current principal is authenticated.
        
        When the current principal is unauthenticated, it provides
        IUnauthenticatedPrincipal:
        
        >>> from zope.app.security.interfaces import IUnauthenticatedPrincipal
        >>> from zope.app.security.principalregistry import UnauthenticatedPrincipal
        >>> anonymous = UnauthenticatedPrincipal('anon', '', '')
        >>> IUnauthenticatedPrincipal.providedBy(anonymous)
        True
        
        When LoginLogout is used for a request that has an unauthenticated principal,
        it provides the user with a link to 'Login':
        
        >>> from zope.publisher.browser import TestRequest
        >>> request = TestRequest()
        >>> request.setPrincipal(anonymous)
        >>> LoginLogout(None, request)()
        u'<a href="@@login.html?nextURL=http%3A//127.0.0.1">[Login]</a>'
        
        Logout, however, behaves differently. Not all authentication protocols (i.e.
        credentials extractors/challengers) support 'logout'. Furthermore, we don't
        know how an admin may have configured Zope's authentication. Our solution is
        to rely on the admin to tell us explicitly that the site supports logout.
        
        By default, the LoginLogout snippet will not provide a logout link for an
        unauthenticated principal. To illustrate, we'll first setup a request with an
        unauthenticated principal:
        
        >>> from zope.security.interfaces import IPrincipal
        >>> from zope.interface import implements
        >>> class Bob:
        ...     implements(IPrincipal)
        ...     id = 'bob'
        ...     title = description = ''
        >>> bob = Bob()
        >>> IUnauthenticatedPrincipal.providedBy(bob)
        False
        >>> request.setPrincipal(bob)
        
        In this case, the default behavior is to return None for the snippet:
        
        >>> print LoginLogout(None, request)()
        None
        
        To show a logout prompt, an admin must register a marker adapter that provides
        the interface:
        
        >>> from zope.app.security.interfaces import ILogoutSupported
        
        This flags to LoginLogout that the site supports logout. There is a 'no-op'
        adapter that can be registered for this:
        
        >>> from zope.app.security import LogoutSupported
        >>> from zope.app.testing import ztapi
        >>> ztapi.provideAdapter(None, ILogoutSupported, LogoutSupported)
        
        Now when we use LoginLogout with an unauthenticated principal, we get a logout
        prompt:
        
        >>> LoginLogout(None, request)()
        u'<a href="@@logout.html?nextURL=http%3A//127.0.0.1">[Logout]</a>'
        
        
        ===============
        Principal Terms
        ===============
        
        Principal Terms are used to support browser interfaces for searching principal
        sources. They provide access to tokens and titles for values. The principal
        terms view uses an authentication utility to get principal titles. Let's
        create an authentication utility to demonstrate how this works:
        
        >>> class Principal:
        ...     def __init__(self, id, title):
        ...         self.id, self.title = id, title
        
        >>> from zope.interface import implements
        >>> from zope.app.security.interfaces import IAuthentication
        >>> from zope.app.security.interfaces import PrincipalLookupError
        >>> class AuthUtility:
        ...     implements(IAuthentication)
        ...     data = {'jim': 'Jim Fulton', 'stephan': 'Stephan Richter'}
        ...
        ...     def getPrincipal(self, id):
        ...         title = self.data.get(id)
        ...         if title is not None:
        ...             return Principal(id, title)
        ...         raise PrincipalLookupError
        
        Now we need to install the authentication utility:
        
        >>> from zope.app.testing import ztapi
        >>> ztapi.provideUtility(IAuthentication, AuthUtility())
        
        We need a principal source so that we can create a view from it.
        
        >>> from zope.component import getUtility
        >>> class PrincipalSource:
        ...     def __contains__(self, id):
        ...          auth = getUtility(IAuthentication)
        ...          try:
        ...              auth.getPrincipal(id)
        ...          except PrincipalLookupError:
        ...              return False
        ...          else:
        ...              return True
        
        Now we can create an terms view:
        
        >>> from zope.app.security.browser.principalterms import PrincipalTerms
        >>> terms = PrincipalTerms(PrincipalSource(), None)
        
        Now we can ask the terms view for terms:
        
        >>> term = terms.getTerm('stephan')
        >>> term.title
        'Stephan Richter'
        >>> term.token
        'c3RlcGhhbg__'
        
        If we ask for a term that does not exist, we get a lookup error:
        
        >>> terms.getTerm('bob')
        Traceback (most recent call last):
        ...
        LookupError: bob
        
        If we have a token, we can get the principal id for it.
        
        >>> terms.getValue('c3RlcGhhbg__')
        'stephan'
        
        
        =======
        CHANGES
        =======
        
        3.5.3 (2008-12-11)
        ---------------------
        
        - use zope.browser.interfaces.ITerms instead of zope.app.form.browser.interfaces
        
        3.5.2 (2008-07-31)
        ------------------
        
        - Bug: It turned out that checking for regex was not much better of an idea,
        since it causes deprecation warnings in Python 2.4. Thus let's look for a
        library that was added in Python 2.5.
        
        3.5.1 (2008-06-24)
        ------------------
        
        - Bug: The `gopherlib` module has been deprecated in Python 2.5. Whenever the
        ZCML of this package was included when using Python 2.5, a deprecation
        warning had been raised stating that `gopherlib` has been
        deprecated. Provided a simple condition to check whether Python 2.5 or later
        is installed by checking for the deleted `regex` module and thus optionally
        load the security declaration for `gopherlib`.
        
        3.5.0 (2008-02-05)
        ------------------
        
        - Feature:
        `zope.app.security.principalregistry.PrincipalRegistry.getPrincipal` returns
        `zope.security.management.system_user` when its id is used for the search
        key.
        
        3.4.0 (2007-10-27)
        ------------------
        
        - Initial release independent of the main Zope tree.
        
Keywords: zope3 security authentication principal ftp http
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Zope Public License
Classifier: Programming Language :: Python
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Framework :: Zope3
