[Checkins] SVN: zope.app.openidconsumer/trunk/ Rough (really rough) draft of an OpenID consumer.

Shane Hathaway shane at hathawaymix.org
Mon Feb 23 18:45:57 EST 2009


Log message for revision 97184:
  Rough (really rough) draft of an OpenID consumer.
  

Changed:
  A   zope.app.openidconsumer/trunk/
  A   zope.app.openidconsumer/trunk/bootstrap.py
  A   zope.app.openidconsumer/trunk/buildout.cfg
  A   zope.app.openidconsumer/trunk/setup.py
  A   zope.app.openidconsumer/trunk/src/
  A   zope.app.openidconsumer/trunk/src/zope/
  A   zope.app.openidconsumer/trunk/src/zope/__init__.py
  A   zope.app.openidconsumer/trunk/src/zope/app/
  A   zope.app.openidconsumer/trunk/src/zope/app/__init__.py
  A   zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/
  A   zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/__init__.py
  A   zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/authentication.py
  A   zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/configure.zcml
  A   zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/interfaces.py
  A   zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/register.py
  A   zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/view.py

-=-
Added: zope.app.openidconsumer/trunk/bootstrap.py
===================================================================
--- zope.app.openidconsumer/trunk/bootstrap.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/bootstrap.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 96548 2009-02-14 21:07:51Z shane $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)

Added: zope.app.openidconsumer/trunk/buildout.cfg
===================================================================
--- zope.app.openidconsumer/trunk/buildout.cfg	                        (rev 0)
+++ zope.app.openidconsumer/trunk/buildout.cfg	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,23 @@
+[buildout]
+develop = .
+parts = test python coverage-test coverage-report
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = zope.app.openidconsumer
+
+[python]
+recipe = zc.recipe.egg
+eggs = zope.app.openidconsumer
+interpreter = python
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = zope.app.openidconsumer
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')

Added: zope.app.openidconsumer/trunk/setup.py
===================================================================
--- zope.app.openidconsumer/trunk/setup.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/setup.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,54 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from setuptools import setup, find_packages
+
+setup(name='zope.app.openidconsumer',
+
+      # Fill in project info below
+      version='0.1',
+      description="",
+      long_description="",
+      keywords='',
+      author='',
+      author_email='',
+      url='',
+      license='',
+      # Get more from http://www.python.org/pypi?%3Aaction=list_classifiers
+      classifiers=['Programming Language :: Python',
+                   'Environment :: Web Environment',
+                   'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
+                   'Framework :: Zope3',
+                   ],
+
+      packages=find_packages('src'),
+      package_dir = {'': 'src'},
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=['setuptools',
+                        'python-openid',
+                        'ZODB3',
+                        'zope.app.component',
+                        'zope.app.security',
+                        'zope.component',
+                        'zope.traversing',
+                        'zope.interface',
+                        'zope.location',
+                        'zope.publisher',
+                        'zope.session',
+                        'zope.security',
+                        'zope.formlib',
+                        'zope.schema',
+                        ],
+      )

Added: zope.app.openidconsumer/trunk/src/zope/__init__.py
===================================================================
--- zope.app.openidconsumer/trunk/src/zope/__init__.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/src/zope/__init__.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)

Added: zope.app.openidconsumer/trunk/src/zope/app/__init__.py
===================================================================
--- zope.app.openidconsumer/trunk/src/zope/app/__init__.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/src/zope/app/__init__.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)

Added: zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/__init__.py
===================================================================
--- zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/__init__.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/__init__.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1 @@
+# Make this directory a package

Added: zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/authentication.py
===================================================================
--- zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/authentication.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/authentication.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,156 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from urllib import quote_plus
+
+from openid.consumer.consumer import Consumer
+from openid.consumer.consumer import SUCCESS
+from openid.store.memstore import MemoryStore
+from persistent import Persistent
+from persistent.mapping import PersistentMapping
+from zope.app.component.hooks import getSite
+from zope.app.security.interfaces import PrincipalLookupError
+from zope.component import getMultiAdapter
+from zope.traversing.browser import absoluteURL
+from zope.interface import implements
+from zope.location import Location
+from zope.publisher.interfaces import Redirect
+from zope.session.interfaces import ISession
+from zope.security.interfaces import IPrincipal
+
+from zope.app.openidconsumer.interfaces import AuthenticationFailed
+from zope.app.openidconsumer.interfaces import IOpenIDConsumer
+
+PACKAGE = 'zope.app.openidconsumer'
+PRINCIPAL = 'principal'
+CONSUMER = 'consumer'
+
+store = MemoryStore()
+
+
+class OpenIDPrincipal(object):
+    implements(IPrincipal)
+
+    description = u"User authenticated via OpenID"
+
+    def __init__(self, principal_id):
+        self.id = self.title = principal_id
+
+
+class OpenIDConsumer(Persistent, Location):
+    implements(IOpenIDConsumer)
+
+    identity_provider = None
+
+    def authenticate(self, request):
+        """Identify a principal for a request.
+
+        If a principal can be identified, then return the
+        principal. Otherwise, return None.
+        """
+        #if not IBrowserRequest.providedBy(request):
+        #    raise NotImplementedError(
+        #        "only browser requests are supported by OpenIDConsumer")
+        session = ISession(request)[PACKAGE]
+        return session.get(PRINCIPAL, None)
+
+    def _get_consumer(self, request):
+        session = ISession(request)[PACKAGE]
+        consumer_session_data = session.get(CONSUMER)
+        if consumer_session_data is None:
+            consumer_session_data = PersistentMapping()
+            session[CONSUMER] = consumer_session_data
+        else:
+            consumer_session_data._p_changed = True
+        return Consumer(consumer_session_data, store)
+
+    def _get_view_url(self, request, name):
+        site = getSite()
+        base = absoluteURL(site, request)
+        res = "%s/@@openid/%s" % (base, name)
+        next_url = request.get('nextURL')
+        if next_url:
+            res += '?nextURL=' + quote_plus(next_url)
+        return res
+
+    def login(self, request, identity_url=None):
+        if self.identity_provider:
+            # override
+            identity_url = self.identity_provider
+        if identity_url:
+            consumer = self._get_consumer(request)
+            auth_req = consumer.begin(identity_url)
+            site = getSite()
+            realm = absoluteURL(site, request)
+            url = auth_req.redirectURL(
+                realm, self._get_view_url(request, 'complete'))
+        else:
+            url = self._get_view_url(request, 'choose_identity')
+        request.response.redirect(url)
+
+    def complete(self, request):
+        app_url = self._get_view_url(request, 'complete')
+        consumer = self._get_consumer(request)
+        resp = consumer.complete(request.form, app_url)
+        if resp.status != SUCCESS:
+            raise AuthenticationFailed(resp)
+        else:
+            session = ISession(request)[PACKAGE]
+            session[PRINCIPAL] = OpenIDPrincipal(resp.identity_url)
+            next_url = request.get('nextURL')
+            if not next_url:
+                next_url = absoluteURL(getSite(), request)
+            request.response.redirect(next_url)
+
+    def unauthenticatedPrincipal(self):
+        """Return the unauthenticated principal, if one is defined.
+
+        Return None if no unauthenticated principal is defined.
+
+        The unauthenticated principal must be an IUnauthenticatedPrincipal.
+        """
+        return None
+
+    def unauthorized(self, principal_id, request):
+        """Signal an authorization failure.
+
+        This method is called when an auhorization problem
+        occurs. It can perform a variety of actions, such
+        as issuing an HTTP authentication challenge or
+        displaying a login interface.
+
+        Note that the authentication utility nearest to the
+        requested resource is called. It is up to
+        authentication utility implementations to
+        collaborate with utilities higher in the object
+        hierarchy.
+
+        If no principal has been identified, id will be
+        None.
+        """
+        self.login(request)
+
+    def getPrincipal(self, id):
+        """Get principal meta-data.
+
+        Returns an object of type IPrincipal for the given principal
+        id. A PrincipalLookupError is raised if the principal cannot be
+        found.
+
+        Note that the authentication utility nearest to the requested
+        resource is called. It is up to authentication utility
+        implementations to collaborate with utilities higher in the
+        object hierarchy.
+        """
+        raise PrincipalLookupError()

Added: zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/configure.zcml
===================================================================
--- zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/configure.zcml	                        (rev 0)
+++ zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/configure.zcml	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,79 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zope"
+    >
+
+  <class class=".authentication.OpenIDConsumer">
+    <require
+        permission="zope.ManageSite"
+        interface=".interfaces.IOpenIDConsumerConfig"
+        set_schema=".interfaces.IOpenIDConsumerConfig"
+        />
+    <require
+        permission="zope.ManageServices"
+        attributes="registrationManager"
+        />
+  </class>
+
+  <browser:addform
+      schema=".interfaces.IOpenIDConsumerConfig"
+      label="Add OpenID Consumer"
+      content_factory=".authentication.OpenIDConsumer"
+      name="AddOpenIDConsumer"
+      permission="zope.ManageServices"
+      >
+
+    <browser:widget
+        field="identity_provider"
+        class="zope.app.form.browser.TextWidget"
+        required="False"
+        convert_missing_value="False"
+        />
+
+  </browser:addform>
+
+  <browser:addMenuItem
+      class=".authentication.OpenIDConsumer"
+      view="AddOpenIDConsumer"
+      title="OpenID Authentication Consumer"
+      description="Consumer of OpenID authentication services"
+      permission="zope.ManageServices"
+      />
+
+  <browser:page
+      for=".interfaces.IOpenIDConsumerConfig"
+      name="addRegistration.html"
+      permission="zope.ManageSite"
+      class=".register.Registration"
+      />
+
+  <browser:editform
+      schema=".interfaces.IOpenIDConsumerConfig"
+      label="Edit OpenID Authentication Consumer"
+      name="configure"
+      menu="zmi_views" title="Configure"
+      permission="zope.ManageServices"
+      />
+
+  <browser:view
+      name="openid"
+      for="zope.location.interfaces.ISite"
+      permission="zope.Public"
+      class=".view.OpenIDView"
+      >
+    <browser:page
+        name="choose_identity"
+        attribute="choose_identity"
+        />
+    <browser:page
+        name="login"
+        attribute="login"
+        />
+    <browser:page
+        name="complete"
+        attribute="complete"
+        />
+  </browser:view>
+
+</configure>

Added: zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/interfaces.py
===================================================================
--- zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/interfaces.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/interfaces.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from zope.app.security.interfaces import IAuthentication
+from zope.interface import Interface
+from zope.schema import URI
+
+class IOpenIDConsumerConfig(Interface):
+    identity_provider = URI(
+        title=u'Identity Provider URI',
+        required=False
+        )
+
+class IOpenIDConsumer(IOpenIDConsumerConfig, IAuthentication):
+    pass
+
+class AuthenticationFailed(Exception):
+    """OpenID authentication failed"""

Added: zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/register.py
===================================================================
--- zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/register.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/register.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+
+from zope.app.openidconsumer.interfaces import IOpenIDConsumer
+from zope.app.component.browser.registration import AddUtilityRegistration
+
+class Registration(AddUtilityRegistration):
+    label = u"Register an OpenID authentication utility"
+    name = ''
+    provided = IOpenIDConsumer

Added: zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/view.py
===================================================================
--- zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/view.py	                        (rev 0)
+++ zope.app.openidconsumer/trunk/src/zope/app/openidconsumer/view.py	2009-02-23 23:45:56 UTC (rev 97184)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+
+from zope.component import getUtility
+from zope.formlib.form import action
+from zope.formlib.form import Fields
+from zope.formlib.form import Form
+from zope.interface import Interface
+from zope.publisher.browser import BrowserView
+from zope.schema import TextLine
+
+from zope.app.openidconsumer.interfaces import IOpenIDConsumer
+
+
+class IChooseIdentitySchema(Interface):
+    url = TextLine(title=u'OpenID URL')
+
+class ChooseIdentityForm(Form):
+    label = u'OpenID Login'
+    form_fields = Fields(IChooseIdentitySchema)
+
+    @action(u"Login")
+    def login(self, action, data):
+        auth = getUtility(IOpenIDConsumer, context=self)
+        auth.login(self.request, data['url'])
+
+
+class OpenIDView(BrowserView):
+
+    def choose_identity(self):
+        return ChooseIdentityForm(self.context, self.request)()
+
+    def login(self):
+        auth = getUtility(IOpenIDConsumer, context=self)
+        auth.login(self.request)
+
+    def complete(self):
+        auth = getUtility(IOpenIDConsumer, context=self)
+        auth.complete(self.request)
+



More information about the Checkins mailing list