Commits

Daniel Holth committed 58e1666

initial commit

Comments (0)

Files changed (37)

+syntax:glob
+*~
+.*
+*.pyc
+*.o
+*.so
+*.log
+*.egg-info/*
+sstore/*
+0.0
+---
+
+-  Initial version.
+-  Completes the OpenID handshake.
+-  Has not been used in an application yet.
+A Creative Commons Attribution-Share Alike license applies to the OpenID
+widget (the bulk of openid.jinja2, associated css and javascript):
+
+    jQuery OpenID Plugin 1.1 Copyright 2009 Jarrett Vance
+    http://jvance.com/pages/jQueryOpenIdPlugin.xhtml
+
+    This work is licensed under a Creative Commons Attribution-Share Alike
+    3.0 Unported License.
+
+The rest of the project carries this license:
+
+Copyright (c) 2010, Daniel Holth
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+    * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+    * Neither the name of ponzi_openid nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ponzi_openid
+------------
+
+OpenID authentication written with the Pyramid web framework.
+
+"Release Early" edition.
+[app:ponzi_openid]
+use = egg:ponzi_openid
+reload_templates = true
+debug_authorization = false
+debug_notfound = false
+debug_templates = true
+default_locale_name = en
+
+session.type = memory
+
+openid.store_file_path = %(here)s/sstore
+
+jinja2.directories = ponzi_openid:templates
+
+[pipeline:main]
+pipeline =
+    egg:WebError#evalerror
+    ponzi_openid
+
+[server:main]
+use = egg:Paste#http
+host = 0.0.0.0
+port = 6543

ponzi_openid/__init__.py

+from pyramid.configuration import Configurator
+from ponzi_openid.models import get_root, OpenID
+
+def configure(config, template_extension="jinja2"):
+    """Add ponzi_openid views, resources to `config`.
+    
+    template_extension: Change this to use another templating
+    language. Only Jinja2 implementation included."""
+
+    config.add_static_view('static', 'ponzi_openid:static')
+
+    config.add_view(
+            view=".views.OpenID",
+            for_=".models.OpenID",
+            attr="index",
+            renderer="openid.%s" % (template_extension,))
+
+    config.add_view(
+            view=".views.OpenID",
+            for_=".models.OpenID",
+            request_method="POST",
+            attr="redirect",
+            renderer="openid_redirect.%s" % (template_extension,))
+
+    config.add_view(
+            name="success",
+            attr="success",
+            for_=".models.OpenID",
+            view=".views.OpenID",
+            renderer="openid_success.%s" % (template_extension,))
+
+def main(global_config, **settings):
+    """ This function returns a Pyramid WSGI application.
+    """
+
+    import logging
+    logging.basicConfig(level=logging.DEBUG)
+
+    config = Configurator(root_factory=get_root, settings=settings)
+    config.begin()
+
+    from pyramid_jinja2 import renderer_factory
+    config.add_renderer('.jinja2', renderer_factory)
+
+    # configure views, templates
+    configure(config) 
+
+    # configure session
+    import pyramid_beaker
+    session_factory = pyramid_beaker.session_factory_from_settings(settings)
+    config.set_session_factory(session_factory)
+
+    # configure OpenID-specific storage
+    import ponzi_openid.models
+    from openid.store import filestore
+    ponzi_openid.models.root.store = \
+        filestore.FileOpenIDStore(settings['openid.store_file_path'])
+
+    config.end()
+    return config.make_wsgi_app()
+

ponzi_openid/models.py

+class OpenID(object):
+    __name__ = u''
+    __parent__ = None
+
+    def __init__(self, name='', parent=None):
+        self.__name__ = name
+        self.__parent__ = parent
+
+root = OpenID('')
+
+def get_root(request):
+    """This is for testing. A real application would make an OpenID
+    object available in their URL space."""
+    return root

ponzi_openid/static/css/openid.css

+body {font-family: Arial;}
+fieldset {border-style:none;}
+img {border-style:none;}
+
+form.openid ul { text-align:center; list-style-type:none; display:inline;}
+form.openid ul li {float:left; padding:4px}
+form.openid ul li span {padding:0 1em 0 3px}
+form.openid fieldset {clear:both; padding:1em 0}
+form.openid div+fieldset {display:none}
+form.openid label {display:block; font-weight:bold; font-size:larger; margin-bottom:.5em}
+input[name=openid_username] {width:8em}
+input[name=openid_identifier] {width:18em}
+form.openid ul li.highlight { -moz-border-radius:4px; -webkit-border-radius:4px; background-color: #FD6}
+form.openid fieldset div {font-family:arial;-moz-border-radius:4px; -webkit-border-radius:4px; 
+                          background: #DCDCDC url(images/fadegrey.png); padding:10px;display:inline-block}
+form.openid input[type='submit'] {margin-left:1em;}
+
+.openid_logo{color:#F7931E;padding:6px 0px 8px 28px; background: url(images/openidico.png) no-repeat}
+
+#openid_login{float:left; font-size:larger; width:30%; margin:2em 1em; text-align:center}
+#openid_login div{margin-top:0.5em}
+#openid_login div+span{font-size:smaller}

ponzi_openid/static/images/aolW.png

Added
New image

ponzi_openid/static/images/blogger.png

Added
New image

ponzi_openid/static/images/claimid.png

Added
New image

ponzi_openid/static/images/facebookW.png

Added
New image

ponzi_openid/static/images/fadegrey.png

Added
New image

ponzi_openid/static/images/flickr.png

Added
New image

ponzi_openid/static/images/flickrW.png

Added
New image

ponzi_openid/static/images/googleW.png

Added
New image

ponzi_openid/static/images/livejournal.png

Added
New image

ponzi_openid/static/images/myopenid.png

Added
New image

ponzi_openid/static/images/myopenidW.png

Added
New image

ponzi_openid/static/images/myspaceW.png

Added
New image

ponzi_openid/static/images/openidW.png

Added
New image

ponzi_openid/static/images/openidico.png

Added
New image

ponzi_openid/static/images/technorati.png

Added
New image

ponzi_openid/static/images/verisign.png

Added
New image

ponzi_openid/static/images/vidoop.png

Added
New image

ponzi_openid/static/images/wordpress.png

Added
New image

ponzi_openid/static/images/yahooW.png

Added
New image

ponzi_openid/static/js/jquery.openid.js

+//jQuery OpenID Plugin 1.1 Copyright 2009 Jarrett Vance http://jvance.com/pages/jQueryOpenIdPlugin.xhtml
+$.fn.openid = function() {
+  var $this = $(this);
+  var $usr = $this.find('input[name=openid_username]');
+  var $id = $this.find('input[name=openid_identifier]');
+  var $front = $this.find('div:has(input[name=openid_username])>span:eq(0)');
+  var $end = $this.find('div:has(input[name=openid_username])>span:eq(1)');
+  var $usrfs = $this.find('fieldset:has(input[name=openid_username])');
+  var $idfs = $this.find('fieldset:has(input[name=openid_identifier])');
+
+  var submitusr = function() {
+    if ($usr.val().length < 1) {
+      $usr.focus();
+      return false;
+    }
+    $id.val($front.text() + $usr.val() + $end.text());
+    return true;
+  };
+
+  var submitid = function() {
+    if ($id.val().length < 1) {
+      $id.focus();
+      return false;
+    }
+    return true;
+
+  };
+  var direct = function() {
+    var $li = $(this);
+    $li.parent().find('li').removeClass('highlight');
+    $li.addClass('highlight');
+    $usrfs.fadeOut();
+    $idfs.fadeOut();
+
+    $this.unbind('submit').submit(function() {
+      $id.val($this.find("li.highlight span").text());
+    });
+    $this.submit();
+    return false;
+  };
+
+  var openid = function() {
+    var $li = $(this);
+    $li.parent().find('li').removeClass('highlight');
+    $li.addClass('highlight');
+    $usrfs.hide();
+    $idfs.show();
+    $id.focus();
+    $this.unbind('submit').submit(submitid);
+    return false;
+  };
+
+  var username = function() {
+    var $li = $(this);
+    $li.parent().find('li').removeClass('highlight');
+    $li.addClass('highlight');
+    $idfs.hide();
+    $usrfs.show();
+    $this.find('label[for=openid_username] span').text($li.attr("title"));
+    $front.text($li.find("span").text().split("username")[0]);
+    $end.text("").text($li.find("span").text().split("username")[1]);
+    $id.focus();
+    $this.unbind('submit').submit(submitusr);
+    return false;
+  };
+
+  $this.find('li.direct').click(direct);
+  $this.find('li.openid').click(openid);
+  $this.find('li.username').click(username);
+  $id.keypress(function(e) {
+    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
+      return submitid();
+    }
+  });
+  $usr.keypress(function(e) {
+    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
+      return submitusr();
+    }
+  });
+  $this.find('li span').hide();
+  $this.find('li').css('line-height', 0).css('cursor', 'pointer');
+  $this.find('li:eq(0)').click();
+  return this;
+}

ponzi_openid/templates/base.jinja2

+<!doctype html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+{% block head %}
+<title>{% block title %}Pyramid OpenID{% endblock %}</title>
+{% block css %}{% endblock%}
+{% endblock %}
+</head>
+<body>
+{% block body %}
+<p>Ponzi-OpenID demonstration templates.</p>
+{% endblock %}
+{% block js %}{% endblock%}
+</body>
+</html>

ponzi_openid/templates/openid.jinja2

+{% extends 'base.jinja2' %}
+{% block title %}jQuery OpenID Plugin{% endblock %}
+{% block css %}
+{{ super() }}
+<link rel="stylesheet" type="text/css" media="screen" href="{{ request.script_name }}/static/css/openid.css" />
+<!-- jQuery OpenID Plugin 1.1 Copyright 2009 Jarrett Vance http://jvance.com/pages/jQueryOpenIdPlugin.xhtml -->
+{% endblock %}
+{% block body %}
+	<h1>jQuery OpenID Plugin</h1>
+<address>By <a href="http://jvance.com">Jarrett Vance</a></address><br />
+
+<h2>Login (with javascript)</h2>
+<form class="openid" id="openid" method="post" action="{{ request.url }}"> 
+  <div><ul class="providers"> 
+  <li class="direct" title="Google"> 
+		<img src="{{ request.script_name }}/static/images/googleW.png" alt="icon" /><span>https://www.google.com/accounts/o8/id</span></li> 
+  <li class="direct" title="Yahoo"> 
+		<img src="{{ request.script_name }}/static/images/yahooW.png" alt="icon" /><span>http://yahoo.com/</span></li> 
+  <li class="username" title="AOL screen name"> 
+		<img src="{{ request.script_name }}/static/images/aolW.png" alt="icon" /><span>http://openid.aol.com/<strong>username</strong></span></li> 
+  <li class="username" title="MyOpenID user name"> 
+		<img src="{{ request.script_name }}/static/images/myopenid.png" alt="icon" /><span>http://<strong>username</strong>.myopenid.com/</span></li> 
+  <li class="username" title="Flickr user name"> 
+		<img src="{{ request.script_name }}/static/images/flickr.png" alt="icon" /><span>http://flickr.com/<strong>username</strong>/</span></li> 
+  <li class="username" title="Technorati user name"> 
+		<img src="{{ request.script_name }}/static/images/technorati.png" alt="icon" /><span>http://technorati.com/people/technorati/<strong>username</strong>/</span></li> 
+  <li class="username" title="Wordpress blog name"> 
+		<img src="{{ request.script_name }}/static/images/wordpress.png" alt="icon" /><span>http://<strong>username</strong>.wordpress.com</span></li> 
+  <li class="username" title="Blogger blog name"> 
+		<img src="{{ request.script_name }}/static/images/blogger.png" alt="icon" /><span>http://<strong>username</strong>.blogspot.com/</span></li> 
+  <li class="username" title="LiveJournal blog name"> 
+		<img src="{{ request.script_name }}/static/images/livejournal.png" alt="icon" /><span>http://<strong>username</strong>.livejournal.com</span></li> 
+  <li class="username" title="ClaimID user name"> 
+		<img src="{{ request.script_name }}/static/images/claimid.png" alt="icon" /><span>http://claimid.com/<strong>username</strong></span></li> 
+  <li class="username" title="Vidoop user name"> 
+		<img src="{{ request.script_name }}/static/images/vidoop.png" alt="icon" /><span>http://<strong>username</strong>.myvidoop.com/</span></li> 
+  <li class="username" title="Verisign user name"> 
+		<img src="{{ request.script_name }}/static/images/verisign.png" alt="icon" /><span>http://<strong>username</strong>.pip.verisignlabs.com/</span></li> 
+  </ul></div> 
+  <fieldset> 
+  <label for="openid_username">Enter your <span>Provider user name</span></label> 
+  <div><span></span><input type="text" name="openid_username" /><span></span> 
+  <input type="submit" value="Login" /></div> 
+  </fieldset> 
+  <fieldset> 
+  <label for="openid_identifier">Enter your <a class="openid_logo" href="http://openid.net">OpenID</a></label> 
+  <div><input type="text" name="openid_identifier" /> 
+  <input type="submit" value="Login" /></div> 
+  </fieldset> 
+</form>
+
+<p>Visit <a href="http://jvance.com/pages/jQueryOpenIdPlugin.xhtml">jQuery OpenID Plugin Homepage</a> for updates.</p>
+
+<p><a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://creativecommons.org/images/public/somerights20.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-Share Alike 3.0 Unported License</a>.</p>
+{% endblock %}
+{% block js %}
+{{ super() }}
+<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
+<script type="text/javascript" src="{{ request.script_name }}/static/js/jquery.openid.js"></script>
+<script type="text/javascript">  $(function() { $("form.openid:eq(0)").openid(); });</script>
+{% endblock %}

ponzi_openid/templates/openid_redirect.jinja2

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+    <title>Continue to your OpenID provider...</title>
+    <link rel="stylesheet" href="{{ request.script_name }}/static/css/style.css" type="text/css" media="screen" charset="utf-8" />
+    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+    <script type="text/javascript">
+      $(document).ready(function () {
+        $('form').submit();
+      });
+    </script>
+  </head>
+  <body>
+{{ openid_message|default('') }}
+  </body>
+</html>

ponzi_openid/templates/openid_success.jinja2

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Success!?</title>
+</head>
+<body>
+<h1>{{ status }}</h1>
+<p>Identified as {{ display_id }}</p>
+<p>REMOTE_USER = {{ request['REMOTE_USER'] }}</p>
+{% if sreg_resp %}
+<h2>Registration Data</h2>
+<table>
+  <thead><tr><th>Field</th><th>Value</th></tr></thead>
+  <tbody>
+    {% for k, v in sreg_data %}
+    <tr><td>{{ k }}</td><td>{{ v }}</td></tr>
+    {% endfor %}
+  </tbody>
+</table>
+{% endif %}
+{% if pape_resp %}
+<h2>Effective Auth Policies</h2>
+<ul>
+  {% if not pape_resp.auth_policies %}
+  <li>(none)</li>
+  {% endif %}
+  {% for policy_uri in pape_resp.auth_policies: %}
+  <li><tt>{{ policy_uri }}</tt></li>
+  {% endfor %}
+</ul>
+{% endif %}
+<a href="{{ request.application_url }}">{{ request.application_url }}</a>
+</body>
+</html>

ponzi_openid/tests.py

+import unittest
+
+from pyramid.configuration import Configurator
+from pyramid import testing
+
+class ViewTests(unittest.TestCase):
+    def setUp(self):
+        self.config = Configurator()
+        self.config.begin()
+
+    def tearDown(self):
+        self.config.end()
+
+    def test_my_view(self):
+        from ponzi_openid.views import OpenID
+        request = testing.DummyRequest()
+        info = OpenID(None, request).index()
+        self.assertEqual(info, {})
+
+

ponzi_openid/views.py

+from jinja2 import Markup
+from openid.consumer import consumer
+from openid.extensions import pape, sreg
+from pyramid.security import remember
+from pyramid.url import model_url
+from webob.exc import HTTPFound
+
+import logging
+log = logging.getLogger(__name__)
+
+class OpenID(object):
+
+    def __init__(self, context, request):
+        self.context=context
+        self.request=request
+
+    @property
+    def base_url(self):
+        return model_url(self.context, self.request)
+
+    def get_consumer(self, request=None):
+        """Create OpenID consumer."""
+        store = self.request.context.store
+        return consumer.Consumer(request.session, store)
+
+    def index(self):
+        return {}
+
+    def redirect(self):
+        """Redirect to OpenID provider or POST+JavaScript pseudo-redirect."""
+        c = self.get_consumer(self.request)
+        auth_request = c.begin(user_url=self.request.POST['openid_identifier'])
+        return_to = self.base_url.rstrip('/')+'/success'
+        # is this the place to set ax/sreg extensions?
+        if auth_request.shouldSendRedirect():
+            redirectURL = auth_request.redirectURL(
+                    self.request.application_url, 
+                    return_to=return_to
+                    )
+            return HTTPFound(location=redirectURL)
+        else: # send as a POST via an intermediary page:
+            message = auth_request.formMarkup(self.request.application_url+'/', 
+                    return_to=return_to)
+            return {'openid_message':Markup(message)}
+      
+    def success(self):
+        log.debug(self.request.url)
+        c = self.get_consumer(self.request)
+        # or request.params? (GET and POST)? can I ask for POST?
+        log.debug("Session: %r" % self.request.session)
+        info = c.complete(self.request.GET,
+                self.request.application_url + self.request.path_info)
+        log.debug("Session: %r" % self.request.session)
+        log.debug(info.status)
+        if info.status == consumer.SUCCESS:
+            # not unicode:
+            log.debug('Display identifier: ' + 
+                    (info.getDisplayIdentifier() or ''))
+            log.debug(info)
+
+            # may be broken for Python 2.6?
+            sreg_resp = sreg.SRegResponse.fromSuccessResponse(info)
+            pape_resp = pape.Response.fromSuccessResponse(info)
+
+            if info.endpoint.canonicalID:
+                log.debug('i-name WTF %s' % info.endpoint.canonicalID)
+
+            # need yet another step 'offer local account registration'
+            headers = remember(self.request, info.getDisplayIdentifier())
+            log.debug("Remember: %r" % (headers,))
+            self.request.response_headerlist = headers
+            self.request.session.save()
+            return {'status':info.status,
+                    'sreg_resp':sreg_resp, 'pape_resp':pape_resp, 
+                    'display_id':info.getDisplayIdentifier()}
+        
+        else:
+            self.request.session.save()
+            return HTTPFound(location=self.base_url)
+[nosetests]
+match=^test
+nocapture=1
+cover-package=ponzi_openid
+with-coverage=1
+cover-erase=1
+
+[compile_catalog]
+directory = ponzi_openid/locale
+domain = ponzi_openid
+statistics = true
+
+[extract_messages]
+add_comments = TRANSLATORS:
+output_file = ponzi_openid/locale/ponzi_openid.pot
+width = 80
+
+[init_catalog]
+domain = ponzi_openid
+input_file = ponzi_openid/locale/ponzi_openid.pot
+output_dir = ponzi_openid/locale
+
+[update_catalog]
+domain = ponzi_openid
+input_file = ponzi_openid/locale/ponzi_openid.pot
+output_dir = ponzi_openid/locale
+previous = true
+import os
+
+from setuptools import setup, find_packages
+
+here = os.path.abspath(os.path.dirname(__file__))
+README = open(os.path.join(here, 'README.txt')).read()
+CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
+
+requires = [ 
+'pyramid',
+'pyramid_beaker',
+'pyramid_jinja2',
+'python-openid',
+'WebError',
+]
+
+setup(name='ponzi_openid',
+      version='0.0',
+      description='ponzi_openid',
+      long_description=README + '\n\n' +  CHANGES,
+      classifiers=[
+        "Programming Language :: Python",
+        "Framework :: Pylons",
+        "Topic :: Internet :: WWW/HTTP",
+        "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
+        "License :: OSI Approved :: BSD License"
+        ],
+      author='Daniel Holth',
+      author_email='dholth@fastmail.fm',
+      url='http://bitbucket.org/dholth/ponzi_openid',
+      keywords='web pyramid pylons openid',
+      packages=find_packages(),
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=requires,
+      tests_require=requires,
+      test_suite="ponzi_openid",
+      entry_points = """\
+      [paste.app_factory]
+      main = ponzi_openid:main
+      """,
+      paster_plugins=['pyramid'],
+      )
+
Empty file added.