Metadata-Version: 1.1
Name: z3c.authviewlet
Version: 1.0
Summary: Authentication viewlet for Zope3
Home-page: http://pypi.python.org/pypi/z3c.authviewlet
Author: Zope Foundation and Contributors
Author-email: zope-dev@zope.org
License: ZPL 2.1
Description: This package provides an authentication viewlet implementation for Zope3.
        
        
        .. contents::
        
        Login and logout
        ----------------
        
        Login and logout work both for basic auth and cookie auth.
        
        
        Setup
        ~~~~~
        
        The layout page template has to include two content providers (viewlet
        mangers):
        
          - ``login-logout-head`` inside the head tag to get automatic
            redirects and JavaScript code which does the logout for basic
            auth and
        
          - ``login-logout`` inside the body tag to get login and logout links.
        
        The sample template looks like this:
        
          >>> import os.path
          >>> template_path = os.path.join(os.path.dirname(__file__), "tests",
          ...     "login-logout-template.pt")
          >>> with open(template_path, "r") as t:
          ...     print(t.read())
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
              <tal:block replace="structure provider:login-logout-head" />
            </head>
            <body>
              <tal:block replace="structure provider:login-logout" />
              <tal:block replace="structure provider:pagelet" />
            </body>
          </html>
        
        This template is registered for the ``IContainer`` interface in
        ``ftesting.zcml``. After creating a container the template is
        used when browsing the container:
        
          >>> from zope.container.btree import BTreeContainer
          >>> layer.getRootFolder()['container'] = BTreeContainer()
        
        Basic auth
        ~~~~~~~~~~
        
        When the user is not logged in the login link is displayed:
        
          >>> from zope.testbrowser.wsgi import Browser
          >>> skinURL = 'http://localhost/++skin++PageletTestSkin/'
          >>> wsgi_app = layer.make_wsgi_app()
          >>> browser = Browser(wsgi_app=wsgi_app)
          >>> browser.handleErrors = False
          >>> browser.open(skinURL + 'container/@@default.html')
          >>> browser.url
          'http://localhost/++skin++PageletTestSkin/container/@@default.html'
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
            </body>
          </html>
        
        Selecting the link leads to the login page, as we use basic auth here,
        we get an HTTP error 401 (unauthorized):
        
          >>> login_url = browser.getLink('Login').url
          >>> browser.getLink('Login').click()
          Traceback (most recent call last):
          httperror_seek_wrapper: HTTP Error 401: Unauthorized
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html
        
        When adding correct credentials we get authorized:
        
          >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
          >>> browser.open(browser.url)
        
        We are redirected to the page where we selected the login link. After
        logging in the login link is no longer displayed. As we did not
        specify that logout is supported, no logout link is displayed:
        
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
            </body>
          </html>
        
        Calling the login URL again leads directly to the page referred in nextURL:
        
          >>> browser.open(login_url)
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
            </body>
          </html>
        
        Calling the login URL again without the query parameter leeds to a
        confirmation page telling that login was successfull:
        
          >>> browser.open(login_url.split('?')[0])
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@login.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
          <head>
          <title>PageletTestLayout</title>
          </head>
          <body>
            <div>
             <h1>Login successful!</h1>
             <p style="font-size: 200%"> You are now logged in as <em>Manager</em>. </p>
             <a href=".">Back to the main page.</a>
            </div>
          </body>
          </html>
        
        Selecting the ``Back to the main page.`` link send the user back to
        the default view of the container. (``ftesting.zcml`` defines
        ``@@default.html`` as the default view.):
        
          >>> browser.getLink('Back to the main page.').click()
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
            </body>
          </html>
        
        
        Providing an ``ILogoutSupported`` adapter leads to a logout link being
        displayed:
        
          >>> import zope.component
          >>> import zope.interface
          >>> import zope.authentication.logout
          >>> import zope.authentication.interfaces
          >>> zope.component.provideAdapter(
          ...     zope.authentication.logout.LogoutSupported,
          ...     adapts=[zope.interface.Interface],
          ...     provides=zope.authentication.interfaces.ILogoutSupported)
          >>> browser.reload()
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
            </body>
          </html>
        
        Logout is done using JavaScript and a redirect. zope.testbrowser >= 5.0
        does not follow redirects if they use the meta tag.
        
        As testbrowser is not able to execute JavaScript the user remains
        authenticated:
        
          >>> logout_url = browser.getLink('Logout').url
          >>> browser.getLink('Logout').click()
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
              <script type="text/javascript"><!--
            // clear HTTP Authentication
            ...
            //-->
          </script>
          <meta http-equiv="refresh"
                content="0;url=http://localhost/++skin++PageletTestSkin/container/@@default.html" />
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Logout</a>
              <div>
            <h1>You are being redirected!</h1>
            <p style="font-size: 150%">
              <a href="http://localhost/++skin++PageletTestSkin/container/@@default.html">
                If you see this screen for more than 5 seconds, click here.
              </a>
            </p>
          </div>
            </body>
          </html>
        
        Calling the logout URL again after logout (simulated using a new
        browser instance) leads directly to the page referred in nextURL:
        
          >>> browser2 = Browser(logout_url, wsgi_app=wsgi_app)
          >>> print(browser2.url)
          http://localhost/++skin++PageletTestSkin/container/@@default.html
          >>> print(browser2.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
            </body>
          </html>
        
        Calling the logout URL again without the query parameter leeds to a
        confirmation page telling that logout was successfull:
        
          >>> browser2.open(logout_url.split('?')[0])
          >>> print(browser2.url)
          http://localhost/++skin++PageletTestSkin/container/@@logout.html
          >>> print(browser2.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
              <script type="text/javascript"><!--
            // clear HTTP Authentication
            ...
            //-->
          </script>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/logout.html/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Login</a>
              <div>
            <h1>Logout successful!</h1>
            <p style="font-size: 200%">
              You are now logged out.
            </p>
            <a href=".">Back to the main page.</a>
          </div>
            </body>
          </html>
        
        
        Cookie auth
        ~~~~~~~~~~~
        
        To do cookie auth we have to set up a pluggable auth utility (PAU)
        with a authenticator plug-in (principal folder) first:
        
          >>> from zope.authentication.interfaces import IAuthentication
          >>> from zope.pluggableauth.interfaces import IAuthenticatorPlugin
          >>> from zope.pluggableauth.authentication import PluggableAuthentication
          >>> from zope.pluggableauth.plugins.principalfolder import PrincipalFolder
          >>> from zope.site import site
        
          >>> root = layer.getRootFolder()
          >>> root['principal_folder'] = PrincipalFolder()
          >>> sm = root.getSiteManager()
          >>> sm.registerUtility(
          ...     root['principal_folder'], IAuthenticatorPlugin, 'principal_folder')
        
          >>> root['auth'] = PluggableAuthentication()
          >>> sm.registerUtility(root['auth'], IAuthentication, '')
          >>> root['auth'].credentialsPlugins = (u'Session Credentials',)
          >>> root['auth'].authenticatorPlugins = (u'principal_folder',)
        
        We need a principal inside the principal folder:
        
          >>> from zope.pluggableauth.plugins.principalfolder import InternalPrincipal
          >>> root['principal_folder']['1'] = InternalPrincipal(
          ...     'tester', 'tpass', 'Tester')
        
        
        We use a new browser, so the principal is not logged in and the login
        link is displayed:
        
          >>> browser = Browser(wsgi_app=wsgi_app)
          >>> browser.open(skinURL + 'container/@@default.html')
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
            </body>
          </html>
        
        Selecting the link leads to the login page:
        
          >>> login_url = browser.getLink('Login').url
          >>> browser.getLink('Login').click()
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/@@loginForm.html?camefrom=http%3A%2F%2Flocalhost%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
          <head>
          <title>PageletTestLayout</title>
          </head>
          <body>
            <div>
            <p>
              Please provide Login Information
            </p>
            <form action="" method="post">
              <div class="row">
                <div class="label"><label for="login">User Name</label></div>
                <div class="field">
                  <input type="text" name="login" id="login" />
                </div>
              </div>
              <div class="row">
                <div class="label"><label for="password">Password</label></div>
                <div class="field">
                  <input type="password" name="password" id="password" />
                </div>
              </div>
              <div class="row">
                <input class="form-element" type="submit"
                       name="SUBMIT" value="Log in" />
              </div>
              <input type="hidden" name="camefrom" value="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
            </form>
          </div>
          </body>
          </html>
        
        Entering wrong username does not authorize but display an error
        message:
        
          >>> browser.getControl('User Name').value = 'me'
          >>> browser.getControl('Password').value = 'tpass'
          >>> browser.getControl('Log in').click()
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/@@loginForm.html?camefrom=http%3A%2F%2Flocalhost%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
          <head>
          <title>PageletTestLayout</title>
          </head>
          <body>
            <div>
            <p>
              Please provide Login Information
            </p>
            <form action="" method="post">
              <div class="row">
                <div class="label"><label for="login">User Name</label></div>
                <div class="field">
                  <input type="text" name="login" id="login" />
                </div>
              </div>
              <div class="row">
                <div class="label"><label for="password">Password</label></div>
                <div class="field">
                  <input type="password" name="password" id="password" />
                </div>
              </div>
              <div class="row">
                <input class="form-element" type="submit"
                       name="SUBMIT" value="Log in" />
              </div>
              <input type="hidden" name="camefrom" value="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
            </form>
          </div>
          </body>
          </html>
        
        Entering wrong password does not authorize either:
        
          >>> browser.getControl('User Name').value = 'tester'
          >>> browser.getControl('Password').value = 'let me in'
          >>> browser.getControl('Log in').click()
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/@@loginForm.html?camefrom=http%3A%2F%2Flocalhost%2F%2B%2Bskin%2B%2BPageletTestSkin%2Fcontainer%2F%40%40login.html%3FnextURL%3Dhttp%253A%2F%2Flocalhost%2F%252B%252Bskin%252B%252BPageletTestSkin%2Fcontainer%2F%2540%2540default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
          <head>
          <title>PageletTestLayout</title>
          </head>
          <body>
            <div>
            <p>
              Please provide Login Information
            </p>
            <form action="" method="post">
              <div class="row">
                <div class="label"><label for="login">User Name</label></div>
                <div class="field">
                  <input type="text" name="login" id="login" />
                </div>
              </div>
              <div class="row">
                <div class="label"><label for="password">Password</label></div>
                <div class="field">
                  <input type="password" name="password" id="password" />
                </div>
              </div>
              <div class="row">
                <input class="form-element" type="submit"
                       name="SUBMIT" value="Log in" />
              </div>
              <input type="hidden" name="camefrom" value="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">
            </form>
          </div>
          </body>
          </html>
        
        
        After entering a correct username and password the user gets
        authorized:
        
          >>> browser.getControl('User Name').value = 'tester'
          >>> browser.getControl('Password').value = 'tpass'
          >>> browser.getControl('Log in').click()
        
        The user gets redirected to the page where he selected the login
        link. After logging in the login link is no longer displayed. As we
        already specified that logout is supported, a logout link is
        displayed:
        
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
            </body>
          </html>
        
        
        Calling the login URL again leads directly to the page referred in nextURL:
        
          >>> browser.open(login_url)
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
            </body>
          </html>
        
        Calling the login URL again without the query parameter leeds to a
        confirmation page telling that login was successfull:
        
          >>> browser.open(login_url.split('?')[0])
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@login.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
          <head>
          <title>PageletTestLayout</title>
          </head>
          <body>
            <div>
             <h1>Login successful!</h1>
             <p style="font-size: 200%"> You are now logged in as <em>Tester</em>. </p>
             <a href=".">Back to the main page.</a>
            </div>
          </body>
          </html>
        
        Selecting the ``Back to the main page.`` link send the user back to
        the default view of the container. (``ftesting.zcml`` defines
        ``@@default.html`` as the default view.):
        
          >>> browser.getLink('Back to the main page.').click()
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
            </body>
          </html>
        
        
        Selecting the displayed logout link drops authentication information
        and displays a confirmation page, which redirects to the default page
        where the login link is displayed again:
        
          >>> logout_url = browser.getLink('Logout').url
          >>> browser.getLink('Logout').click()
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
              <script type="text/javascript"><!--
            // clear HTTP Authentication
            ...
            //-->
          </script>
          <meta http-equiv="refresh"
                content="0;url=http://localhost/++skin++PageletTestSkin/container/@@default.html" />
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Logout</a>
              <div>
            <h1>You are being redirected!</h1>
          <BLANKLINE>
            <p style="font-size: 150%">
              <a href="http://localhost/++skin++PageletTestSkin/container/@@default.html">
                If you see this screen for more than 5 seconds, click here.
              </a>
            </p>
          </div>
            </body>
          </html>
          >>> browser.getLink('If you see this screen for more than 5 seconds').click()
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
            </body>
          </html>
        
        Calling the logout URL again after logout leads directly to the page
        referred in nextURL:
        
          >>> browser.open(logout_url)
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@default.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
            </body>
          </html>
        
        Calling the logout URL again without the query parameter leeds to a
        confirmation page telling that logout was successfull:
        
          >>> browser.open(logout_url.split('?')[0])
          >>> print(browser.url)
          http://localhost/++skin++PageletTestSkin/container/@@logout.html
          >>> print(browser.contents)
          <!DOCTYPE ...>
          <html ...>
            <head>
              <title>PageletTest</title>
              <script type="text/javascript"><!--
            // clear HTTP Authentication
            ...
            //-->
          </script>
            </head>
            <body>
              <a href="http://localhost/++skin++PageletTestSkin/container/logout.html/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Login</a>
              <div>
            <h1>Logout successful!</h1>
            <p style="font-size: 200%">
              You are now logged out.
            </p>
            <a href=".">Back to the main page.</a>
          </div>
            </body>
          </html>
        
        
        Changes
        -------
        
        1.0 (2017-06-07)
        ~~~~~~~~~~~~~~~~
        
        - Update to Python 3. Now supporting: Python 3.4 to 3.6, PyPy2 and PyPy3.
        
        - Update the tests to `zope.testbrowser >= 5.0`.
        
        
        0.8.0 (2010-10-13)
        ~~~~~~~~~~~~~~~~~~
        
        - Adapted test set up to the changes in `z3c.layer.pagelet` 1.9 thus
          requiring at least this version now.
        
        - Moved code from page template of session credentials login page to view
          class so it can be customized. (Taken from
          `zope.app.authentication.browser.loginform.LoginForm`.) Moved view class
          ``SessionCredentialsLoginForm`` from `z3c.authviewlet.auth` to
          `z3c.authviewlet.session`.
        
        0.7.0 (2009-12-27)
        ~~~~~~~~~~~~~~~~~~
        
        - Moved files in `z3c.authviewlet.browser` to `z3c.authviewlet` as
          we only have browser code in this package.
        
        - Broke dependency on `zope.app.publisher` by defining our own
          ``ILogin`` interface.
        
        0.6.0 (2009-12-24)
        ~~~~~~~~~~~~~~~~~~
        
        - Added `i18n domains` to allow translation (done in `z3c.locales` package).
        
        0.5.0 (2009-11-30)
        ~~~~~~~~~~~~~~~~~~
        
        - Moved authentication viewlet implementation from `z3c.layer.pagelet`
          to this package.
        
        - Initial release.
        
Keywords: z3c authentication viewlet zope zope3
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: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Framework :: Zope3
