├── examples ├── openid │ ├── __init__.py │ ├── djopenid │ │ ├── __init__.py │ │ ├── server │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ ├── urls.py │ │ │ └── tests.py │ │ ├── consumer │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── urls.py │ │ ├── templates │ │ │ ├── consumer │ │ │ │ ├── request_form.html │ │ │ │ └── index.html │ │ │ ├── server │ │ │ │ ├── endpoint.html │ │ │ │ ├── idPage.html │ │ │ │ ├── pape_request_info.html │ │ │ │ ├── index.html │ │ │ │ └── trust.html │ │ │ ├── xrds.xml │ │ │ └── index.html │ │ ├── urls.py │ │ ├── views.py │ │ ├── manage.py │ │ ├── README │ │ └── settings.py │ ├── discover │ └── README ├── appengine │ ├── djangodemo │ │ ├── __init__.py │ │ ├── yosdemo │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── views.py │ │ ├── manage.py │ │ ├── urls.py │ │ └── settings.py │ ├── media │ │ ├── img │ │ │ ├── nrm-grey.png │ │ │ ├── indicator.gif │ │ │ └── lo-y-gsmall.gif │ │ ├── js │ │ │ └── simpleauth.js │ │ └── css │ │ │ └── common.css │ ├── app.yml │ ├── index.yaml │ ├── templates │ │ ├── index.html │ │ ├── simpleauth.html │ │ └── social.html │ └── djangodemo.py ├── opensocial │ ├── gifts │ │ ├── public │ │ │ ├── grail.png │ │ │ ├── snakes.png │ │ │ ├── dictator.png │ │ │ ├── style.css │ │ │ └── gadget.xml │ │ └── app.yaml │ ├── oauthbox │ │ ├── app.yaml │ │ └── main.py │ └── friends │ │ ├── app.yaml │ │ └── main.py └── yql.py ├── src ├── oauthlib │ ├── __init__.py │ └── LICENSE ├── openid │ ├── extensions │ │ ├── draft │ │ │ └── __init__.py │ │ ├── __init__.py │ │ └── oauth.py │ ├── consumer │ │ └── __init__.py │ ├── server │ │ └── __init__.py │ ├── sreg.py │ ├── store │ │ ├── __init__.py │ │ ├── nonce.py │ │ └── memstore.py │ ├── yadis │ │ ├── constants.py │ │ ├── __init__.py │ │ └── services.py │ ├── dh.py │ ├── __init__.py │ ├── extension.py │ └── kvform.py ├── simplejson │ ├── LICENSE │ ├── jsonfilter.py │ └── scanner.py ├── opensocial │ ├── simplejson │ │ ├── LICENSE │ │ ├── jsonfilter.py │ │ └── scanner.py │ ├── oauth │ │ └── LICENSE │ ├── test_data.py │ ├── errors.py │ ├── mock_http.py │ └── data.py └── yahoo │ ├── LICENSE │ ├── yql.py │ └── __init__.py ├── test ├── unit │ ├── openid │ │ ├── __init__.py │ │ ├── data │ │ │ ├── test_etxrd │ │ │ │ ├── not-xrds.xml │ │ │ │ ├── no-xrd.xml │ │ │ │ ├── status222.xrds │ │ │ │ ├── README │ │ │ │ ├── spoof1.xrds │ │ │ │ ├── spoof2.xrds │ │ │ │ ├── spoof3.xrds │ │ │ │ ├── delegated-20060809.xrds │ │ │ │ ├── valid-populated-xrds.xml │ │ │ │ ├── delegated-20060809-r1.xrds │ │ │ │ ├── delegated-20060809-r2.xrds │ │ │ │ ├── prefixsometimes.xrds │ │ │ │ ├── sometimesprefix.xrds │ │ │ │ └── subsegments.xrds │ │ │ ├── openid-1.2-consumer-sqlitestore.db │ │ │ ├── test_discover │ │ │ │ ├── yadis_no_delegate.xml │ │ │ │ ├── openid_no_delegate.html │ │ │ │ ├── openid2_xrds_no_local_id.xml │ │ │ │ ├── yadis_0entries.xml │ │ │ │ ├── openid2_xrds.xml │ │ │ │ ├── yadis_idp.xml │ │ │ │ ├── openid.html │ │ │ │ ├── openid2.html │ │ │ │ ├── openid_1_and_2.html │ │ │ │ ├── yadis_idp_delegate.xml │ │ │ │ ├── yadis_another_delegate.xml │ │ │ │ ├── openid_and_yadis.html │ │ │ │ ├── yadis_2_bad_local_id.xml │ │ │ │ ├── openid_1_and_2_xrds.xml │ │ │ │ ├── openid_1_and_2_xrds_bad_delegate.xml │ │ │ │ ├── yadis_2entries_idp.xml │ │ │ │ └── yadis_2entries_delegate.xml │ │ │ ├── example-xrds.xml │ │ │ ├── test1-discover.txt │ │ │ ├── accept.txt │ │ │ └── test1-parsehtml.txt │ │ ├── test_pape.py │ │ ├── test_htmldiscover.py │ │ ├── test_services.py │ │ ├── test_symbol.py │ │ ├── test_extension.py │ │ ├── test_urinorm.py │ │ ├── datadriven.py │ │ ├── test_xrires.py │ │ ├── dh.py │ │ ├── support.py │ │ ├── urinorm.txt │ │ ├── trustroot.py │ │ ├── test_parsehtml.py │ │ ├── linkparse.py │ │ ├── cryptutil.py │ │ ├── test_nonce.py │ │ ├── test_accept.py │ │ └── test_xri.py │ ├── opensocial │ │ ├── opensocial_tests │ │ │ ├── __init__.py │ │ │ ├── oauth_test.py │ │ │ ├── google_sandbox_test.py │ │ │ ├── myspace_test.py │ │ │ ├── orkut_test.py │ │ │ └── partuza_test.py │ │ ├── run_all_tests.py │ │ ├── run_unit_tests.py │ │ ├── run_system_tests.py │ │ └── module_test_runner.py │ └── yahoo │ │ └── test_yql.py └── run_unit_tests.py ├── CHANGELOG ├── setup.py └── LICENSE /examples/openid/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/oauthlib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/unit/openid/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/openid/djopenid/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/appengine/djangodemo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/openid/djopenid/server/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/openid/extensions/draft/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/openid/djopenid/consumer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/appengine/djangodemo/yosdemo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/not-xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /examples/openid/djopenid/consumer/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /examples/openid/djopenid/server/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Yahoo! Social SDK - Python - CHANGELOG 2 | ====================================== 3 | 4 | v1.0 - initial stable release 5 | -------------------------------------------------------------------------------- /examples/appengine/djangodemo/yosdemo/models.py: -------------------------------------------------------------------------------- 1 | # models.py 2 | 3 | from django.db import models 4 | 5 | from google.appengine.ext import db 6 | -------------------------------------------------------------------------------- /examples/appengine/media/img/nrm-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YahooArchive/yos-social-python/HEAD/examples/appengine/media/img/nrm-grey.png -------------------------------------------------------------------------------- /examples/appengine/media/img/indicator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YahooArchive/yos-social-python/HEAD/examples/appengine/media/img/indicator.gif -------------------------------------------------------------------------------- /examples/opensocial/gifts/public/grail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YahooArchive/yos-social-python/HEAD/examples/opensocial/gifts/public/grail.png -------------------------------------------------------------------------------- /examples/opensocial/gifts/public/snakes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YahooArchive/yos-social-python/HEAD/examples/opensocial/gifts/public/snakes.png -------------------------------------------------------------------------------- /examples/appengine/media/img/lo-y-gsmall.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YahooArchive/yos-social-python/HEAD/examples/appengine/media/img/lo-y-gsmall.gif -------------------------------------------------------------------------------- /examples/opensocial/gifts/public/dictator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YahooArchive/yos-social-python/HEAD/examples/opensocial/gifts/public/dictator.png -------------------------------------------------------------------------------- /examples/opensocial/oauthbox/app.yaml: -------------------------------------------------------------------------------- 1 | application: oauthbox 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | handlers: 7 | - url: .* 8 | script: main.py 9 | -------------------------------------------------------------------------------- /src/openid/extensions/__init__.py: -------------------------------------------------------------------------------- 1 | """OpenID Extension modules.""" 2 | 3 | __all__ = ['ax', 'pape', 'sreg'] 4 | 5 | from openid.extensions.draft import pape5 as pape 6 | -------------------------------------------------------------------------------- /test/unit/openid/data/openid-1.2-consumer-sqlitestore.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YahooArchive/yos-social-python/HEAD/test/unit/openid/data/openid-1.2-consumer-sqlitestore.db -------------------------------------------------------------------------------- /test/unit/opensocial/opensocial_tests/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | sys.path.insert(0, sys.path[0] + '/../src') 4 | 5 | logging.basicConfig(level=logging.INFO) -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/consumer/request_form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ html }} 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/opensocial/friends/app.yaml: -------------------------------------------------------------------------------- 1 | application: friends-sample 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | handlers: 7 | 8 | - url: .* 9 | script: main.py 10 | -------------------------------------------------------------------------------- /src/openid/consumer/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This package contains the portions of the library used only when 3 | implementing an OpenID consumer. 4 | """ 5 | 6 | __all__ = ['consumer', 'discover'] 7 | -------------------------------------------------------------------------------- /src/openid/server/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This package contains the portions of the library used only when 3 | implementing an OpenID server. See L{openid.server.server}. 4 | """ 5 | 6 | __all__ = ['server', 'trustroot'] 7 | -------------------------------------------------------------------------------- /src/openid/sreg.py: -------------------------------------------------------------------------------- 1 | """moved to L{openid.extensions.sreg}""" 2 | 3 | import warnings 4 | warnings.warn("openid.sreg has moved to openid.extensions.sreg", 5 | DeprecationWarning) 6 | 7 | from openid.extensions.sreg import * 8 | -------------------------------------------------------------------------------- /examples/appengine/djangodemo/yosdemo/views.py: -------------------------------------------------------------------------------- 1 | # views.py 2 | 3 | from django.http import HttpResponse 4 | 5 | def main(request): 6 | 7 | result = "demo .........................................................." 8 | 9 | return HttpResponse(result) 10 | -------------------------------------------------------------------------------- /examples/opensocial/gifts/app.yaml: -------------------------------------------------------------------------------- 1 | application: gifts-sample 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | handlers: 7 | 8 | - url: /public/(.*) 9 | static_files: public/\1 10 | upload: public/(.*) 11 | 12 | - url: .* 13 | script: main.py -------------------------------------------------------------------------------- /examples/openid/djopenid/consumer/urls.py: -------------------------------------------------------------------------------- 1 | 2 | from django.conf.urls.defaults import * 3 | 4 | urlpatterns = patterns( 5 | 'djopenid.consumer.views', 6 | (r'^$', 'startOpenID'), 7 | (r'^finish/$', 'finishOpenID'), 8 | (r'^xrds/$', 'rpXRDS'), 9 | ) 10 | -------------------------------------------------------------------------------- /src/openid/store/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This package contains the modules related to this library's use of 3 | persistent storage. 4 | 5 | @sort: interface, filestore, sqlstore, memstore 6 | """ 7 | 8 | __all__ = ['interface', 'filestore', 'sqlstore', 'memstore', 'nonce'] 9 | -------------------------------------------------------------------------------- /examples/appengine/app.yml: -------------------------------------------------------------------------------- 1 | application: yapdemo 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | handlers: 7 | - url: /media 8 | static_dir: media 9 | 10 | - url: /social/.* 11 | script: djangodemo.py 12 | 13 | - url: /.* 14 | script: yosdemo.py 15 | -------------------------------------------------------------------------------- /examples/openid/djopenid/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | urlpatterns = patterns( 4 | '', 5 | ('^$', 'djopenid.views.index'), 6 | ('^consumer/', include('djopenid.consumer.urls')), 7 | ('^server/', include('djopenid.server.urls')), 8 | ) 9 | -------------------------------------------------------------------------------- /test/unit/openid/test_pape.py: -------------------------------------------------------------------------------- 1 | 2 | from openid.extensions import pape 3 | 4 | import unittest 5 | 6 | class PapeImportTestCase(unittest.TestCase): 7 | def test_version(self): 8 | from openid.extensions.draft import pape5 9 | self.assert_(pape is pape5) 10 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/no-xrd.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/status222.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *x 5 | The subsegment does not exist 6 | 2006-08-18T00:02:35.000Z 7 | xri://= 8 | 9 | -------------------------------------------------------------------------------- /examples/openid/djopenid/server/urls.py: -------------------------------------------------------------------------------- 1 | 2 | from django.conf.urls.defaults import * 3 | 4 | urlpatterns = patterns( 5 | 'djopenid.server.views', 6 | (r'^$', 'server'), 7 | (r'^xrds/$', 'idpXrds'), 8 | (r'^processTrustResult/$', 'processTrustResult'), 9 | (r'^user/$', 'idPage'), 10 | (r'^endpoint/$', 'endpoint'), 11 | (r'^trust/$', 'trustPage'), 12 | ) 13 | -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/server/endpoint.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This is an OpenID server endpoint. Your browser should never 5 | actually request this page. 6 | 7 | {% if error %} 8 | The OpenID server has encountered an error: 9 |

10 | {{ error|escape }} 11 |

12 | {% endif %} 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/yadis_no_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | http://openid.net/signon/1.0 8 | http://www.myopenid.com/server 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/unit/openid/data/example-xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | http://example.com/ 10 | http://www.openidenabled.com/ 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid_no_delegate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 |

foo

9 | 10 | 11 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid2_xrds_no_local_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | http://specs.openid.net/auth/2.0/signon 8 | http://www.myopenid.com/server 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/yadis_0entries.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | http://is-not-openid.unittest/ 9 | http://noffing.unittest./ 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid2_xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | http://specs.openid.net/auth/2.0/signon 8 | http://www.myopenid.com/server 9 | http://smoker.myopenid.com/ 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/yadis_idp.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | http://specs.openid.net/auth/2.0/server 9 | http://www.myopenid.com/server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 |

foo

10 | 11 | 12 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 |

foo

10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | {% for type_uri in type_uris %} 9 | {{ type_uri|escape }} 10 | {% endfor %} 11 | {% for endpoint_url in endpoint_urls %} 12 | {{ endpoint_url }} 13 | {% endfor %} 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/openid/djopenid/views.py: -------------------------------------------------------------------------------- 1 | 2 | from djopenid import util 3 | from django.views.generic.simple import direct_to_template 4 | 5 | def index(request): 6 | consumer_url = util.getViewURL( 7 | request, 'djopenid.consumer.views.startOpenID') 8 | server_url = util.getViewURL(request, 'djopenid.server.views.server') 9 | 10 | return direct_to_template( 11 | request, 12 | 'index.html', 13 | {'consumer_url':consumer_url, 'server_url':server_url}) 14 | 15 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid_1_and_2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 |

foo

10 | 11 | 12 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/yadis_idp_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | http://specs.openid.net/auth/2.0/server 9 | http://www.myopenid.com/server 10 | http://smoker.myopenid.com/ 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/server/idPage.html: -------------------------------------------------------------------------------- 1 | {% extends "server/index.html" %} 2 | 3 | {% block head %} 4 | 6 | 7 | 8 | {% endblock %} 9 | 10 | {% block body %} 11 |

12 | This is the identity page for the OpenID that this server serves. 13 |

14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/yadis_another_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://openid.net/signon/1.0 10 | http://vroom.unittest/server 11 | http://smoker.myopenid.com/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/appengine/index.yaml: -------------------------------------------------------------------------------- 1 | indexes: 2 | 3 | # AUTOGENERATED 4 | 5 | # This index.yaml is automatically updated whenever the dev_appserver 6 | # detects that a new type of query is run. If you want to manage the 7 | # index.yaml file manually, remove the above marker line (the line 8 | # saying "# AUTOGENERATED"). If you want to manage some indexes 9 | # manually, move them above the marker line. The index.yaml file is 10 | # automatically uploaded to the admin console when you next deploy 11 | # your application using appcfg.py. 12 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid_and_yadis.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 | 10 |

foo

11 | 12 | 13 | -------------------------------------------------------------------------------- /src/openid/yadis/constants.py: -------------------------------------------------------------------------------- 1 | __all__ = ['YADIS_HEADER_NAME', 'YADIS_CONTENT_TYPE', 'YADIS_ACCEPT_HEADER'] 2 | from openid.yadis.accept import generateAcceptHeader 3 | 4 | YADIS_HEADER_NAME = 'X-XRDS-Location' 5 | YADIS_CONTENT_TYPE = 'application/xrds+xml' 6 | 7 | # A value suitable for using as an accept header when performing YADIS 8 | # discovery, unless the application has special requirements 9 | YADIS_ACCEPT_HEADER = generateAcceptHeader( 10 | ('text/html', 0.3), 11 | ('application/xhtml+xml', 0.5), 12 | (YADIS_CONTENT_TYPE, 1.0), 13 | ) 14 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/yadis_2_bad_local_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://specs.openid.net/auth/2.0/signon 10 | http://www.myopenid.com/server 11 | http://smoker.myopenid.com/ 12 | http://localid.mismatch.invalid/ 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/openid/djopenid/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from django.core.management import execute_manager 3 | try: 4 | import settings # Assumed to be in the same directory. 5 | except ImportError: 6 | import sys 7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) 8 | sys.exit(1) 9 | 10 | if __name__ == "__main__": 11 | execute_manager(settings) 12 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/README: -------------------------------------------------------------------------------- 1 | delegated-20060809.xrds - results from proxy.xri.net, determined by 2 | Drummond and Kevin to be incorrect. 3 | delegated-20060809-r1.xrds - Drummond's 1st correction 4 | delegated-20060809-r2.xrds - Drummond's 2nd correction 5 | 6 | spoofs: keturn's (=!E4)'s attempts to log in with Drummond's i-number (=!D2) 7 | spoof1.xrds 8 | spoof2.xrds 9 | spoof3.xrds - attempt to steal @!C0!D2 by having "at least one" CanonicalID 10 | match the $res service ProviderID. 11 | 12 | ref.xrds - resolving @ootao*test.ref, which refers to a neustar XRI. 13 | -------------------------------------------------------------------------------- /examples/appengine/djangodemo/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from django.core.management import execute_manager 3 | try: 4 | import settings # Assumed to be in the same directory. 5 | except ImportError: 6 | import sys 7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) 8 | sys.exit(1) 9 | 10 | if __name__ == "__main__": 11 | execute_manager(settings) 12 | -------------------------------------------------------------------------------- /examples/appengine/djangodemo/urls.py: -------------------------------------------------------------------------------- 1 | 2 | # urls.py 3 | 4 | from django.conf.urls.defaults import * 5 | 6 | from django.contrib import admin 7 | admin.autodiscover() 8 | 9 | urlpatterns = patterns('', 10 | 11 | (r"^$", "yosdemo.oauthdance.views.main"), 12 | (r"^index/", "yosdemo.oauthdance.views.main"), 13 | 14 | # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 15 | # to INSTALLED_APPS to enable admin documentation: 16 | (r'^admin/doc/', include('django.contrib.admindocs.urls')), 17 | 18 | # Uncomment the next line to enable the admin: 19 | (r'^admin/(.*)', admin.site.root), 20 | ) 21 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | __author__ = 'Dustin Whittle ' 4 | 5 | from distutils.core import setup 6 | 7 | setup( 8 | name='yos_social_sdk', 9 | version='0.0.2', 10 | description='Python client library for Yahoo! Social + Data REST APIs', 11 | author='Dustin Whittle', 12 | author_email='dustin@yahoo-inc.com', 13 | license='MIT', 14 | url='http://github.com/yahoo/yos-social-python/tree/master', 15 | packages=['yahoo', 'oauthlib', 'openid', 'simplejson'], 16 | package_dir={'yahoo': 'src/yahoo', 'oauthlib': 'src/oauthlib', 'openid': 'src/openid', 'simplejson': 'src/simplejson'} 17 | ) 18 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid_1_and_2_xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://specs.openid.net/auth/2.0/signon 10 | http://openid.net/signon/1.1 11 | http://www.myopenid.com/server 12 | http://smoker.myopenid.com/ 13 | http://smoker.myopenid.com/ 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/openid/yadis/__init__.py: -------------------------------------------------------------------------------- 1 | """Yadis. 2 | 3 | @see: U{http://www.openidenabled.com/yadis} 4 | """ 5 | 6 | __all__ = [ 7 | 'constants', 8 | 'discover', 9 | 'etxrd', 10 | 'filters', 11 | 'manager', 12 | 'parsehtml', 13 | 'services', 14 | 'xri', 15 | 'xrires', 16 | ] 17 | 18 | __version__ = '[library version:1.1.0-rc1]'[17:-1] 19 | 20 | # Parse the version info 21 | try: 22 | version_info = map(int, __version__.split('.')) 23 | except ValueError: 24 | version_info = (None, None, None) 25 | else: 26 | if len(version_info) != 3: 27 | version_info = (None, None, None) 28 | else: 29 | version_info = tuple(version_info) 30 | -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/server/pape_request_info.html: -------------------------------------------------------------------------------- 1 | {% if pape_request %} 2 | {% if pape_request.preferred_auth_policies %} 3 | The relying party requested the following PAPE policies be in effect: 4 | 5 | 10 | {% endif %} 11 | 12 | {% if pape_request.preferred_auth_level_types %} 13 | The relying party requested the following authentication level types: 14 | 15 | 20 | {% endif %} 21 | {% endif %} 22 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://specs.openid.net/auth/2.0/signon 10 | http://openid.net/signon/1.0 11 | http://openid.net/signon/1.1 12 | http://www.myopenid.com/server 13 | http://smoker.myopenid.com/ 14 | http://localid.mismatch.invalid/ 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/unit/openid/test_htmldiscover.py: -------------------------------------------------------------------------------- 1 | from openid.consumer.discover import OpenIDServiceEndpoint 2 | import datadriven 3 | 4 | class BadLinksTestCase(datadriven.DataDrivenTestCase): 5 | cases = [ 6 | '', 7 | "http://not.in.a.link.tag/", 8 | '', 9 | ] 10 | 11 | def __init__(self, data): 12 | datadriven.DataDrivenTestCase.__init__(self, data) 13 | self.data = data 14 | 15 | def runOneTest(self): 16 | actual = OpenIDServiceEndpoint.fromHTML('http://unused.url/', self.data) 17 | expected = [] 18 | self.failUnlessEqual(expected, actual) 19 | 20 | def pyUnitTests(): 21 | return datadriven.loadTests(__name__) 22 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/yadis_2entries_idp.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | =!1000 8 | 9 | 10 | http://specs.openid.net/auth/2.0/signon 11 | http://www.myopenid.com/server 12 | http://smoker.myopenid.com/ 13 | 14 | 15 | 16 | http://specs.openid.net/auth/2.0/server 17 | http://www.livejournal.com/openid/server.bml 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_discover/yadis_2entries_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | =!1000 8 | 9 | 10 | http://openid.net/signon/1.0 11 | http://www.myopenid.com/server 12 | http://smoker.myopenid.com/ 13 | 14 | 15 | 16 | http://openid.net/signon/1.0 17 | http://www.livejournal.com/openid/server.bml 18 | http://frank.livejournal.com/ 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/spoof1.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *keturn 5 | xri://= 6 | !E4 7 | =!E4 8 | 9 | 10 | xri://$res*auth*($v*2.0) 11 | http://keturn.example.com/resolve/ 12 | =!E4 13 | 14 | 15 | 16 | *isDrummond 17 | =!E4 18 | !D2 19 | =!D2 20 | 21 | http://openid.net/signon/1.0 22 | http://keturn.example.com/openid 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/spoof2.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *keturn 5 | xri://= 6 | !E4 7 | =!E4 8 | 9 | 10 | xri://$res*auth*($v*2.0) 11 | http://keturn.example.com/resolve/ 12 | xri://= 13 | 14 | 15 | 16 | *isDrummond 17 | xri://= 18 | !D2 19 | =!D2 20 | 21 | http://openid.net/signon/1.0 22 | http://keturn.example.com/openid 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/unit/openid/test_services.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from openid.yadis import services 4 | from openid.yadis.discover import DiscoveryFailure, DiscoveryResult 5 | 6 | 7 | class TestGetServiceEndpoints(unittest.TestCase): 8 | def setUp(self): 9 | self.orig_discover = services.discover 10 | services.discover = self.discover 11 | 12 | def tearDown(self): 13 | services.discover = self.orig_discover 14 | 15 | def discover(self, input_url): 16 | result = DiscoveryResult(input_url) 17 | result.response_text = "This is not XRDS text." 18 | return result 19 | 20 | def test_catchXRDSError(self): 21 | self.failUnlessRaises(DiscoveryFailure, 22 | services.getServiceEndpoints, 23 | "http://example.invalid/sometest") 24 | -------------------------------------------------------------------------------- /examples/appengine/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Yahoo! Developer Network: Google App Engine + Yahoo! OAuth Tokens 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Python OpenID Example 4 | 5 | 6 |

7 | This is a Django package which implements both an OpenID server 8 | and an OpenID consumer. These examples are provided with the 9 | OpenID library so you can learn how to use it in your own 10 | applications. 11 |

12 | 13 |

14 | To begin, click one of these links: 15 |

16 | 17 | 21 | 22 |

23 | Note: If you want to test the example consumer 24 | using the example server, you must start a separate server process 25 | for each application. 26 |

27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/opensocial/gifts/public/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: helvetica, arial, sans-serif; 3 | font-size: 10pt; 4 | } 5 | 6 | td { 7 | font-size: 10pt; 8 | } 9 | 10 | .gift { 11 | width: 48px; 12 | height: 48px; 13 | border: 1px solid green; 14 | } 15 | 16 | .thumbnail { 17 | width: 48px; 18 | height: 48px; 19 | border: 1px solid black; 20 | } 21 | 22 | .layout { 23 | } 24 | 25 | .layout td { 26 | text-align: center; 27 | vertical-align: top; 28 | } 29 | 30 | .list { 31 | border: 1px solid black; 32 | } 33 | 34 | .list td { 35 | padding: 4px; 36 | font-size: 8pt; 37 | text-align: center; 38 | vertical-align: middle; 39 | } 40 | 41 | .list .header { 42 | background-color: #CCDDFF; 43 | text-align: center; 44 | font-weight: bold; 45 | font-size: 10pt; 46 | } 47 | 48 | .list .sub-header td { 49 | text-align: center; 50 | font-weight: bold; 51 | font-size: 10pt; 52 | } 53 | -------------------------------------------------------------------------------- /examples/appengine/templates/simpleauth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Yahoo! Developer Network: OpenID + OAuth Popup 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/run_unit_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | __author__ = 'Dustin Whittle ' 4 | __version__ = '0.1' 5 | 6 | import os, sys, unittest 7 | 8 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'unit/yahoo/')) 9 | import test_oauth, test_application, test_yql 10 | 11 | class TestRunner(object): 12 | 13 | def __init__(self, modules_to_test=None): 14 | self.modules_to_test = modules_to_test or [test_oauth, test_application, test_yql] 15 | 16 | def RunTests(self): 17 | runner = unittest.TextTestRunner(verbosity=2) 18 | for module in self.modules_to_test: 19 | print '\nRunning tests in module:' + module.__name__ 20 | runner.run(unittest.defaultTestLoader.loadTestsFromModule(module)) 21 | 22 | def RunTests(): 23 | runner = TestRunner() 24 | runner.modules_to_test = [test_oauth, test_application, test_yql] 25 | runner.RunTests() 26 | 27 | if __name__ == '__main__': 28 | RunTests() 29 | -------------------------------------------------------------------------------- /test/unit/opensocial/run_all_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import run_system_tests 22 | import run_unit_tests 23 | 24 | 25 | def RunAllTests(): 26 | run_unit_tests.RunUnitTests() 27 | run_system_tests.RunSystemTests() 28 | 29 | 30 | if __name__ == '__main__': 31 | RunAllTests() -------------------------------------------------------------------------------- /test/unit/openid/test_symbol.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from openid import oidutil 4 | 5 | class SymbolTest(unittest.TestCase): 6 | def test_selfEquality(self): 7 | s = oidutil.Symbol('xxx') 8 | self.failUnlessEqual(s, s) 9 | 10 | def test_otherEquality(self): 11 | x = oidutil.Symbol('xxx') 12 | y = oidutil.Symbol('xxx') 13 | self.failUnlessEqual(x, y) 14 | 15 | def test_inequality(self): 16 | x = oidutil.Symbol('xxx') 17 | y = oidutil.Symbol('yyy') 18 | self.failIfEqual(x, y) 19 | 20 | def test_selfInequality(self): 21 | x = oidutil.Symbol('xxx') 22 | self.failIf(x != x) 23 | 24 | def test_otherInequality(self): 25 | x = oidutil.Symbol('xxx') 26 | y = oidutil.Symbol('xxx') 27 | self.failIf(x != y) 28 | 29 | def test_ne_inequality(self): 30 | x = oidutil.Symbol('xxx') 31 | y = oidutil.Symbol('yyy') 32 | self.failUnless(x != y) 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /test/unit/opensocial/run_unit_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import module_test_runner 22 | import opensocial_tests.client_test 23 | 24 | 25 | def RunUnitTests(): 26 | test_runner = module_test_runner.ModuleTestRunner() 27 | test_runner.modules = [opensocial_tests.client_test] 28 | test_runner.RunAllTests() 29 | 30 | if __name__ == '__main__': 31 | RunUnitTests() -------------------------------------------------------------------------------- /src/simplejson/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006 Bob Ippolito 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /src/opensocial/simplejson/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006 Bob Ippolito 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /src/oauthlib/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2007 Leah Culver 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/opensocial/oauth/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2007 Andy Smith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/spoof3.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *keturn 5 | xri://@ 6 | @E4 7 | @!E4 8 | 9 | 10 | xri://$res*auth*($v*2.0) 11 | http://keturn.example.com/resolve/ 12 | @!E4 13 | 14 | 15 | 16 | *is 17 | @!E4 18 | !D2 19 | =!C0 20 | =!E4!01 21 | 22 | xri://$res*auth*($v*2.0) 23 | http://keturn.example.com/resolve/ 24 | @!C0 25 | 26 | 27 | 28 | *drummond 29 | @!C0 30 | !D2 31 | @!C0!D2 32 | 33 | http://openid.net/signon/1.0 34 | http://keturn.example.com/openid 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/unit/yahoo/test_yql.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | __author__ = 'Dustin Whittle ' 4 | __version__ = '0.1' 5 | 6 | import os, sys, unittest 7 | 8 | # update sys path to include bundled modules with priority 9 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../../src')) 10 | 11 | import yahoo.yql 12 | 13 | class YQLTest(unittest.TestCase): 14 | 15 | def setUp(self): 16 | self.yql = yahoo.yql.YQLQuery() 17 | 18 | def test_query_valid(self): 19 | """ 20 | Tests the calling of yql public api given a valid query. 21 | """ 22 | response = self.yql.execute('select * from search.web where query="dustin whittle"') 23 | self.assertTrue('query' in response and 'results' in response['query']) 24 | 25 | def test_query_invalid(self): 26 | """ 27 | Tests error handling when calling a yql public api given an invalid query. 28 | """ 29 | response = self.yql.execute('select * from delicious.feeds.unknown_test') 30 | self.assertEquals('No definition found for Table delicious.feeds.unknown_test', response['error']['description']) 31 | 32 | def tearDown(self): 33 | self.yql = None 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /src/yahoo/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyrights for code authored by Yahoo! Inc. is licensed under the following terms: 3 | 4 | MIT License 5 | 6 | Copyright (c) 2009 Yahoo! Inc. All Rights Reserved. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/server/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Django OpenID Example Server 4 | 29 | {% block head %} 30 | 31 | {% endblock %} 32 | 33 | 34 | 35 | {% block body %} 36 |
37 | 38 |

39 | This is an example server built for the Django framework. It only 40 | authenticates one OpenID, which is also served by this 41 | application. The OpenID it serves is 42 | 43 |

44 | {{ user_url }}
45 |     
46 |

47 | 48 |
49 | {% endblock %} 50 | 51 | 52 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/delegated-20060809.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://!!1003 26 | !0000.0000.3B9A.CA01 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/valid-populated-xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | http://openid.net/signon/1.0 11 | http://www.myopenid.com/server 12 | http://josh.myopenid.com/ 13 | 14 | 15 | 16 | http://lid.netmesh.org/sso/2.0b5 17 | http://lid.netmesh.org/2.0b5 18 | http://mylid.net/josh 19 | 20 | 21 | 22 | http://openid.net/signon/1.0 23 | http://www.livejournal.com/openid/server.bml 24 | http://www.livejournal.com/users/nedthealpaca/ 25 | 26 | 27 | 28 | http://typekey.com/services/1.0 29 | joshhoyt 30 | 31 | 32 | 33 | http://openid.net/signon/1.0 34 | http://www.schtuff.com/openid 35 | http://users.schtuff.com/josh 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/delegated-20060809-r1.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | xri://!!1003 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://!!1003 26 | !0000.0000.3B9A.CA01 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/unit/openid/test_extension.py: -------------------------------------------------------------------------------- 1 | from openid import extension 2 | from openid import message 3 | 4 | import unittest 5 | 6 | class DummyExtension(extension.Extension): 7 | ns_uri = 'http://an.extension/' 8 | ns_alias = 'dummy' 9 | 10 | def getExtensionArgs(self): 11 | return {} 12 | 13 | class ToMessageTest(unittest.TestCase): 14 | def test_OpenID1(self): 15 | oid1_msg = message.Message(message.OPENID1_NS) 16 | ext = DummyExtension() 17 | ext.toMessage(oid1_msg) 18 | namespaces = oid1_msg.namespaces 19 | self.failUnless(namespaces.isImplicit(DummyExtension.ns_uri)) 20 | self.failUnlessEqual( 21 | DummyExtension.ns_uri, 22 | namespaces.getNamespaceURI(DummyExtension.ns_alias)) 23 | self.failUnlessEqual(DummyExtension.ns_alias, 24 | namespaces.getAlias(DummyExtension.ns_uri)) 25 | 26 | def test_OpenID2(self): 27 | oid2_msg = message.Message(message.OPENID2_NS) 28 | ext = DummyExtension() 29 | ext.toMessage(oid2_msg) 30 | namespaces = oid2_msg.namespaces 31 | self.failIf(namespaces.isImplicit(DummyExtension.ns_uri)) 32 | self.failUnlessEqual( 33 | DummyExtension.ns_uri, 34 | namespaces.getNamespaceURI(DummyExtension.ns_alias)) 35 | self.failUnlessEqual(DummyExtension.ns_alias, 36 | namespaces.getAlias(DummyExtension.ns_uri)) 37 | -------------------------------------------------------------------------------- /test/unit/opensocial/opensocial_tests/oauth_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import logging 22 | import unittest 23 | import urllib2 24 | 25 | import opensocial 26 | 27 | from opensocial import oauth 28 | 29 | 30 | class TestOAuth(unittest.TestCase): 31 | 32 | def setUp(self): 33 | self.config = opensocial.ContainerConfig( 34 | oauth_consumer_key='oauth.org:12345689', 35 | oauth_consumer_secret='not_a_secret', 36 | server_rpc_base='http://oauthbox.appspot.com/rpc') 37 | self.container = opensocial.ContainerContext(self.config) 38 | self.user_id = '101' 39 | 40 | def test_fetch(self): 41 | data = self.container.fetch_person(self.user_id) 42 | self.assertEquals(data.get_field('verified'), 'True') 43 | 44 | -------------------------------------------------------------------------------- /test/unit/opensocial/run_system_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import module_test_runner 22 | import opensocial_tests.orkut_test 23 | import opensocial_tests.myspace_test 24 | import opensocial_tests.partuza_test 25 | import opensocial_tests.oauth_test 26 | import opensocial_tests.google_sandbox_test 27 | 28 | def RunSystemTests(): 29 | test_runner = module_test_runner.ModuleTestRunner() 30 | test_runner.modules = [ 31 | opensocial_tests.orkut_test, 32 | opensocial_tests.myspace_test, 33 | opensocial_tests.partuza_test, 34 | opensocial_tests.oauth_test, 35 | opensocial_tests.google_sandbox_test, 36 | ] 37 | test_runner.RunAllTests() 38 | 39 | 40 | if __name__ == '__main__': 41 | RunSystemTests() 42 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/delegated-20060809-r2.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | xri://@!5BAD.2AA.3C72.AF46 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://@!5BAD.2AA.3C72.AF46 26 | !0000.0000.3B9A.CA01 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/prefixsometimes.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | xri://@!5BAD.2AA.3C72.AF46 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://@!5BAD.2AA.3C72.AF46 26 | !0000.0000.3B9A.CA01 27 | xri://@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/sometimesprefix.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | xri://@!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | xri://@!5BAD.2AA.3C72.AF46 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://@!5BAD.2AA.3C72.AF46 26 | !0000.0000.3B9A.CA01 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/unit/opensocial/module_test_runner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import unittest 22 | 23 | 24 | class ModuleTestRunner(object): 25 | 26 | def __init__(self, module_list=None, module_test_settings=None): 27 | self.modules = module_list or [] 28 | self.settings = module_test_settings or {} 29 | 30 | def RunAllTests(self): 31 | """Executes all tests present in the list of modules.""" 32 | runner = unittest.TextTestRunner() 33 | for module in self.modules: 34 | for setting, value in self.settings.iteritems(): 35 | try: 36 | setattr(module, setting, value) 37 | except AttributeError: 38 | pass 39 | print '\nRunning all tests in module', module.__name__ 40 | runner.run(unittest.defaultTestLoader.loadTestsFromModule(module)) -------------------------------------------------------------------------------- /test/unit/openid/test_urinorm.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | import openid.urinorm 4 | 5 | class UrinormTest(unittest.TestCase): 6 | def __init__(self, desc, case, expected): 7 | unittest.TestCase.__init__(self) 8 | self.desc = desc 9 | self.case = case 10 | self.expected = expected 11 | 12 | def shortDescription(self): 13 | return self.desc 14 | 15 | def runTest(self): 16 | try: 17 | actual = openid.urinorm.urinorm(self.case) 18 | except ValueError, why: 19 | self.assertEqual(self.expected, 'fail', why) 20 | else: 21 | self.assertEqual(actual, self.expected) 22 | 23 | def parse(cls, full_case): 24 | desc, case, expected = full_case.split('\n') 25 | case = unicode(case, 'utf-8') 26 | 27 | return cls(desc, case, expected) 28 | 29 | parse = classmethod(parse) 30 | 31 | 32 | def parseTests(test_data): 33 | result = [] 34 | 35 | cases = test_data.split('\n\n') 36 | for case in cases: 37 | case = case.strip() 38 | 39 | if case: 40 | result.append(UrinormTest.parse(case)) 41 | 42 | return result 43 | 44 | def pyUnitTests(): 45 | here = os.path.dirname(os.path.abspath(__file__)) 46 | test_data_file_name = os.path.join(here, 'urinorm.txt') 47 | test_data_file = file(test_data_file_name) 48 | test_data = test_data_file.read() 49 | test_data_file.close() 50 | 51 | tests = parseTests(test_data) 52 | return unittest.TestSuite(tests) 53 | -------------------------------------------------------------------------------- /test/unit/openid/datadriven.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import types 3 | 4 | class DataDrivenTestCase(unittest.TestCase): 5 | cases = [] 6 | 7 | def generateCases(cls): 8 | return cls.cases 9 | 10 | generateCases = classmethod(generateCases) 11 | 12 | def loadTests(cls): 13 | tests = [] 14 | for case in cls.generateCases(): 15 | if isinstance(case, tuple): 16 | test = cls(*case) 17 | elif isinstance(case, dict): 18 | test = cls(**case) 19 | else: 20 | test = cls(case) 21 | tests.append(test) 22 | return tests 23 | 24 | loadTests = classmethod(loadTests) 25 | 26 | def __init__(self, description): 27 | unittest.TestCase.__init__(self, 'runOneTest') 28 | self.description = description 29 | 30 | def shortDescription(self): 31 | return '%s for %s' % (self.__class__.__name__, self.description) 32 | 33 | def loadTests(module_name): 34 | loader = unittest.defaultTestLoader 35 | this_module = __import__(module_name, {}, {}, [None]) 36 | 37 | tests = [] 38 | for name in dir(this_module): 39 | obj = getattr(this_module, name) 40 | if (isinstance(obj, (type, types.ClassType)) and 41 | issubclass(obj, unittest.TestCase)): 42 | if hasattr(obj, 'loadTests'): 43 | tests.extend(obj.loadTests()) 44 | else: 45 | tests.append(loader.loadTestsFromTestCase(obj)) 46 | 47 | return unittest.TestSuite(tests) 48 | -------------------------------------------------------------------------------- /examples/openid/discover: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from openid.consumer.discover import discover, DiscoveryFailure 3 | from openid.fetchers import HTTPFetchingError 4 | 5 | names = [["server_url", "Server URL "], 6 | ["local_id", "Local ID "], 7 | ["canonicalID", "Canonical ID"], 8 | ] 9 | 10 | def show_services(user_input, normalized, services): 11 | print " Claimed identifier:", normalized 12 | if services: 13 | print " Discovered OpenID services:" 14 | for n, service in enumerate(services): 15 | print " %s." % (n,) 16 | for attr, name in names: 17 | val = getattr(service, attr, None) 18 | if val is not None: 19 | print " %s: %s" % (name, val) 20 | 21 | print " Type URIs:" 22 | for type_uri in service.type_uris: 23 | print " *", type_uri 24 | 25 | print 26 | 27 | else: 28 | print " No OpenID services found" 29 | print 30 | 31 | if __name__ == "__main__": 32 | import sys 33 | 34 | for user_input in sys.argv[1:]: 35 | print "=" * 50 36 | print "Running discovery on", user_input 37 | try: 38 | normalized, services = discover(user_input) 39 | except DiscoveryFailure, why: 40 | print "Discovery failed:", why 41 | print 42 | except HTTPFetchingError, why: 43 | print "HTTP request failed:", why 44 | print 45 | else: 46 | show_services(user_input, normalized, services) 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Yahoo! Social SDK 2 | Software License Agreement (BSD License) 3 | Copyright (c) 2009, Yahoo! Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use of this software in source and binary forms, with 7 | or without modification, are permitted provided that the following 8 | conditions are met: 9 | 10 | * Redistributions of source code must retain the above 11 | copyright notice, this list of conditions and the 12 | following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above 15 | copyright notice, this list of conditions and the 16 | following disclaimer in the documentation and/or other 17 | materials provided with the distribution. 18 | 19 | * Neither the name of Yahoo! Inc. nor the names of its 20 | contributors may be used to endorse or promote products 21 | derived from this software without specific prior 22 | written permission of Yahoo! Inc. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 28 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | -------------------------------------------------------------------------------- /src/openid/extensions/oauth.py: -------------------------------------------------------------------------------- 1 | from openid.extension import Extension 2 | from oauthlib import oauth 3 | 4 | __all__ = [ 5 | 'OauthAuthorizeTokenRequest', 6 | 'OauthAuthorizeTokenResponse', 7 | 'ns_uri', 8 | ] 9 | 10 | ns_uri = 'http://specs.openid.net/extensions/oauth/1.0' 11 | 12 | class OauthAuthorizeTokenRequest(Extension): 13 | 14 | ns_alias = 'oauth' 15 | 16 | def __init__(self, consumer, scope): 17 | Extension.__init__(self) 18 | self.consumer = consumer 19 | self.scope = scope 20 | 21 | def getExtensionArgs(self): 22 | args = {} 23 | 24 | args['consumer'] = self.consumer 25 | #args['scope'] = self.scope 26 | 27 | return args 28 | 29 | OauthAuthorizeTokenRequest.ns_uri = ns_uri 30 | 31 | class OauthAuthorizeTokenResponse(Extension): 32 | 33 | ns_alias = 'oauth' 34 | 35 | def __init__(self): 36 | Extension.__init__(self) 37 | self.authorized_request_token = None 38 | 39 | def fromSuccessResponse(cls, success_response): 40 | self = cls() 41 | 42 | #args = success_response.getSignedNS(self.ns_uri) 43 | 44 | args = success_response.extensionResponse(self.ns_uri, False) 45 | 46 | if (len(args) > 0): 47 | #Note that we're passing an empty string for the secret part since the oauth token secret 48 | #should be an empty string per section 10 of the extension spec 49 | self.authorized_request_token = oauth.OAuthToken(args['request_token'], '') 50 | 51 | return self 52 | 53 | fromSuccessResponse = classmethod(fromSuccessResponse) 54 | 55 | OauthAuthorizeTokenResponse.ns_uri = ns_uri 56 | -------------------------------------------------------------------------------- /src/opensocial/test_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | """This file provides test data explicitly for usage in library unit tests.""" 19 | 20 | 21 | __author__ = 'davidbyttow@google.com (David Byttow)' 22 | 23 | 24 | import httplib 25 | 26 | import data 27 | import simplejson 28 | 29 | 30 | VIEWER_FIELDS = { 31 | 'entry': {'id': '101', 32 | 'name': {'givenName': 'Kenny', 'familyName': ''}}, 33 | } 34 | 35 | FRIEND_COLLECTION_FIELDS = { 36 | 'startIndex': 0, 37 | 'totalResults': 3, 38 | 'entry': [ 39 | { 40 | 'id': '102', 41 | 'name': {'givenName': 'Stan', 'familyName': 'Marsh'}, 42 | }, 43 | { 44 | 'id': '103', 45 | 'name': {'givenName': 'Kyle', 'familyName': 'Broflovski'}, 46 | }, 47 | { 48 | 'id': '104', 49 | 'name': {'givenName': 'Eric', 'familyName': 'Cartman'}, 50 | } 51 | ] 52 | } 53 | 54 | VIEWER = data.Person.parse_json(VIEWER_FIELDS) 55 | 56 | FRIENDS = data.Collection.parse_json(FRIEND_COLLECTION_FIELDS, 57 | data.Person) 58 | 59 | NO_AUTH = { 'error' : { 'code': httplib.UNAUTHORIZED }} -------------------------------------------------------------------------------- /examples/opensocial/gifts/public/gadget.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 38 |
39 | ]]> 40 |
41 |
42 | 43 | -------------------------------------------------------------------------------- /src/openid/dh.py: -------------------------------------------------------------------------------- 1 | from openid import cryptutil 2 | from openid import oidutil 3 | 4 | def strxor(x, y): 5 | if len(x) != len(y): 6 | raise ValueError('Inputs to strxor must have the same length') 7 | 8 | xor = lambda (a, b): chr(ord(a) ^ ord(b)) 9 | return "".join(map(xor, zip(x, y))) 10 | 11 | class DiffieHellman(object): 12 | DEFAULT_MOD = 155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443L 13 | 14 | DEFAULT_GEN = 2 15 | 16 | def fromDefaults(cls): 17 | return cls(cls.DEFAULT_MOD, cls.DEFAULT_GEN) 18 | 19 | fromDefaults = classmethod(fromDefaults) 20 | 21 | def __init__(self, modulus, generator): 22 | self.modulus = long(modulus) 23 | self.generator = long(generator) 24 | 25 | self._setPrivate(cryptutil.randrange(1, modulus - 1)) 26 | 27 | def _setPrivate(self, private): 28 | """This is here to make testing easier""" 29 | self.private = private 30 | self.public = pow(self.generator, self.private, self.modulus) 31 | 32 | def usingDefaultValues(self): 33 | return (self.modulus == self.DEFAULT_MOD and 34 | self.generator == self.DEFAULT_GEN) 35 | 36 | def getSharedSecret(self, composite): 37 | return pow(composite, self.private, self.modulus) 38 | 39 | def xorSecret(self, composite, secret, hash_func): 40 | dh_shared = self.getSharedSecret(composite) 41 | hashed_dh_shared = hash_func(cryptutil.longToBinary(dh_shared)) 42 | return strxor(secret, hashed_dh_shared) 43 | -------------------------------------------------------------------------------- /src/simplejson/jsonfilter.py: -------------------------------------------------------------------------------- 1 | import simplejson 2 | import cgi 3 | 4 | class JSONFilter(object): 5 | def __init__(self, app, mime_type='text/x-json'): 6 | self.app = app 7 | self.mime_type = mime_type 8 | 9 | def __call__(self, environ, start_response): 10 | # Read JSON POST input to jsonfilter.json if matching mime type 11 | response = {'status': '200 OK', 'headers': []} 12 | def json_start_response(status, headers): 13 | response['status'] = status 14 | response['headers'].extend(headers) 15 | environ['jsonfilter.mime_type'] = self.mime_type 16 | if environ.get('REQUEST_METHOD', '') == 'POST': 17 | if environ.get('CONTENT_TYPE', '') == self.mime_type: 18 | args = [_ for _ in [environ.get('CONTENT_LENGTH')] if _] 19 | data = environ['wsgi.input'].read(*map(int, args)) 20 | environ['jsonfilter.json'] = simplejson.loads(data) 21 | res = simplejson.dumps(self.app(environ, json_start_response)) 22 | jsonp = cgi.parse_qs(environ.get('QUERY_STRING', '')).get('jsonp') 23 | if jsonp: 24 | content_type = 'text/javascript' 25 | res = ''.join(jsonp + ['(', res, ')']) 26 | elif 'Opera' in environ.get('HTTP_USER_AGENT', ''): 27 | # Opera has bunk XMLHttpRequest support for most mime types 28 | content_type = 'text/plain' 29 | else: 30 | content_type = self.mime_type 31 | headers = [ 32 | ('Content-type', content_type), 33 | ('Content-length', len(res)), 34 | ] 35 | headers.extend(response['headers']) 36 | start_response(response['status'], headers) 37 | return [res] 38 | 39 | def factory(app, global_conf, **kw): 40 | return JSONFilter(app, **kw) 41 | -------------------------------------------------------------------------------- /src/opensocial/simplejson/jsonfilter.py: -------------------------------------------------------------------------------- 1 | import simplejson 2 | import cgi 3 | 4 | class JSONFilter(object): 5 | def __init__(self, app, mime_type='text/x-json'): 6 | self.app = app 7 | self.mime_type = mime_type 8 | 9 | def __call__(self, environ, start_response): 10 | # Read JSON POST input to jsonfilter.json if matching mime type 11 | response = {'status': '200 OK', 'headers': []} 12 | def json_start_response(status, headers): 13 | response['status'] = status 14 | response['headers'].extend(headers) 15 | environ['jsonfilter.mime_type'] = self.mime_type 16 | if environ.get('REQUEST_METHOD', '') == 'POST': 17 | if environ.get('CONTENT_TYPE', '') == self.mime_type: 18 | args = [_ for _ in [environ.get('CONTENT_LENGTH')] if _] 19 | data = environ['wsgi.input'].read(*map(int, args)) 20 | environ['jsonfilter.json'] = simplejson.loads(data) 21 | res = simplejson.dumps(self.app(environ, json_start_response)) 22 | jsonp = cgi.parse_qs(environ.get('QUERY_STRING', '')).get('jsonp') 23 | if jsonp: 24 | content_type = 'text/javascript' 25 | res = ''.join(jsonp + ['(', res, ')']) 26 | elif 'Opera' in environ.get('HTTP_USER_AGENT', ''): 27 | # Opera has bunk XMLHttpRequest support for most mime types 28 | content_type = 'text/plain' 29 | else: 30 | content_type = self.mime_type 31 | headers = [ 32 | ('Content-type', content_type), 33 | ('Content-length', len(res)), 34 | ] 35 | headers.extend(response['headers']) 36 | start_response(response['status'], headers) 37 | return [res] 38 | 39 | def factory(app, global_conf, **kw): 40 | return JSONFilter(app, **kw) 41 | -------------------------------------------------------------------------------- /src/openid/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This package is an implementation of the OpenID specification in 3 | Python. It contains code for both server and consumer 4 | implementations. For information on implementing an OpenID consumer, 5 | see the C{L{openid.consumer.consumer}} module. For information on 6 | implementing an OpenID server, see the C{L{openid.server.server}} 7 | module. 8 | 9 | @contact: U{dev@lists.openidenabled.com 10 | } 11 | 12 | @copyright: (C) 2005-2008 JanRain, Inc. 13 | 14 | @license: Licensed under the Apache License, Version 2.0 (the "License"); 15 | you may not use this file except in compliance with the License. 16 | You may obtain a copy of the License at 17 | U{http://www.apache.org/licenses/LICENSE-2.0} 18 | 19 | Unless required by applicable law or agreed to in writing, software 20 | distributed under the License is distributed on an "AS IS" BASIS, 21 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | See the License for the specific language governing permissions 23 | and limitations under the License. 24 | """ 25 | 26 | __version__ = '[library version:2.2.1]'[17:-1] 27 | 28 | __all__ = [ 29 | 'association', 30 | 'consumer', 31 | 'cryptutil', 32 | 'dh', 33 | 'extension', 34 | 'extensions', 35 | 'fetchers', 36 | 'kvform', 37 | 'message', 38 | 'oidutil', 39 | 'server', 40 | 'sreg', 41 | 'store', 42 | 'urinorm', 43 | 'yadis', 44 | ] 45 | 46 | # Parse the version info 47 | try: 48 | version_info = map(int, __version__.split('.')) 49 | except ValueError: 50 | version_info = (None, None, None) 51 | else: 52 | if len(version_info) != 3: 53 | version_info = (None, None, None) 54 | else: 55 | version_info = tuple(version_info) 56 | -------------------------------------------------------------------------------- /test/unit/openid/test_xrires.py: -------------------------------------------------------------------------------- 1 | 2 | from unittest import TestCase 3 | from openid.yadis import xrires 4 | 5 | class ProxyQueryTestCase(TestCase): 6 | def setUp(self): 7 | self.proxy_url = 'http://xri.example.com/' 8 | self.proxy = xrires.ProxyResolver(self.proxy_url) 9 | self.servicetype = 'xri://+i-service*(+forwarding)*($v*1.0)' 10 | self.servicetype_enc = 'xri%3A%2F%2F%2Bi-service%2A%28%2Bforwarding%29%2A%28%24v%2A1.0%29' 11 | 12 | 13 | def test_proxy_url(self): 14 | st = self.servicetype 15 | ste = self.servicetype_enc 16 | args_esc = "_xrd_r=application%2Fxrds%2Bxml&_xrd_t=" + ste 17 | pqu = self.proxy.queryURL 18 | h = self.proxy_url 19 | self.failUnlessEqual(h + '=foo?' + args_esc, pqu('=foo', st)) 20 | self.failUnlessEqual(h + '=foo/bar?baz&' + args_esc, 21 | pqu('=foo/bar?baz', st)) 22 | self.failUnlessEqual(h + '=foo/bar?baz=quux&' + args_esc, 23 | pqu('=foo/bar?baz=quux', st)) 24 | self.failUnlessEqual(h + '=foo/bar?mi=fa&so=la&' + args_esc, 25 | pqu('=foo/bar?mi=fa&so=la', st)) 26 | 27 | # With no service endpoint selection. 28 | args_esc = "_xrd_r=application%2Fxrds%2Bxml%3Bsep%3Dfalse" 29 | self.failUnlessEqual(h + '=foo?' + args_esc, pqu('=foo', None)) 30 | 31 | 32 | def test_proxy_url_qmarks(self): 33 | st = self.servicetype 34 | ste = self.servicetype_enc 35 | args_esc = "_xrd_r=application%2Fxrds%2Bxml&_xrd_t=" + ste 36 | pqu = self.proxy.queryURL 37 | h = self.proxy_url 38 | self.failUnlessEqual(h + '=foo/bar??' + args_esc, pqu('=foo/bar?', st)) 39 | self.failUnlessEqual(h + '=foo/bar????' + args_esc, 40 | pqu('=foo/bar???', st)) 41 | -------------------------------------------------------------------------------- /src/openid/extension.py: -------------------------------------------------------------------------------- 1 | from openid import message as message_module 2 | 3 | class Extension(object): 4 | """An interface for OpenID extensions. 5 | 6 | @ivar ns_uri: The namespace to which to add the arguments for this 7 | extension 8 | """ 9 | ns_uri = None 10 | ns_alias = None 11 | 12 | def getExtensionArgs(self): 13 | """Get the string arguments that should be added to an OpenID 14 | message for this extension. 15 | 16 | @returns: A dictionary of completely non-namespaced arguments 17 | to be added. For example, if the extension's alias is 18 | 'uncle', and this method returns {'meat':'Hot Rats'}, the 19 | final message will contain {'openid.uncle.meat':'Hot Rats'} 20 | """ 21 | raise NotImplementedError 22 | 23 | def toMessage(self, message=None): 24 | """Add the arguments from this extension to the provided 25 | message, or create a new message containing only those 26 | arguments. 27 | 28 | @returns: The message with the extension arguments added 29 | """ 30 | if message is None: 31 | warnings.warn('Passing None to Extension.toMessage is deprecated. ' 32 | 'Creating a message assuming you want OpenID 2.', 33 | DeprecationWarning, stacklevel=2) 34 | message = message_module.Message(message_module.OPENID2_NS) 35 | 36 | implicit = message.isOpenID1() 37 | 38 | try: 39 | message.namespaces.addAlias(self.ns_uri, self.ns_alias, 40 | implicit=implicit) 41 | except KeyError: 42 | if message.namespaces.getAlias(self.ns_uri) != self.ns_alias: 43 | raise 44 | 45 | message.updateArgs(self.ns_uri, self.getExtensionArgs()) 46 | return message 47 | -------------------------------------------------------------------------------- /src/opensocial/errors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | """Errors used on the Python opensocial client libraries.""" 19 | 20 | 21 | __author__ = 'davidbyttow@google.com (David Byttow)' 22 | 23 | 24 | class Error(Exception): 25 | """Base opensocial.client error type.""" 26 | 27 | 28 | class ConfigError(Error): 29 | """Raised when the client has not been configured properly.""" 30 | 31 | 32 | class BadResponseError(Error): 33 | """Raised when the status code is not OK or data returned is invalid.""" 34 | def __init__(self, code, message=""): 35 | self.code = code 36 | self.message = message 37 | 38 | def __str__(self): 39 | return "Bad Response: %d - %s" % (self.code, self.message) 40 | 41 | 42 | class BadRequestError(Error): 43 | """Raised when a malformed request is detected.""" 44 | def __init__(self, response): 45 | self.response = response 46 | 47 | def __str__(self): 48 | return 'STATUS: %d\nRESPONSE: %s' % (self.response.status, 49 | self.response.content) 50 | 51 | 52 | class UnauthorizedRequestError(Error): 53 | """Raised when a request failed due to bad authorization credentials.""" 54 | def __init__(self, response): 55 | self.response = response 56 | -------------------------------------------------------------------------------- /test/unit/opensocial/opensocial_tests/google_sandbox_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'kurrik@google.com (Arne Roomann-Kurrik)' 19 | 20 | 21 | import unittest 22 | import urllib2 23 | 24 | import opensocial 25 | from opensocial import errors 26 | 27 | class TestGoogleSandbox(unittest.TestCase): 28 | 29 | def setUp(self): 30 | self.config = opensocial.ContainerConfig( 31 | oauth_consumer_key='google.com:249475676706', 32 | oauth_consumer_secret='fWPcoVP6DOLVqZOF2HH+ihU2', 33 | server_rpc_base='http://www-opensocial-sandbox.googleusercontent.com/api/rpc', 34 | ) 35 | self.container = opensocial.ContainerContext(self.config) 36 | self.user_id = '101911127807751034357' 37 | 38 | 39 | def test_invalid_request(self): 40 | # Invalid ID 41 | req_error1 = opensocial.FetchAppDataRequest('asfsdkfaja','@self') 42 | 43 | # Single response raises an Error 44 | self.assertRaises(errors.Error, self.container.send_request, req_error1) 45 | 46 | batch = opensocial.RequestBatch() 47 | batch.add_request('er1', req_error1) 48 | batch.send(self.container) 49 | 50 | # Batch responses return an Error 51 | self.assertTrue(isinstance(batch.get('er1'), errors.Error)) 52 | -------------------------------------------------------------------------------- /test/unit/openid/dh.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from openid.dh import DiffieHellman, strxor 3 | 4 | def test_strxor(): 5 | NUL = '\x00' 6 | 7 | cases = [ 8 | (NUL, NUL, NUL), 9 | ('\x01', NUL, '\x01'), 10 | ('a', 'a', NUL), 11 | ('a', NUL, 'a'), 12 | ('abc', NUL * 3, 'abc'), 13 | ('x' * 10, NUL * 10, 'x' * 10), 14 | ('\x01', '\x02', '\x03'), 15 | ('\xf0', '\x0f', '\xff'), 16 | ('\xff', '\x0f', '\xf0'), 17 | ] 18 | 19 | for aa, bb, expected in cases: 20 | actual = strxor(aa, bb) 21 | assert actual == expected, (aa, bb, expected, actual) 22 | 23 | exc_cases = [ 24 | ('', 'a'), 25 | ('foo', 'ba'), 26 | (NUL * 3, NUL * 4), 27 | (''.join(map(chr, xrange(256))), 28 | ''.join(map(chr, xrange(128)))), 29 | ] 30 | 31 | for aa, bb in exc_cases: 32 | try: 33 | unexpected = strxor(aa, bb) 34 | except ValueError: 35 | pass 36 | else: 37 | assert False, 'Expected ValueError, got %r' % (unexpected,) 38 | 39 | def test1(): 40 | dh1 = DiffieHellman.fromDefaults() 41 | dh2 = DiffieHellman.fromDefaults() 42 | secret1 = dh1.getSharedSecret(dh2.public) 43 | secret2 = dh2.getSharedSecret(dh1.public) 44 | assert secret1 == secret2 45 | return secret1 46 | 47 | def test_exchange(): 48 | s1 = test1() 49 | s2 = test1() 50 | assert s1 != s2 51 | 52 | def test_public(): 53 | f = file(os.path.join(os.path.dirname(__file__), 'dhpriv')) 54 | dh = DiffieHellman.fromDefaults() 55 | try: 56 | for line in f: 57 | parts = line.strip().split(' ') 58 | dh._setPrivate(long(parts[0])) 59 | 60 | assert dh.public == long(parts[1]) 61 | finally: 62 | f.close() 63 | 64 | def test(): 65 | test_exchange() 66 | test_public() 67 | test_strxor() 68 | 69 | if __name__ == '__main__': 70 | test() 71 | -------------------------------------------------------------------------------- /test/unit/openid/support.py: -------------------------------------------------------------------------------- 1 | from openid import message 2 | from openid import oidutil 3 | 4 | class OpenIDTestMixin(object): 5 | def failUnlessOpenIDValueEquals(self, msg, key, expected, ns=None): 6 | if ns is None: 7 | ns = message.OPENID_NS 8 | 9 | actual = msg.getArg(ns, key) 10 | error_format = 'Wrong value for openid.%s: expected=%s, actual=%s' 11 | error_message = error_format % (key, expected, actual) 12 | self.failUnlessEqual(expected, actual, error_message) 13 | 14 | def failIfOpenIDKeyExists(self, msg, key, ns=None): 15 | if ns is None: 16 | ns = message.OPENID_NS 17 | 18 | actual = msg.getArg(ns, key) 19 | error_message = 'openid.%s unexpectedly present: %s' % (key, actual) 20 | self.failIf(actual is not None, error_message) 21 | 22 | class CatchLogs(object): 23 | def setUp(self): 24 | self.old_logger = oidutil.log 25 | oidutil.log = self.gotLogMessage 26 | self.messages = [] 27 | 28 | def gotLogMessage(self, message): 29 | self.messages.append(message) 30 | 31 | def tearDown(self): 32 | oidutil.log = self.old_logger 33 | 34 | def failUnlessLogMatches(self, *prefixes): 35 | """ 36 | Check that the log messages contained in self.messages have 37 | prefixes in *prefixes. Raise AssertionError if not, or if the 38 | number of prefixes is different than the number of log 39 | messages. 40 | """ 41 | assert len(prefixes) == len(self.messages), \ 42 | "Expected log prefixes %r, got %r" % (prefixes, 43 | self.messages) 44 | 45 | for prefix, message in zip(prefixes, self.messages): 46 | assert message.startswith(prefix), \ 47 | "Expected log prefixes %r, got %r" % (prefixes, 48 | self.messages) 49 | 50 | def failUnlessLogEmpty(self): 51 | self.failUnlessLogMatches() 52 | -------------------------------------------------------------------------------- /src/openid/yadis/services.py: -------------------------------------------------------------------------------- 1 | # -*- test-case-name: openid.test.test_services -*- 2 | 3 | from openid.yadis.filters import mkFilter 4 | from openid.yadis.discover import discover, DiscoveryFailure 5 | from openid.yadis.etxrd import parseXRDS, iterServices, XRDSError 6 | 7 | def getServiceEndpoints(input_url, flt=None): 8 | """Perform the Yadis protocol on the input URL and return an 9 | iterable of resulting endpoint objects. 10 | 11 | @param flt: A filter object or something that is convertable to 12 | a filter object (using mkFilter) that will be used to generate 13 | endpoint objects. This defaults to generating BasicEndpoint 14 | objects. 15 | 16 | @param input_url: The URL on which to perform the Yadis protocol 17 | 18 | @return: The normalized identity URL and an iterable of endpoint 19 | objects generated by the filter function. 20 | 21 | @rtype: (str, [endpoint]) 22 | 23 | @raises DiscoveryFailure: when Yadis fails to obtain an XRDS document. 24 | """ 25 | result = discover(input_url) 26 | try: 27 | endpoints = applyFilter(result.normalized_uri, 28 | result.response_text, flt) 29 | except XRDSError, err: 30 | raise DiscoveryFailure(str(err), None) 31 | return (result.normalized_uri, endpoints) 32 | 33 | def applyFilter(normalized_uri, xrd_data, flt=None): 34 | """Generate an iterable of endpoint objects given this input data, 35 | presumably from the result of performing the Yadis protocol. 36 | 37 | @param normalized_uri: The input URL, after following redirects, 38 | as in the Yadis protocol. 39 | 40 | 41 | @param xrd_data: The XML text the XRDS file fetched from the 42 | normalized URI. 43 | @type xrd_data: str 44 | 45 | """ 46 | flt = mkFilter(flt) 47 | et = parseXRDS(xrd_data) 48 | 49 | endpoints = [] 50 | for service_element in iterServices(et): 51 | endpoints.extend( 52 | flt.getServiceEndpoints(normalized_uri, service_element)) 53 | 54 | return endpoints 55 | -------------------------------------------------------------------------------- /test/unit/opensocial/opensocial_tests/myspace_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import unittest 22 | 23 | import opensocial 24 | 25 | 26 | class TestMySpace(unittest.TestCase): 27 | 28 | def setUp(self): 29 | self.config = opensocial.ContainerConfig( 30 | oauth_consumer_key='http://opensocial-resources.googlecode.com/svn/samples/rest_rpc/sample.xml', 31 | oauth_consumer_secret='6a838d107daf4d09b7d446422f5e7a81', 32 | server_rest_base='http://api.myspace.com/v2') 33 | self.container = opensocial.ContainerContext(self.config) 34 | self.user_id = '425505213' 35 | 36 | def test_fetch_person(self): 37 | me = self.container.fetch_person(self.user_id) 38 | self.assertEquals('myspace.com:' + self.user_id, me.get_id()) 39 | self.assertEquals('API', me.get_display_name()) 40 | 41 | def test_fetch_person_fields(self): 42 | me = self.container.fetch_person(self.user_id, ['gender']) 43 | self.assertEquals('Male', me.get_field('gender')) 44 | 45 | def test_fetch_friends(self): 46 | friends = self.container.fetch_friends(self.user_id) 47 | self.assertEquals(5, len(friends)) 48 | self.assertEquals(1, friends.startIndex) 49 | self.assertEquals(5, friends.totalResults) 50 | self.assertEquals('myspace.com:6221', friends[0].get_id()) 51 | self.assertEquals('myspace.com:431404430', friends[1].get_id()) 52 | -------------------------------------------------------------------------------- /examples/openid/djopenid/README: -------------------------------------------------------------------------------- 1 | 2 | DJANGO EXAMPLE PACKAGE 3 | ====================== 4 | 5 | This package implements an example consumer and server for the Django 6 | Python web framework. You can get Django (and learn more about it) at 7 | 8 | http://www.djangoproject.com/ 9 | 10 | SETUP 11 | ===== 12 | 13 | 1. Install the OpenID library, version 2.0.0 or later. 14 | 15 | 2. Install Django 0.95.1. 16 | 17 | If you find that the examples run on even newer versions of 18 | Django, please let us know! 19 | 20 | 3. Modify djopenid/settings.py appropriately; you may wish to change 21 | the database type or path, although the default settings should be 22 | sufficient for most systems. 23 | 24 | 4. In examples/djopenid/ run: 25 | 26 | python manage.py syncdb 27 | 28 | 5. To run the example consumer or server, run 29 | 30 | python manage.py runserver PORT 31 | 32 | where PORT is the port number on which to listen. 33 | 34 | Note that if you want to try both the consumer and server at the 35 | same time, run the command twice with two different values for 36 | PORT. 37 | 38 | 6. Point your web browser at the server at 39 | 40 | http://localhost:PORT/ 41 | 42 | to begin. 43 | 44 | ABOUT THE CODE 45 | ============== 46 | 47 | The example server and consumer code provided in this package are 48 | intended to be instructional in the use of this OpenID library. While 49 | it is not recommended to use the example code in production, the code 50 | should be sufficient to explain the general use of the library. 51 | 52 | If you aren't familiar with the Django web framework, you can quickly 53 | start looking at the important code by looking in the 'views' modules: 54 | 55 | djopenid.consumer.views 56 | djopenid.server.views 57 | 58 | Each view is a python callable that responds to an HTTP request. 59 | Regardless of whether you use a framework, your application should 60 | look similar to these example applications. 61 | 62 | CONTACT 63 | ======= 64 | 65 | Please send bug reports, patches, and other feedback to 66 | 67 | dev@lists.openidenabled.com 68 | -------------------------------------------------------------------------------- /test/unit/openid/urinorm.txt: -------------------------------------------------------------------------------- 1 | Already normal form 2 | http://example.com/ 3 | http://example.com/ 4 | 5 | Add a trailing slash 6 | http://example.com 7 | http://example.com/ 8 | 9 | Remove an empty port segment 10 | http://example.com:/ 11 | http://example.com/ 12 | 13 | Remove a default port segment 14 | http://example.com:80/ 15 | http://example.com/ 16 | 17 | Capitalization in host names 18 | http://wWw.exaMPLE.COm/ 19 | http://www.example.com/ 20 | 21 | Capitalization in scheme names 22 | htTP://example.com/ 23 | http://example.com/ 24 | 25 | Capitalization in percent-escaped reserved characters 26 | http://example.com/foo%2cbar 27 | http://example.com/foo%2Cbar 28 | 29 | Unescape percent-encoded unreserved characters 30 | http://example.com/foo%2Dbar%2dbaz 31 | http://example.com/foo-bar-baz 32 | 33 | remove_dot_segments example 1 34 | http://example.com/a/b/c/./../../g 35 | http://example.com/a/g 36 | 37 | remove_dot_segments example 2 38 | http://example.com/mid/content=5/../6 39 | http://example.com/mid/6 40 | 41 | remove_dot_segments: single-dot 42 | http://example.com/a/./b 43 | http://example.com/a/b 44 | 45 | remove_dot_segments: double-dot 46 | http://example.com/a/../b 47 | http://example.com/b 48 | 49 | remove_dot_segments: leading double-dot 50 | http://example.com/../b 51 | http://example.com/b 52 | 53 | remove_dot_segments: trailing single-dot 54 | http://example.com/a/. 55 | http://example.com/a/ 56 | 57 | remove_dot_segments: trailing double-dot 58 | http://example.com/a/.. 59 | http://example.com/ 60 | 61 | remove_dot_segments: trailing single-dot-slash 62 | http://example.com/a/./ 63 | http://example.com/a/ 64 | 65 | remove_dot_segments: trailing double-dot-slash 66 | http://example.com/a/../ 67 | http://example.com/ 68 | 69 | Test of all kinds of syntax-based normalization 70 | hTTPS://a/./b/../b/%63/%7bfoo%7d 71 | https://a/b/c/%7Bfoo%7D 72 | 73 | Unsupported scheme 74 | ftp://example.com/ 75 | fail 76 | 77 | Non-absolute URI 78 | http:/foo 79 | fail 80 | 81 | Illegal character in URI 82 | http://.com/ 83 | fail 84 | 85 | Non-ascii character in URI 86 | http://foo.com/ 87 | fail 88 | -------------------------------------------------------------------------------- /examples/appengine/media/js/simpleauth.js: -------------------------------------------------------------------------------- 1 | YUI({combine: true, timeout: 10000}).use('node', 'event', 'io', 'overlay', 'dump', 'json-parse', function (Y) { 2 | 3 | if(Y.Node.get('#ysimpleauth-login')) 4 | { 5 | Y.on('click', function (e) { 6 | 7 | // prevent default 8 | e.preventDefault(); 9 | 10 | // create overlay + loading indicator 11 | var overlay = new Y.Overlay({ 12 | width: '100%', 13 | height: '100%', 14 | bodyContent: '
Signing in... Please finish signing in...
', 15 | zIndex: 10000, 16 | visible: true 17 | }); 18 | overlay.render('body'); 19 | overlay.show(); 20 | 21 | // open popup window 22 | var height = 500; 23 | var width = 500; 24 | 25 | var left = Math.max(0, Math.floor((e.target.get('winWidth') - width) / 2)); 26 | var top = Math.max(0, Math.floor((e.target.get('winHeight') - height) / 2)); 27 | 28 | var simpleauth = window.open('simpleauth.php?openid_mode=discover&popup=true', 'simpleauth', 'location=yes,status=yes,resizable=true,width=' + width + ',height=' + height + ',left=' + left + ',top=' + top); 29 | 30 | // hide overlay when popup closes 31 | 32 | // focus popup 33 | simpleauth.window.focus(); 34 | 35 | // wait until oauth completes 36 | 37 | // close popup window and refresh page for access token 38 | popupMonitor = window.setTimeout(checkPopup, 500); 39 | function checkPopup() { 40 | 41 | if(false == simpleauth.closed) 42 | { 43 | simpleauth.window.focus(); 44 | 45 | popupMonitor = window.setTimeout(checkPopup, 500); 46 | } 47 | else 48 | { 49 | overlay.hide(); 50 | // window.location = 'simpleauth.php?openid_mode=oauth'; 51 | window.clearInterval(); 52 | } 53 | } 54 | 55 | }, '#ysimpleauth-login'); 56 | } 57 | 58 | }); -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/server/trust.html: -------------------------------------------------------------------------------- 1 | {% extends "server/index.html" %} 2 | 3 | {% block body %} 4 | 5 | {% ifequal trust_root_valid "Valid" %} 6 | 7 |

The site {{ trust_root|escape }} has requested verification 8 | of your OpenID.

9 | 10 | {% include "server/pape_request_info.html" %} 11 | {% endifequal %} 12 | {% ifequal trust_root_valid "Invalid" %} 13 |
14 |

This request claims to be from {{ trust_root|escape }} but I have 15 | determined that it is a pack of lies. Beware, if you release 16 | information to them, they are likely to do unconscionable things with it, 17 | being the lying liars that they are.

18 |

Please tell the real {{ trust_root|escape }} that someone is 19 | trying to abuse your trust in their good name.

20 |
21 | {% endifequal %} 22 | {% ifequal trust_root_valid "Unreachable" %} 23 |

The site {{ trust_root|escape }} has requested verification 24 | of your OpenID. I have failed to reach it and thus cannot vouch for its 25 | authenticity. Perhaps it is on your local network.

26 | {% endifequal %} 27 | {% ifequal trust_root_valid "DISCOVERY_FAILED" %} 28 |

The site {{ trust_root|escape }} has requested verification 29 | of your OpenID. However, {{ trust_root|escape }} does not 30 | implement OpenID 2.0's relying party verification mechanism. Please use 31 | extra caution in deciding whether to release information to this party, 32 | and ask {{ trust_root|escape }} to implement relying party 33 | verification for your future transactions.

34 | 35 | {% include "server/pape_request_info.html" %} 36 | {% endifequal %} 37 | 38 | 39 | 40 |
41 |
43 | Verify your identity to the relying party? 44 | 45 |
46 | 47 | 48 |
49 |
50 | 51 | {% endblock %} 52 | -------------------------------------------------------------------------------- /src/yahoo/yql.py: -------------------------------------------------------------------------------- 1 | """ 2 | Yahoo! Python SDK 3 | 4 | * Yahoo! Query Language 5 | * Yahoo! Social API 6 | 7 | Find documentation and support on Yahoo! Developer Network: http://developer.yahoo.com 8 | 9 | Hosted on GitHub: http://github.com/yahoo/yos-social-python/tree/master 10 | 11 | @copyright: Copyrights for code authored by Yahoo! Inc. is licensed under the following terms: 12 | @license: BSD Open Source License 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | THE SOFTWARE. 31 | """ 32 | 33 | __author__ = 'Dustin Whittle ' 34 | __version__ = '0.1' 35 | 36 | import httplib, urllib, simplejson 37 | 38 | # Yahoo! YQL API 39 | PUBLIC_API_URL = 'http://query.yahooapis.com/v1/public/yql' 40 | OAUTH_API_URL = 'http://query.yahooapis.com/v1/yql' 41 | DATATABLES_URL = 'store://datatables.org/alltableswithkeys' 42 | 43 | class YQLQuery(object): 44 | 45 | def __init__(self): 46 | self.connection = httplib.HTTPConnection('query.yahooapis.com') 47 | 48 | def execute(self, yql, token = None): 49 | 50 | self.connection.request('GET', PUBLIC_API_URL + '?' + urllib.urlencode({ 'q': yql, 'format': 'json', 'env': DATATABLES_URL })) 51 | return simplejson.loads(self.connection.getresponse().read()) 52 | 53 | -------------------------------------------------------------------------------- /src/yahoo/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Yahoo! Python SDK 3 | 4 | * Yahoo! Query Language 5 | * Yahoo! Social API 6 | 7 | Find documentation and support on Yahoo! Developer Network: http://developer.yahoo.com 8 | 9 | Hosted on GitHub: http://github.com/yahoo/yos-social-python/tree/master 10 | 11 | @copyright: Copyrights for code authored by Yahoo! Inc. is licensed under the following terms: 12 | @license: BSD Open Source License 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | THE SOFTWARE. 31 | """ 32 | 33 | __author__ = 'Dustin Whittle ' 34 | __version__ = '0.1' 35 | 36 | __all__ = [ 'oauth', 'application', 'yql' ] 37 | 38 | # import required modules 39 | """ 40 | import os 41 | import sys 42 | 43 | import getopt 44 | 45 | import string 46 | import re 47 | 48 | import logging 49 | import exceptions 50 | import pprint 51 | 52 | import time 53 | import datetime 54 | 55 | import httplib 56 | import urllib 57 | import urllib2 58 | import urlparse 59 | import cgi 60 | 61 | import hashlib 62 | import hmac 63 | import base64 64 | import random 65 | import uuid 66 | 67 | import xml 68 | import json 69 | 70 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../')) 71 | 72 | import oauth.oauth as oauth 73 | import simplejson 74 | """ -------------------------------------------------------------------------------- /examples/appengine/media/css/common.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | text-align: left; 4 | } 5 | 6 | img { 7 | border: 0; 8 | } 9 | 10 | a { 11 | text-decoration: none; 12 | font-weight: bold; 13 | } 14 | 15 | /** yahoo signin button **/ 16 | div.authbar { 17 | width: 98%; 18 | text-align: right; 19 | display: block; 20 | } 21 | 22 | div#ysimpleauth-login { margin: 10px; padding: 4px; text-align: left; } 23 | 24 | span.svy-sg { margin:0;overflow:hidden;display:inline; } 25 | span.svy-sg a { border:0;overflow:visible;padding:0px;margin:4px;text-decoration:none;font: 100% times,verdana,sans-serif;cursor:pointer;float:left;*white-space:nowrap; } 26 | span.svy-sg span {float:left;position:relative; top:4px; left:4px; background:url(../img/nrm-grey.png) no-repeat 100% 100%;color:#000;font-weight:normal; } 27 | span.svy-sg span span { background-position:0 100%;top:0;left:-8px; } 28 | span.svy-sg span span span {background-position:0 0;top:-8px;left:0;margin-bottom:-4px; } 29 | span.svy-sg span span span span { background-position:100% 0;top:0;left:8px;margin-bottom:0;padding:4px 8px 0px 0px; } 30 | span.svy-sg span span span span span {left:0px;padding:0 48px 0 0;background:url(../img/lo-y-gsmall.gif) no-repeat 100% 50%; } 31 | span.svy-sg span span span span span.rtext {float:left;padding:0 0 0 3px;background:none; } 32 | 33 | /** yahoo login window overlay **/ 34 | .yui-overlay-content { background-color: #000; font-size:93%; color: #fff; filter:alpha(opacity=0.6); opacity: 0.6; -moz-opacity: 0.6; z-index: 20000; width: 100%; height: 100%; margin:0; padding:0; border:0 } 35 | 36 | #profile, #updates, #socialgraph { 37 | margin: 4em; 38 | display: block; 39 | } 40 | 41 | #updates ul li, #socialgraph ul li { 42 | list-style-type: none; 43 | margin: 4px; 44 | vertical-align: middle; 45 | } 46 | 47 | #updates ul li img, #socialgraph ul li img { 48 | padding-top: 1px; 49 | padding-right: 4px; 50 | } 51 | 52 | #socialgraph ul li { 53 | display: inline; 54 | padding: 1px; 55 | } 56 | 57 | 58 | /** vcard **/ 59 | .vcard { 60 | color: #000; 61 | text-align: left; 62 | font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif; 63 | } 64 | 65 | .vcard form { 66 | margin-top: 1em; 67 | } 68 | 69 | .fn { 70 | padding-top: 3em; 71 | font-weight: bold; 72 | font-size: 123.1%; 73 | } 74 | 75 | .vcard img { 76 | float: left; 77 | margin: 6px; 78 | } 79 | 80 | .vcard em { 81 | margin-top: 1em; 82 | display: block; 83 | } -------------------------------------------------------------------------------- /src/opensocial/mock_http.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import httplib 22 | import urllib 23 | 24 | from opensocial import http 25 | 26 | 27 | class ResponseRecord(object): 28 | 29 | def __init__(self, request, response): 30 | self.request = request 31 | self.response = response 32 | 33 | 34 | class MockUrlFetch(http.UrlFetch): 35 | """A mock UrlFetch implementation for unit tests. 36 | 37 | Used to set canned responses for particular requests. The default canned 38 | response (Error 500) will be returned if a response is not found. 39 | 40 | """ 41 | 42 | def __init__(self): 43 | self.records = [] 44 | self.default_response = http.Response(httplib.INTERNAL_SERVER_ERROR, '') 45 | 46 | def add_response(self, request, response): 47 | """Adds a canned response for a given request. 48 | 49 | Args: 50 | request: An http.Request object used to trigger this response. 51 | response: An http.Response object that will be returned. 52 | 53 | """ 54 | self.records.append(ResponseRecord(request, response)) 55 | 56 | def fetch(self, request): 57 | """Perform the fake fetch. 58 | 59 | Looks up the details of the specified request and returns a canned 60 | response if one is found, otherwise 500 error. 61 | 62 | """ 63 | response = self._lookup_request(request) 64 | return response 65 | 66 | def _lookup_request(self, request): 67 | url = request.get_url() 68 | for record in self.records: 69 | other_url = record.request.get_url() 70 | if (record.request.get_method() == request.get_method() and 71 | url == other_url and 72 | record.request.post_body == request.post_body): 73 | return record.response 74 | return self.default_response 75 | -------------------------------------------------------------------------------- /examples/opensocial/friends/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import logging 22 | import wsgiref 23 | import wsgiref.handlers 24 | 25 | from opensocial import * 26 | from google.appengine.ext import webapp 27 | 28 | 29 | class Handler(webapp.RequestHandler): 30 | 31 | def get(self): 32 | self.test_friends('03067092798963641994') 33 | 34 | def get_container(self): 35 | config = ContainerConfig(oauth_consumer_key='orkut.com:623061448914', 36 | oauth_consumer_secret='uynAeXiWTisflWX99KU1D2q5', 37 | server_rest_base='http://sandbox.orkut.com/social/rest/', 38 | server_rpc_base='http://sandbox.orkut.com/social/rpc/') 39 | return ContainerContext(config) 40 | 41 | def test_friends(self, user_id): 42 | container = self.get_container() 43 | 44 | batch = RequestBatch() 45 | batch.add_request('me', request.FetchPersonRequest(user_id)) 46 | batch.add_request('friends', 47 | request.FetchPeopleRequest(user_id, '@friends')) 48 | batch.send(container) 49 | 50 | me = batch.get('me') 51 | friends = batch.get('friends') 52 | 53 | self.response.out.write('

Test

') 54 | self.output(me, friends) 55 | 56 | def output(self, me, friends): 57 | self.response.out.write('%s\'s Friends: ' % me.get_display_name()) 58 | if not friends: 59 | self.response.out.write('You have no friends.') 60 | else: 61 | self.response.out.write('
    ') 62 | for person in friends: 63 | self.response.out.write('
  • %s
  • ' % person.get_display_name()) 64 | self.response.out.write('
') 65 | 66 | 67 | def main(): 68 | application = webapp.WSGIApplication([ 69 | ('.*', Handler), 70 | ], debug=True) 71 | wsgiref.handlers.CGIHandler().run(application) 72 | 73 | if __name__ == '__main__': 74 | main() 75 | -------------------------------------------------------------------------------- /test/unit/openid/data/test_etxrd/subsegments.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *nishitani 5 | 6 | 2007-12-25T11:33:39.000Z 7 | xri://= 8 | !E117.EF2F.454B.C707 9 | =!E117.EF2F.454B.C707 10 | 11 | http://openid.net/signon/1.0 12 | xri://!!1003!103 13 | https://linksafe.ezibroker.net/server/ 14 | 15 | 16 | xri://$res*auth*($v*2.0) 17 | xri://!!1003!103 18 | application/xrds+xml;trust=none 19 | http://resolve.ezibroker.net/resolve/=nishitani/ 20 | 21 | 22 | xri://+i-service*(+forwarding)*($v*1.0) 23 | 24 | xri://!!1003!103 25 | (+index) 26 | 27 | http://linksafe-forward.ezibroker.net/forwarding/ 28 | 29 | 30 | 31 | *masaki 32 | SUCCESS 33 | xri://!!1003 34 | !0000.0000.3B9A.CA01 35 | =!E117.EF2F.454B.C707!0000.0000.3B9A.CA01 36 | 37 | http://openid.net/signon/1.0 38 | xri://!!1003!103 39 | https://linksafe.ezibroker.net/server/ 40 | 41 | 42 | xri://+i-service*(+contact)*($v*1.0) 43 | 44 | xri://!!1003!103 45 | (+contact) 46 | 47 | http://linksafe-contact.ezibroker.net/contact/ 48 | 49 | 50 | xri://+i-service*(+forwarding)*($v*1.0) 51 | 52 | xri://!!1003!103 53 | (+index) 54 | 55 | http://linksafe-forward.ezibroker.net/forwarding/ 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /test/unit/openid/trustroot.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | from openid.server.trustroot import TrustRoot 4 | 5 | class _ParseTest(unittest.TestCase): 6 | def __init__(self, sanity, desc, case): 7 | unittest.TestCase.__init__(self) 8 | self.desc = desc + ': ' + repr(case) 9 | self.case = case 10 | self.sanity = sanity 11 | 12 | def shortDescription(self): 13 | return self.desc 14 | 15 | def runTest(self): 16 | tr = TrustRoot.parse(self.case) 17 | if self.sanity == 'sane': 18 | assert tr.isSane(), self.case 19 | elif self.sanity == 'insane': 20 | assert not tr.isSane(), self.case 21 | else: 22 | assert tr is None, tr 23 | 24 | class _MatchTest(unittest.TestCase): 25 | def __init__(self, match, desc, line): 26 | unittest.TestCase.__init__(self) 27 | tr, rt = line.split() 28 | self.desc = desc + ': ' + repr(tr) + ' ' + repr(rt) 29 | self.tr = tr 30 | self.rt = rt 31 | self.match = match 32 | 33 | def shortDescription(self): 34 | return self.desc 35 | 36 | def runTest(self): 37 | tr = TrustRoot.parse(self.tr) 38 | self.failIf(tr is None, self.tr) 39 | 40 | match = tr.validateURL(self.rt) 41 | if self.match: 42 | assert match 43 | else: 44 | assert not match 45 | 46 | def getTests(t, grps, head, dat): 47 | tests = [] 48 | top = head.strip() 49 | gdat = map(str.strip, dat.split('-' * 40 + '\n')) 50 | assert not gdat[0] 51 | assert len(gdat) == (len(grps) * 2 + 1), (gdat, grps) 52 | i = 1 53 | for x in grps: 54 | n, desc = gdat[i].split(': ') 55 | cases = gdat[i + 1].split('\n') 56 | assert len(cases) == int(n) 57 | for case in cases: 58 | tests.append(t(x, top + ' - ' + desc, case)) 59 | i += 2 60 | return tests 61 | 62 | def parseTests(data): 63 | parts = map(str.strip, data.split('=' * 40 + '\n')) 64 | assert not parts[0] 65 | _, ph, pdat, mh, mdat = parts 66 | 67 | tests = [] 68 | tests.extend(getTests(_ParseTest, ['bad', 'insane', 'sane'], ph, pdat)) 69 | tests.extend(getTests(_MatchTest, [1, 0], mh, mdat)) 70 | return tests 71 | 72 | def pyUnitTests(): 73 | here = os.path.dirname(os.path.abspath(__file__)) 74 | test_data_file_name = os.path.join(here, 'data', 'trustroot.txt') 75 | test_data_file = file(test_data_file_name) 76 | test_data = test_data_file.read() 77 | test_data_file.close() 78 | 79 | tests = parseTests(test_data) 80 | return unittest.TestSuite(tests) 81 | 82 | if __name__ == '__main__': 83 | suite = pyUnitTests() 84 | runner = unittest.TextTestRunner() 85 | runner.run(suite) 86 | -------------------------------------------------------------------------------- /examples/appengine/templates/social.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Yahoo! Developer Network: Google App Engine + Yahoo! Social Data 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | {{profile.nickname}}'s Profile Picture 16 | {{profile.givenName}} 17 | {{profile.familyName}} 18 | 19 | 20 |
21 | {{profile.location}} 22 |
23 | 24 | {{profile.status.message}} 25 | 26 |
27 |
28 | 29 |
30 |

{{profile.nickname}}'s Updates

31 | 32 |
33 |
34 |
35 | 36 | 37 | 38 |
39 |
40 |
41 | 42 | {% if updates %} 43 | 48 | {% else %} 49 | No updates, make some! 50 | {% endif %} 51 |
52 | 53 |
54 |

{{profile.nickname}}'s Social Graph

55 | {% if connections %} 56 |
    57 | {% for connection in connections %} 58 |
  • {{connection.nickname}}'s Profile Picture
  • 59 | {% endfor %} 60 |
61 | {% else %} 62 | No contacts, find some! 63 | {% endif %} 64 |
65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /test/unit/openid/test_parsehtml.py: -------------------------------------------------------------------------------- 1 | from openid.yadis.parsehtml import YadisHTMLParser, ParseDone 2 | from HTMLParser import HTMLParseError 3 | 4 | import os.path, unittest, sys 5 | 6 | class _TestCase(unittest.TestCase): 7 | reserved_values = ['None', 'EOF'] 8 | 9 | def __init__(self, filename, testname, expected, case): 10 | self.filename = filename 11 | self.testname = testname 12 | self.expected = expected 13 | self.case = case 14 | unittest.TestCase.__init__(self) 15 | 16 | def runTest(self): 17 | p = YadisHTMLParser() 18 | try: 19 | p.feed(self.case) 20 | except ParseDone, why: 21 | found = why[0] 22 | 23 | # make sure we protect outselves against accidental bogus 24 | # test cases 25 | assert found not in self.reserved_values 26 | 27 | # convert to a string 28 | if found is None: 29 | found = 'None' 30 | 31 | msg = "%r != %r for case %s" % (found, self.expected, self.case) 32 | self.failUnlessEqual(found, self.expected, msg) 33 | except HTMLParseError: 34 | self.failUnless(self.expected == 'None', (self.case, self.expected)) 35 | else: 36 | self.failUnless(self.expected == 'EOF', (self.case, self.expected)) 37 | 38 | def shortDescription(self): 39 | return "%s (%s<%s>)" % ( 40 | self.testname, 41 | self.__class__.__module__, 42 | os.path.basename(self.filename)) 43 | 44 | def parseCases(data): 45 | cases = [] 46 | for chunk in data.split('\f\n'): 47 | expected, case = chunk.split('\n', 1) 48 | cases.append((expected, case)) 49 | return cases 50 | 51 | def pyUnitTests(): 52 | """Make a pyunit TestSuite from a file defining test cases.""" 53 | s = unittest.TestSuite() 54 | for (filename, test_num, expected, case) in getCases(): 55 | s.addTest(_TestCase(filename, str(test_num), expected, case)) 56 | return s 57 | 58 | def test(): 59 | runner = unittest.TextTestRunner() 60 | return runner.run(loadTests()) 61 | 62 | filenames = ['data/test1-parsehtml.txt'] 63 | 64 | default_test_files = [] 65 | base = os.path.dirname(__file__) 66 | for filename in filenames: 67 | full_name = os.path.join(base, filename) 68 | default_test_files.append(full_name) 69 | 70 | def getCases(test_files=default_test_files): 71 | cases = [] 72 | for filename in test_files: 73 | test_num = 0 74 | data = file(filename).read() 75 | for expected, case in parseCases(data): 76 | test_num += 1 77 | cases.append((filename, test_num, expected, case)) 78 | return cases 79 | 80 | 81 | if __name__ == '__main__': 82 | sys.exit(not test().wasSuccessful()) 83 | -------------------------------------------------------------------------------- /src/simplejson/scanner.py: -------------------------------------------------------------------------------- 1 | """ 2 | Iterator based sre token scanner 3 | """ 4 | # NOTE(kgibbs): This line must be added to make this file work under 5 | # Python 2.2, which is commonly used at Google. 6 | from __future__ import generators 7 | # NOTE(kgibbs): End changes. 8 | import sre_parse, sre_compile, sre_constants 9 | from sre_constants import BRANCH, SUBPATTERN 10 | from re import VERBOSE, MULTILINE, DOTALL # NOTE(guido): Was 'from sre ...' 11 | import re 12 | 13 | __all__ = ['Scanner', 'pattern'] 14 | 15 | FLAGS = (VERBOSE | MULTILINE | DOTALL) 16 | class Scanner(object): 17 | def __init__(self, lexicon, flags=FLAGS): 18 | self.actions = [None] 19 | # combine phrases into a compound pattern 20 | s = sre_parse.Pattern() 21 | s.flags = flags 22 | p = [] 23 | # NOTE(kgibbs): These lines must be added to make this file work under 24 | # Python 2.2, which is commonly used at Google. 25 | def enumerate(obj): 26 | i = -1 27 | for item in obj: 28 | i += 1 29 | yield i, item 30 | # NOTE(kgibbs): End changes. 31 | for idx, token in enumerate(lexicon): 32 | phrase = token.pattern 33 | try: 34 | subpattern = sre_parse.SubPattern(s, 35 | [(SUBPATTERN, (idx + 1, sre_parse.parse(phrase, flags)))]) 36 | except sre_constants.error: 37 | raise 38 | p.append(subpattern) 39 | self.actions.append(token) 40 | 41 | s.groups = len(p)+1 # NOTE(guido): Added to make SRE validation work 42 | p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) 43 | self.scanner = sre_compile.compile(p) 44 | 45 | 46 | def iterscan(self, string, idx=0, context=None): 47 | """ 48 | Yield match, end_idx for each match 49 | """ 50 | match = self.scanner.scanner(string, idx).match 51 | actions = self.actions 52 | lastend = idx 53 | end = len(string) 54 | while True: 55 | m = match() 56 | if m is None: 57 | break 58 | matchbegin, matchend = m.span() 59 | if lastend == matchend: 60 | break 61 | action = actions[m.lastindex] 62 | if action is not None: 63 | rval, next_pos = action(m, context) 64 | if next_pos is not None and next_pos != matchend: 65 | # "fast forward" the scanner 66 | matchend = next_pos 67 | match = self.scanner.scanner(string, matchend).match 68 | yield rval, matchend 69 | lastend = matchend 70 | 71 | def pattern(pattern, flags=FLAGS): 72 | def decorator(fn): 73 | fn.pattern = pattern 74 | fn.regex = re.compile(pattern, flags) 75 | return fn 76 | return decorator 77 | -------------------------------------------------------------------------------- /test/unit/openid/data/test1-discover.txt: -------------------------------------------------------------------------------- 1 | equiv 2 | Status: 200 OK 3 | Content-Type: text/html 4 | 5 | 6 | 7 | 8 | Joe Schmoe's Homepage 9 | 10 | 11 |

Joe Schmoe's Homepage

12 |

Blah blah blah blah blah blah blah

13 | 14 | 15 | 16 | header 17 | Status: 200 OK 18 | Content-Type: text/html 19 | YADIS_HEADER: URL_BASE/xrds 20 | 21 | 22 | 23 | Joe Schmoe's Homepage 24 | 25 | 26 |

Joe Schmoe's Homepage

27 |

Blah blah blah blah blah blah blah

28 | 29 | 30 | xrds 31 | Status: 200 OK 32 | Content-Type: application/xrds+xml 33 | 34 | 35 | 36 | xrds_ctparam 37 | Status: 200 OK 38 | Content-Type: application/xrds+xml; charset=UTF8 39 | 40 | 41 | 42 | xrds_ctcase 43 | Status: 200 OK 44 | Content-Type: appliCATION/XRDS+xml 45 | 46 | 47 | 48 | xrds_html 49 | Status: 200 OK 50 | Content-Type: text/html 51 | 52 | 53 | 54 | redir_equiv 55 | Status: 302 Found 56 | Content-Type: text/plain 57 | Location: URL_BASE/equiv 58 | 59 | You are presently being redirected. 60 | 61 | redir_header 62 | Status: 302 Found 63 | Content-Type: text/plain 64 | Location: URL_BASE/header 65 | 66 | You are presently being redirected. 67 | 68 | redir_xrds 69 | Status: 302 Found 70 | Content-Type: application/xrds+xml 71 | Location: URL_BASE/xrds 72 | 73 | 74 | 75 | redir_xrds_html 76 | Status: 302 Found 77 | Content-Type: text/plain 78 | Location: URL_BASE/xrds_html 79 | 80 | You are presently being redirected. 81 | 82 | redir_redir_equiv 83 | Status: 302 Found 84 | Content-Type: text/plain 85 | Location: URL_BASE/redir_equiv 86 | 87 | You are presently being redirected. 88 | 89 | lowercase_header 90 | Status: 200 OK 91 | Content-Type: text/html 92 | x-xrds-location: URL_BASE/xrds 93 | 94 | 95 | 96 | Joe Schmoe's Homepage 97 | 98 | 99 |

Joe Schmoe's Homepage

100 |

Blah blah blah blah blah blah blah

101 | 102 | 103 | 404_server_response 104 | Status: 404 Not Found 105 | 106 | EEk! 107 | 108 | 500_server_response 109 | Status: 500 Server error 110 | 111 | EEk! 112 | 113 | 201_server_response 114 | Status: 201 Created 115 | 116 | EEk! 117 | 118 | 404_with_header 119 | Status: 404 Not Found 120 | YADIS_HEADER: URL_BASE/xrds 121 | 122 | EEk! 123 | 124 | 404_with_meta 125 | Status: 404 Not Found 126 | Content-Type: text/html 127 | 128 | 129 | 130 | 131 | Joe Schmoe's Homepage 132 | 133 | 134 |

Joe Schmoe's Homepage

135 |

Blah blah blah blah blah blah blah

136 | 137 | 138 | -------------------------------------------------------------------------------- /src/opensocial/simplejson/scanner.py: -------------------------------------------------------------------------------- 1 | """ 2 | Iterator based sre token scanner 3 | """ 4 | # NOTE(kgibbs): This line must be added to make this file work under 5 | # Python 2.2, which is commonly used at Google. 6 | from __future__ import generators 7 | # NOTE(kgibbs): End changes. 8 | import sre_parse, sre_compile, sre_constants 9 | from sre_constants import BRANCH, SUBPATTERN 10 | from re import VERBOSE, MULTILINE, DOTALL # NOTE(guido): Was 'from sre ...' 11 | import re 12 | 13 | __all__ = ['Scanner', 'pattern'] 14 | 15 | FLAGS = (VERBOSE | MULTILINE | DOTALL) 16 | class Scanner(object): 17 | def __init__(self, lexicon, flags=FLAGS): 18 | self.actions = [None] 19 | # combine phrases into a compound pattern 20 | s = sre_parse.Pattern() 21 | s.flags = flags 22 | p = [] 23 | # NOTE(kgibbs): These lines must be added to make this file work under 24 | # Python 2.2, which is commonly used at Google. 25 | def enumerate(obj): 26 | i = -1 27 | for item in obj: 28 | i += 1 29 | yield i, item 30 | # NOTE(kgibbs): End changes. 31 | for idx, token in enumerate(lexicon): 32 | phrase = token.pattern 33 | try: 34 | subpattern = sre_parse.SubPattern(s, 35 | [(SUBPATTERN, (idx + 1, sre_parse.parse(phrase, flags)))]) 36 | except sre_constants.error: 37 | raise 38 | p.append(subpattern) 39 | self.actions.append(token) 40 | 41 | s.groups = len(p)+1 # NOTE(guido): Added to make SRE validation work 42 | p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) 43 | self.scanner = sre_compile.compile(p) 44 | 45 | 46 | def iterscan(self, string, idx=0, context=None): 47 | """ 48 | Yield match, end_idx for each match 49 | """ 50 | match = self.scanner.scanner(string, idx).match 51 | actions = self.actions 52 | lastend = idx 53 | end = len(string) 54 | while True: 55 | m = match() 56 | if m is None: 57 | break 58 | matchbegin, matchend = m.span() 59 | if lastend == matchend: 60 | break 61 | action = actions[m.lastindex] 62 | if action is not None: 63 | rval, next_pos = action(m, context) 64 | if next_pos is not None and next_pos != matchend: 65 | # "fast forward" the scanner 66 | matchend = next_pos 67 | match = self.scanner.scanner(string, matchend).match 68 | yield rval, matchend 69 | lastend = matchend 70 | 71 | def pattern(pattern, flags=FLAGS): 72 | def decorator(fn): 73 | fn.pattern = pattern 74 | fn.regex = re.compile(pattern, flags) 75 | return fn 76 | return decorator 77 | -------------------------------------------------------------------------------- /examples/openid/djopenid/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for djopenid project. 2 | 3 | import os 4 | import sys 5 | import warnings 6 | 7 | try: 8 | import openid 9 | except ImportError, e: 10 | warnings.warn("Could not import OpenID library. Please consult the djopenid README.") 11 | sys.exit(1) 12 | 13 | DEBUG = True 14 | TEMPLATE_DEBUG = DEBUG 15 | 16 | ADMINS = ( 17 | # ('Your Name', 'your_email@domain.com'), 18 | ) 19 | 20 | MANAGERS = ADMINS 21 | 22 | DATABASE_ENGINE = 'sqlite3' # 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'. 23 | DATABASE_NAME = '/tmp/test.db' # Or path to database file if using sqlite3. 24 | DATABASE_USER = '' # Not used with sqlite3. 25 | DATABASE_PASSWORD = '' # Not used with sqlite3. 26 | DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. 27 | DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. 28 | 29 | # Local time zone for this installation. All choices can be found here: 30 | # http://www.postgresql.org/docs/current/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE 31 | TIME_ZONE = 'America/Chicago' 32 | 33 | # Language code for this installation. All choices can be found here: 34 | # http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes 35 | # http://blogs.law.harvard.edu/tech/stories/storyReader$15 36 | LANGUAGE_CODE = 'en-us' 37 | 38 | SITE_ID = 1 39 | 40 | # Absolute path to the directory that holds media. 41 | # Example: "/home/media/media.lawrence.com/" 42 | MEDIA_ROOT = '' 43 | 44 | # URL that handles the media served from MEDIA_ROOT. 45 | # Example: "http://media.lawrence.com" 46 | MEDIA_URL = '' 47 | 48 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 49 | # trailing slash. 50 | # Examples: "http://foo.com/media/", "/media/". 51 | ADMIN_MEDIA_PREFIX = '/media/' 52 | 53 | # Make this unique, and don't share it with anybody. 54 | SECRET_KEY = 'u^bw6lmsa6fah0$^lz-ct$)y7x7#ag92-z+y45-8!(jk0lkavy' 55 | 56 | # List of callables that know how to import templates from various sources. 57 | TEMPLATE_LOADERS = ( 58 | 'django.template.loaders.filesystem.load_template_source', 59 | 'django.template.loaders.app_directories.load_template_source', 60 | # 'django.template.loaders.eggs.load_template_source', 61 | ) 62 | 63 | MIDDLEWARE_CLASSES = ( 64 | 'django.middleware.common.CommonMiddleware', 65 | 'django.contrib.sessions.middleware.SessionMiddleware', 66 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 67 | 'django.middleware.doc.XViewMiddleware', 68 | ) 69 | 70 | ROOT_URLCONF = 'djopenid.urls' 71 | 72 | TEMPLATE_CONTEXT_PROCESSORS = () 73 | 74 | TEMPLATE_DIRS = ( 75 | os.path.abspath(os.path.join(os.path.dirname(__file__), 'templates')), 76 | ) 77 | 78 | INSTALLED_APPS = ( 79 | 'django.contrib.contenttypes', 80 | 'django.contrib.sessions', 81 | 82 | 'djopenid.consumer', 83 | 'djopenid.server', 84 | ) 85 | -------------------------------------------------------------------------------- /examples/appengine/djangodemo/settings.py: -------------------------------------------------------------------------------- 1 | 2 | # settings.py 3 | 4 | # Django settings for yosdemo project. 5 | 6 | import os 7 | 8 | ROOT_PATH = os.path.dirname(__file__) 9 | 10 | DEBUG = True 11 | TEMPLATE_DEBUG = DEBUG 12 | 13 | ADMINS = ( 14 | ('dustin', 'dustin.whittle@gmail.com') 15 | ) 16 | 17 | MANAGERS = ADMINS 18 | 19 | DATABASE_ENGINE = '' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 20 | DATABASE_NAME = '' # Or path to database file if using sqlite3. 21 | DATABASE_USER = '' # Not used with sqlite3. 22 | DATABASE_PASSWORD = '' # Not used with sqlite3. 23 | DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. 24 | DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. 25 | 26 | # Local time zone for this installation. Choices can be found here: 27 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 28 | # although not all choices may be available on all operating systems. 29 | # If running in a Windows environment this must be set to the same as your 30 | # system time zone. 31 | TIME_ZONE = 'America/Los_Angeles' 32 | 33 | # Language code for this installation. All choices can be found here: 34 | # http://www.i18nguy.com/unicode/language-identifiers.html 35 | LANGUAGE_CODE = 'en-us' 36 | 37 | SITE_ID = 1 38 | 39 | # If you set this to False, Django will make some optimizations so as not 40 | # to load the internationalization machinery. 41 | USE_I18N = True 42 | 43 | # Absolute path to the directory that holds media. 44 | # Example: "/home/media/media.lawrence.com/" 45 | MEDIA_ROOT = '' 46 | 47 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 48 | # trailing slash if there is a path component (optional in other cases). 49 | # Examples: "http://media.lawrence.com", "http://example.com/media/" 50 | MEDIA_URL = '' 51 | 52 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 53 | # trailing slash. 54 | # Examples: "http://foo.com/media/", "/media/". 55 | ADMIN_MEDIA_PREFIX = '/media/' 56 | 57 | # Make this unique, and don't share it with anybody. 58 | SECRET_KEY = '-aa#*n^bte!(0l%4t$yx8=!=o-i)$(bw2#9e%c3y71!m-kmqzr' 59 | 60 | # List of callables that know how to import templates from various sources. 61 | TEMPLATE_LOADERS = ( 62 | 'django.template.loaders.filesystem.load_template_source', 63 | 'django.template.loaders.app_directories.load_template_source', 64 | # 'django.template.loaders.eggs.load_template_source', 65 | ) 66 | 67 | MIDDLEWARE_CLASSES = ( 68 | 'django.middleware.common.CommonMiddleware', 69 | # 'django.contrib.sessions.middleware.SessionMiddleware', 70 | # 'django.contrib.auth.middleware.AuthenticationMiddleware', 71 | ) 72 | 73 | ROOT_URLCONF = 'djangodemo.urls' 74 | 75 | TEMPLATE_DIRS = ( 76 | ROOT_PATH + '/templates', 77 | ) 78 | 79 | INSTALLED_APPS = ( 80 | # 'django.contrib.auth', 81 | 'django.contrib.contenttypes', 82 | # 'django.contrib.sessions', 83 | 'django.contrib.sites', 84 | ) 85 | -------------------------------------------------------------------------------- /examples/yql.py: -------------------------------------------------------------------------------- 1 | """ 2 | Yahoo! Python SDK 3 | 4 | * Yahoo! Query Language 5 | * Yahoo! Social API 6 | 7 | Find documentation and support on Yahoo! Developer Network: http://developer.yahoo.com 8 | 9 | Hosted on GitHub: http://github.com/yahoo/yos-social-python/tree/master 10 | 11 | @copyright: Copyrights for code authored by Yahoo! Inc. is licensed under the following terms: 12 | @license: BSD Open Source License 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | THE SOFTWARE. 31 | """ 32 | 33 | __author__ = 'Dustin Whittle ' 34 | __version__ = '0.1' 35 | 36 | ############################################################################## 37 | # Requires: Python 2.6 + oauth + simplejson # 38 | # Install dependencies at system level: easy_install oauth simplejson # 39 | ############################################################################## 40 | 41 | # import required modules 42 | import os, sys, getopt, pprint 43 | 44 | # update sys path to include bundled modules with priority 45 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../src')) 46 | 47 | import yahoo.yql 48 | 49 | def main(): 50 | """ 51 | Demonstrates usage of YQL (public api) via commandline: 52 | """ 53 | 54 | yql = '' 55 | 56 | # use command line options if present, otherwise prompt user 57 | try: 58 | opts, args = getopt.getopt(sys.argv[1:], '', ['yql=']) 59 | for option, arg in opts: 60 | if option == '--yql': 61 | yql = arg 62 | while not yql: 63 | yql = raw_input('Please enter yql query: ') 64 | except getopt.error, msg: 65 | print ('python yql.py --yql="select * from delicious.feeds.popular"') 66 | sys.exit(2) 67 | 68 | # make public yql call 69 | response = yahoo.yql.YQLQuery().execute(yql) 70 | if 'query' in response and 'results' in response['query']: 71 | pprint.PrettyPrinter(indent=2).pprint(response['query']['results']) 72 | elif 'error' in response: 73 | print 'YQL query failed with error: "%s".' % response['error']['description'] 74 | else: 75 | print 'YQL response malformed.' 76 | 77 | 78 | if __name__ == '__main__': 79 | main() 80 | -------------------------------------------------------------------------------- /src/openid/store/nonce.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | 'split', 3 | 'mkNonce', 4 | 'checkTimestamp', 5 | ] 6 | 7 | from openid import cryptutil 8 | from time import strptime, strftime, gmtime, time 9 | from calendar import timegm 10 | import string 11 | 12 | NONCE_CHARS = string.ascii_letters + string.digits 13 | 14 | # Keep nonces for five hours (allow five hours for the combination of 15 | # request time and clock skew). This is probably way more than is 16 | # necessary, but there is not much overhead in storing nonces. 17 | SKEW = 60 * 60 * 5 18 | 19 | time_fmt = '%Y-%m-%dT%H:%M:%SZ' 20 | time_str_len = len('0000-00-00T00:00:00Z') 21 | 22 | def split(nonce_string): 23 | """Extract a timestamp from the given nonce string 24 | 25 | @param nonce_string: the nonce from which to extract the timestamp 26 | @type nonce_string: str 27 | 28 | @returns: A pair of a Unix timestamp and the salt characters 29 | @returntype: (int, str) 30 | 31 | @raises ValueError: if the nonce does not start with a correctly 32 | formatted time string 33 | """ 34 | timestamp_str = nonce_string[:time_str_len] 35 | try: 36 | timestamp = timegm(strptime(timestamp_str, time_fmt)) 37 | except AssertionError: # Python 2.2 38 | timestamp = -1 39 | if timestamp < 0: 40 | raise ValueError('time out of range') 41 | return timestamp, nonce_string[time_str_len:] 42 | 43 | def checkTimestamp(nonce_string, allowed_skew=SKEW, now=None): 44 | """Is the timestamp that is part of the specified nonce string 45 | within the allowed clock-skew of the current time? 46 | 47 | @param nonce_string: The nonce that is being checked 48 | @type nonce_string: str 49 | 50 | @param allowed_skew: How many seconds should be allowed for 51 | completing the request, allowing for clock skew. 52 | @type allowed_skew: int 53 | 54 | @param now: The current time, as a Unix timestamp 55 | @type now: int 56 | 57 | @returntype: bool 58 | @returns: Whether the timestamp is correctly formatted and within 59 | the allowed skew of the current time. 60 | """ 61 | try: 62 | stamp, _ = split(nonce_string) 63 | except ValueError: 64 | return False 65 | else: 66 | if now is None: 67 | now = time() 68 | 69 | # Time after which we should not use the nonce 70 | past = now - allowed_skew 71 | 72 | # Time that is too far in the future for us to allow 73 | future = now + allowed_skew 74 | 75 | # the stamp is not too far in the future and is not too far in 76 | # the past 77 | return past <= stamp <= future 78 | 79 | def mkNonce(when=None): 80 | """Generate a nonce with the current timestamp 81 | 82 | @param when: Unix timestamp representing the issue time of the 83 | nonce. Defaults to the current time. 84 | @type when: int 85 | 86 | @returntype: str 87 | @returns: A string that should be usable as a one-way nonce 88 | 89 | @see: time 90 | """ 91 | salt = cryptutil.randomString(6, NONCE_CHARS) 92 | if when is None: 93 | t = gmtime() 94 | else: 95 | t = gmtime(when) 96 | 97 | time_str = strftime(time_fmt, t) 98 | return time_str + salt 99 | -------------------------------------------------------------------------------- /examples/openid/README: -------------------------------------------------------------------------------- 1 | Python OpenID library example code 2 | ================================== 3 | 4 | The examples directory contains working code illustrating the use of 5 | the library for performing OpenID authentication, both as a consumer 6 | and a server. There are two kinds of examples, one that can run 7 | without any external dependencies, and one that uses the Django Web 8 | framework. The examples do not illustrate how to use all of the 9 | features of the library, but they should be a good starting point to 10 | see how to use this library with your code. 11 | 12 | Both the Django libraries and the BaseHTTPServer examples require that 13 | the OpenID library is installed or that it has been added to Python's 14 | search path (PYTHONPATH environment variable or sys.path). 15 | 16 | The Django example is probably a good place to start reading the 17 | code. There is little that is Django-specific about the OpenID logic 18 | in the example, and it should be easy to port to any framework. To run 19 | the django examples, see the README file in the djopenid subdirectory. 20 | 21 | The other examples use Python's built-in BaseHTTPServer and have a 22 | good deal of ad-hoc dispatching and rendering code mixed in 23 | 24 | Using the BaseHTTPServer examples 25 | ================================= 26 | 27 | This directory contains a working server and consumer that use this 28 | OpenID library. They are both written using python's standard 29 | BaseHTTPServer. 30 | 31 | 32 | To run the example system: 33 | 34 | 1. Make sure you've installed the library, as explained in the 35 | installation instructions. 36 | 37 | 2. Start the consumer server: 38 | 39 | python consumer.py --port 8001 40 | 41 | 42 | 3. In another terminal, start the identity server: 43 | 44 | python server.py --port 8000 45 | 46 | (Hit Ctrl-C in either server's window to stop that server.) 47 | 48 | 49 | 4. Open your web broswer, and go to the consumer server: 50 | 51 | http://localhost:8001/ 52 | 53 | Note that all pages the consumer server shows will have "Python OpenID 54 | Consumer Example" across the top. 55 | 56 | 57 | 5. Enter an identity url managed by the sample identity server: 58 | 59 | http://localhost:8000/id/bob 60 | 61 | 62 | 6. The browser will be redirected to the sample server, which will be 63 | requesting that you log in to proceed. Enter the username for the 64 | identity URL into the login box: 65 | 66 | bob 67 | 68 | Note that all pages the identity server shows will have "Python 69 | OpenID Server Example" across the top. 70 | 71 | 72 | 7. After you log in as bob, the server example will ask you if you 73 | want to allow http://localhost:8001/ to know your identity. Say 74 | yes. 75 | 76 | 77 | 8. You should end up back on the consumer site, at a page indicating 78 | you've logged in successfully. 79 | 80 | 81 | That's a basic OpenID login procedure. You can continue through it, 82 | playing with variations to see how they work. The python code is 83 | intended to be a straightforward example of how to use the python 84 | OpenID library to function as either an identity server or consumer. 85 | 86 | Getting help 87 | ============ 88 | 89 | Please send bug reports, patches, and other feedback to 90 | 91 | dev@lists.openidenabled.com 92 | -------------------------------------------------------------------------------- /examples/opensocial/oauthbox/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2007 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | 19 | import logging 20 | import wsgiref.handlers 21 | 22 | import opensocial 23 | 24 | from opensocial import simplejson 25 | from opensocial import oauth 26 | from google.appengine.ext import webapp 27 | 28 | 29 | class MainHandler(webapp.RequestHandler): 30 | 31 | def get(self): 32 | pass 33 | 34 | def post(self): 35 | oauth_version = self.request.get('oauth_version') 36 | oauth_nonce = self.request.get('oauth_nonce') 37 | oauth_timestamp = self.request.get('oauth_timestamp') 38 | oauth_consumer_key = self.request.get('oauth_consumer_key') 39 | oauth_signature = self.request.get('oauth_signature') 40 | xoauth_requestor_id = self.request.get('xoauth_requestor_id') 41 | opensocial_method = self.request.get('opensocial_method') 42 | post_body = self.request.body 43 | post_data = simplejson.loads(post_body)[0] 44 | id = post_data.get('id') 45 | 46 | params = {} 47 | for key, value in self.request.params.mixed().items(): 48 | params[key] = value.encode('utf-8', 'ignore') 49 | 50 | oauth_request = oauth.OAuthRequest.from_request(self.request.method, 51 | self.request.url, 52 | params) 53 | consumer = oauth.OAuthConsumer('oauth.org:123456789', 'not_a_secret') 54 | 55 | signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1() 56 | built_signature = signature_method.build_signature(oauth_request, 57 | consumer, 58 | None) 59 | verified = built_signature == oauth_signature 60 | data = { 61 | 'request': { 62 | 'method': self.request.method, 63 | 'url': self.request.url, 64 | 'oauth_version': oauth_version, 65 | 'oauth_nonce': oauth_nonce, 66 | 'oauth_timestamp': oauth_timestamp, 67 | 'oauth_consumer_key': oauth_consumer_key, 68 | 'oauth_signature': oauth_signature, 69 | 'post_body': post_body 70 | }, 71 | 'response': { 72 | 'built_signature': built_signature 73 | }, 74 | 'verified': str(verified), 75 | } 76 | 77 | json = { 78 | 'id': id, 79 | 'data': data 80 | } 81 | 82 | output = simplejson.dumps([json]) 83 | if verified: 84 | logging.info(output) 85 | else: 86 | logging.error(output) 87 | self.response.out.write(output) 88 | 89 | 90 | def main(): 91 | application = webapp.WSGIApplication([('.*', MainHandler)], 92 | debug=True) 93 | wsgiref.handlers.CGIHandler().run(application) 94 | 95 | 96 | if __name__ == '__main__': 97 | main() 98 | -------------------------------------------------------------------------------- /test/unit/openid/linkparse.py: -------------------------------------------------------------------------------- 1 | from openid.consumer.html_parse import parseLinkAttrs 2 | import os.path 3 | import codecs 4 | import unittest 5 | 6 | def parseLink(line): 7 | parts = line.split() 8 | optional = parts[0] == 'Link*:' 9 | assert optional or parts[0] == 'Link:' 10 | 11 | attrs = {} 12 | for attr in parts[1:]: 13 | k, v = attr.split('=', 1) 14 | if k[-1] == '*': 15 | attr_optional = 1 16 | k = k[:-1] 17 | else: 18 | attr_optional = 0 19 | 20 | attrs[k] = (attr_optional, v) 21 | 22 | return (optional, attrs) 23 | 24 | def parseCase(s): 25 | header, markup = s.split('\n\n', 1) 26 | lines = header.split('\n') 27 | name = lines.pop(0) 28 | assert name.startswith('Name: ') 29 | desc = name[6:] 30 | return desc, markup, map(parseLink, lines) 31 | 32 | def parseTests(s): 33 | tests = [] 34 | 35 | cases = s.split('\n\n\n') 36 | header = cases.pop(0) 37 | tests_line, _ = header.split('\n', 1) 38 | k, v = tests_line.split(': ') 39 | assert k == 'Num Tests' 40 | num_tests = int(v) 41 | 42 | for case in cases[:-1]: 43 | desc, markup, links = parseCase(case) 44 | tests.append((desc, markup, links, case)) 45 | 46 | return num_tests, tests 47 | 48 | class _LinkTest(unittest.TestCase): 49 | def __init__(self, desc, case, expected, raw): 50 | unittest.TestCase.__init__(self) 51 | self.desc = desc 52 | self.case = case 53 | self.expected = expected 54 | self.raw = raw 55 | 56 | def shortDescription(self): 57 | return self.desc 58 | 59 | def runTest(self): 60 | actual = parseLinkAttrs(self.case) 61 | i = 0 62 | for optional, exp_link in self.expected: 63 | if optional: 64 | if i >= len(actual): 65 | continue 66 | 67 | act_link = actual[i] 68 | for k, (o, v) in exp_link.items(): 69 | if o: 70 | act_v = act_link.get(k) 71 | if act_v is None: 72 | continue 73 | else: 74 | act_v = act_link[k] 75 | 76 | if optional and v != act_v: 77 | break 78 | 79 | self.assertEqual(v, act_v) 80 | else: 81 | i += 1 82 | 83 | assert i == len(actual) 84 | 85 | def pyUnitTests(): 86 | here = os.path.dirname(os.path.abspath(__file__)) 87 | test_data_file_name = os.path.join(here, 'linkparse.txt') 88 | test_data_file = codecs.open(test_data_file_name, 'r', 'utf-8') 89 | test_data = test_data_file.read() 90 | test_data_file.close() 91 | 92 | num_tests, test_cases = parseTests(test_data) 93 | 94 | tests = [_LinkTest(*case) for case in test_cases] 95 | 96 | def test_parseSucceeded(): 97 | assert len(test_cases) == num_tests, (len(test_cases), num_tests) 98 | 99 | check_desc = 'Check that we parsed the correct number of test cases' 100 | check = unittest.FunctionTestCase( 101 | test_parseSucceeded, description=check_desc) 102 | tests.insert(0, check) 103 | 104 | return unittest.TestSuite(tests) 105 | 106 | if __name__ == '__main__': 107 | suite = pyUnitTests() 108 | runner = unittest.TextTestRunner() 109 | runner.run(suite) 110 | -------------------------------------------------------------------------------- /examples/openid/djopenid/templates/consumer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Django OpenID Example Consumer 4 | 29 | 30 | 31 | 32 |
33 | 34 |

35 | This is an example consumer built for the Django framework. Enter 36 | an OpenID in the box below. 37 |

38 | 39 | {% if error %} 40 |
{{ error|escape }}
41 | {% endif %} 42 | 43 | {% if url %} 44 |
45 | OpenID authentication succeeded; you authenticated as 46 | {{ url|escape }}. 47 | 48 |

49 | {% if sreg %} 50 | Simple Registration data returned: 51 | 52 |

    53 | {% for pair in sreg %} 54 |
  • {{ pair.0 }}: {{ pair.1 }}
  • 55 | {% endfor %} 56 |
57 | {% else %} 58 | The server returned no Simple Registration data. 59 | {% endif %} 60 | 61 | {% if ax %} 62 | Attribute Exchange data returned: 63 | 64 |
    65 | {% for pair in ax %} 66 |
  • {{ pair.0 }}: {{ pair.1|join:", " }}
  • 67 | {% endfor %} 68 |
69 | {% else %} 70 | The server returned no Attribute Exchange data. 71 | {% endif %} 72 | 73 | {% if pape %} 74 | An authentication policy response contained these policies: 75 | 76 |
    77 | {% for uri in pape.auth_policies %} 78 |
  • {{ uri }}
  • 79 | {% endfor %} 80 |
81 | {% else %} 82 | The server returned no authentication policy data (PAPE). 83 | {% endif %} 84 |

85 |
86 | {% endif %} 87 | 88 | {% if message %} 89 |
90 | {{ message|escape }} 91 |
92 | {% endif %} 93 | 94 | {% if failure_reason %} 95 |
96 | {{ failure_reason|escape }} 97 |
98 | {% endif %} 99 | 100 |
101 | 102 | 103 |

104 | Request these authentication policies 105 | (PAPE): 106 | 107 | 108 | {% for pair in pape_policies %} 109 | 110 | 111 | 116 | 117 | {% endfor %} 118 |
112 | 115 |
119 |

120 | 121 | 122 |
123 | 124 |
125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /test/unit/openid/cryptutil.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | import os.path 4 | 5 | from openid import cryptutil 6 | 7 | # Most of the purpose of this test is to make sure that cryptutil can 8 | # find a good source of randomness on this machine. 9 | 10 | def test_cryptrand(): 11 | # It's possible, but HIGHLY unlikely that a correct implementation 12 | # will fail by returning the same number twice 13 | 14 | s = cryptutil.getBytes(32) 15 | t = cryptutil.getBytes(32) 16 | assert len(s) == 32 17 | assert len(t) == 32 18 | assert s != t 19 | 20 | a = cryptutil.randrange(2L ** 128) 21 | b = cryptutil.randrange(2L ** 128) 22 | assert type(a) is long 23 | assert type(b) is long 24 | assert b != a 25 | 26 | # Make sure that we can generate random numbers that are larger 27 | # than platform int size 28 | cryptutil.randrange(long(sys.maxint) + 1L) 29 | 30 | def test_reversed(): 31 | if hasattr(cryptutil, 'reversed'): 32 | cases = [ 33 | ('', ''), 34 | ('a', 'a'), 35 | ('ab', 'ba'), 36 | ('abc', 'cba'), 37 | ('abcdefg', 'gfedcba'), 38 | ([], []), 39 | ([1], [1]), 40 | ([1,2], [2,1]), 41 | ([1,2,3], [3,2,1]), 42 | (range(1000), range(999, -1, -1)), 43 | ] 44 | 45 | for case, expected in cases: 46 | expected = list(expected) 47 | actual = list(cryptutil.reversed(case)) 48 | assert actual == expected, (case, expected, actual) 49 | twice = list(cryptutil.reversed(actual)) 50 | assert twice == list(case), (actual, case, twice) 51 | 52 | def test_binaryLongConvert(): 53 | MAX = sys.maxint 54 | for iteration in xrange(500): 55 | n = 0L 56 | for i in range(10): 57 | n += long(random.randrange(MAX)) 58 | 59 | s = cryptutil.longToBinary(n) 60 | assert type(s) is str 61 | n_prime = cryptutil.binaryToLong(s) 62 | assert n == n_prime, (n, n_prime) 63 | 64 | cases = [ 65 | ('\x00', 0L), 66 | ('\x01', 1L), 67 | ('\x7F', 127L), 68 | ('\x00\xFF', 255L), 69 | ('\x00\x80', 128L), 70 | ('\x00\x81', 129L), 71 | ('\x00\x80\x00', 32768L), 72 | ('OpenID is cool', 1611215304203901150134421257416556L) 73 | ] 74 | 75 | for s, n in cases: 76 | n_prime = cryptutil.binaryToLong(s) 77 | s_prime = cryptutil.longToBinary(n) 78 | assert n == n_prime, (s, n, n_prime) 79 | assert s == s_prime, (n, s, s_prime) 80 | 81 | def test_longToBase64(): 82 | f = file(os.path.join(os.path.dirname(__file__), 'n2b64')) 83 | try: 84 | for line in f: 85 | parts = line.strip().split(' ') 86 | assert parts[0] == cryptutil.longToBase64(long(parts[1])) 87 | finally: 88 | f.close() 89 | 90 | def test_base64ToLong(): 91 | f = file(os.path.join(os.path.dirname(__file__), 'n2b64')) 92 | try: 93 | for line in f: 94 | parts = line.strip().split(' ') 95 | assert long(parts[1]) == cryptutil.base64ToLong(parts[0]) 96 | finally: 97 | f.close() 98 | 99 | 100 | def test(): 101 | test_reversed() 102 | test_binaryLongConvert() 103 | test_cryptrand() 104 | test_longToBase64() 105 | test_base64ToLong() 106 | 107 | if __name__ == '__main__': 108 | test() 109 | -------------------------------------------------------------------------------- /examples/appengine/djangodemo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Yahoo! Python SDK 3 | 4 | * Yahoo! Query Language 5 | * Yahoo! Social API 6 | 7 | Find documentation and support on Yahoo! Developer Network: http://developer.yahoo.com 8 | 9 | Hosted on GitHub: http://github.com/yahoo/yos-social-python/tree/master 10 | 11 | @copyright: Copyrights for code authored by Yahoo! Inc. is licensed under the following terms: 12 | @license: BSD Open Source License 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | THE SOFTWARE. 31 | """ 32 | 33 | __author__ = 'Dustin Whittle ' 34 | __version__ = '0.1' 35 | 36 | ############################################################################## 37 | # Requires: Python 2.6 + oauth + simplejson # 38 | # Install dependencies at system level: easy_install oauth simplejson # 39 | ############################################################################## 40 | 41 | # import required modules 42 | import os, sys, getopt, pprint, pickle, logging 43 | 44 | # update sys path to include bundled modules with priority 45 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'sdk/')) 46 | 47 | import oauthlib.oauth 48 | 49 | import yahoo.oauth, yahoo.yql, yahoo.application 50 | 51 | 52 | # google app engine: django 1.0 support 53 | from google.appengine.dist import use_library 54 | use_library('django', '1.0') 55 | 56 | from google.appengine.ext.webapp import util 57 | 58 | # Force Django to reload its settings. 59 | from django.conf import settings 60 | settings._target = None 61 | 62 | # Must set this env var before importing any part of Django 63 | os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' 64 | 65 | import logging 66 | import django.core.handlers.wsgi 67 | import django.core.signals 68 | import django.db 69 | import django.dispatch.dispatcher 70 | 71 | def log_exception(*args, **kwds): 72 | logging.exception('Exception in request:') 73 | 74 | # Log errors. 75 | django.dispatch.dispatcher.connect( log_exception, django.core.signals.got_request_exception) 76 | 77 | # Unregister the rollback event handler. 78 | django.dispatch.dispatcher.disconnect(django.db._rollback_on_exception,django.core.signals.got_request_exception) 79 | 80 | def main(): 81 | 82 | # Create a Django application for WSGI. 83 | application = django.core.handlers.wsgi.WSGIHandler() 84 | 85 | 86 | # Run the WSGI CGI handler with that application. 87 | util.run_wsgi_app(application) 88 | 89 | if __name__ == '__main__': 90 | main() 91 | -------------------------------------------------------------------------------- /test/unit/openid/test_nonce.py: -------------------------------------------------------------------------------- 1 | from openid.test import datadriven 2 | import time 3 | import unittest 4 | import re 5 | 6 | from openid.store.nonce import \ 7 | mkNonce, \ 8 | split as splitNonce, \ 9 | checkTimestamp 10 | 11 | nonce_re = re.compile(r'\A\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ') 12 | 13 | class NonceTest(unittest.TestCase): 14 | def test_mkNonce(self): 15 | nonce = mkNonce() 16 | self.failUnless(nonce_re.match(nonce)) 17 | self.failUnless(len(nonce) == 26) 18 | 19 | def test_mkNonce_when(self): 20 | nonce = mkNonce(0) 21 | self.failUnless(nonce_re.match(nonce)) 22 | self.failUnless(nonce.startswith('1970-01-01T00:00:00Z')) 23 | self.failUnless(len(nonce) == 26) 24 | 25 | def test_splitNonce(self): 26 | s = '1970-01-01T00:00:00Z' 27 | expected_t = 0 28 | expected_salt = '' 29 | actual_t, actual_salt = splitNonce(s) 30 | self.failUnlessEqual(expected_t, actual_t) 31 | self.failUnlessEqual(expected_salt, actual_salt) 32 | 33 | def test_mkSplit(self): 34 | t = 42 35 | nonce_str = mkNonce(t) 36 | self.failUnless(nonce_re.match(nonce_str)) 37 | et, salt = splitNonce(nonce_str) 38 | self.failUnlessEqual(len(salt), 6) 39 | self.failUnlessEqual(et, t) 40 | 41 | class BadSplitTest(datadriven.DataDrivenTestCase): 42 | cases = [ 43 | '', 44 | '1970-01-01T00:00:00+1:00', 45 | '1969-01-01T00:00:00Z', 46 | '1970-00-01T00:00:00Z', 47 | '1970.01-01T00:00:00Z', 48 | 'Thu Sep 7 13:29:31 PDT 2006', 49 | 'monkeys', 50 | ] 51 | 52 | def __init__(self, nonce_str): 53 | datadriven.DataDrivenTestCase.__init__(self, nonce_str) 54 | self.nonce_str = nonce_str 55 | 56 | def runOneTest(self): 57 | self.failUnlessRaises(ValueError, splitNonce, self.nonce_str) 58 | 59 | class CheckTimestampTest(datadriven.DataDrivenTestCase): 60 | cases = [ 61 | # exact, no allowed skew 62 | ('1970-01-01T00:00:00Z', 0, 0, True), 63 | 64 | # exact, large skew 65 | ('1970-01-01T00:00:00Z', 1000, 0, True), 66 | 67 | # no allowed skew, one second old 68 | ('1970-01-01T00:00:00Z', 0, 1, False), 69 | 70 | # many seconds old, outside of skew 71 | ('1970-01-01T00:00:00Z', 10, 50, False), 72 | 73 | # one second old, one second skew allowed 74 | ('1970-01-01T00:00:00Z', 1, 1, True), 75 | 76 | # One second in the future, one second skew allowed 77 | ('1970-01-01T00:00:02Z', 1, 1, True), 78 | 79 | # two seconds in the future, one second skew allowed 80 | ('1970-01-01T00:00:02Z', 1, 0, False), 81 | 82 | # malformed nonce string 83 | ('monkeys', 0, 0, False), 84 | ] 85 | 86 | def __init__(self, nonce_string, allowed_skew, now, expected): 87 | datadriven.DataDrivenTestCase.__init__( 88 | self, repr((nonce_string, allowed_skew, now))) 89 | self.nonce_string = nonce_string 90 | self.allowed_skew = allowed_skew 91 | self.now = now 92 | self.expected = expected 93 | 94 | def runOneTest(self): 95 | actual = checkTimestamp(self.nonce_string, self.allowed_skew, self.now) 96 | self.failUnlessEqual(bool(self.expected), bool(actual)) 97 | 98 | def pyUnitTests(): 99 | return datadriven.loadTests(__name__) 100 | 101 | if __name__ == '__main__': 102 | suite = pyUnitTests() 103 | runner = unittest.TextTestRunner() 104 | runner.run(suite) 105 | -------------------------------------------------------------------------------- /test/unit/opensocial/opensocial_tests/orkut_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | import unittest 22 | import urllib2 23 | 24 | import opensocial 25 | 26 | from opensocial import oauth 27 | from opensocial import request 28 | 29 | 30 | class TestOrkut(unittest.TestCase): 31 | 32 | def setUp(self): 33 | self.config = opensocial.ContainerConfig( 34 | oauth_consumer_key='orkut.com:623061448914', 35 | oauth_consumer_secret='uynAeXiWTisflWX99KU1D2q5', 36 | server_rpc_base='http://sandbox.orkut.com/social/rpc', 37 | server_rest_base='http://sandbox.orkut.com/social/rest') 38 | self.container = opensocial.ContainerContext(self.config) 39 | self.user_id = '03067092798963641994' 40 | 41 | def validate_user(self, user): 42 | self.assertEquals(self.user_id, user.get_id()) 43 | 44 | def validate_friends(self, friends): 45 | self.assertEquals(6, len(friends)) 46 | self.assertEquals(0, friends.startIndex) 47 | self.assertEquals(6, friends.totalResults) 48 | self.assertEquals('13314698784882897227', friends[0].get_id()) 49 | self.assertEquals('04285289033838943214', friends[1].get_id()) 50 | 51 | def do_fetch_person(self, use_rpc, fields=None): 52 | self.container.set_allow_rpc(use_rpc) 53 | person = self.container.fetch_person(self.user_id, fields) 54 | return person 55 | 56 | def do_fetch_friends(self, use_rpc, fields=None): 57 | self.container.set_allow_rpc(use_rpc) 58 | friends = self.container.fetch_friends(self.user_id, fields) 59 | return friends 60 | 61 | def test_fetch_person_rpc(self): 62 | person = self.do_fetch_person(True) 63 | self.validate_user(person) 64 | 65 | def test_fetch_person_rest(self): 66 | person = self.do_fetch_person(False) 67 | self.validate_user(person) 68 | 69 | def test_fetch_friends_rpc(self): 70 | friends = self.do_fetch_friends(True) 71 | self.validate_friends(friends) 72 | 73 | def test_fetch_friends_rest(self): 74 | friends = self.do_fetch_friends(False) 75 | self.validate_friends(friends) 76 | 77 | def test_fetch_person_fields_rpc(self): 78 | person = self.do_fetch_person(True, ['gender']) 79 | self.assertEquals('male', person.get_field('gender')) 80 | 81 | def test_fetch_person_fields_rest(self): 82 | person = self.do_fetch_person(False, ['gender']) 83 | self.assertEquals('male', person.get_field('gender')) 84 | 85 | def test_batch(self): 86 | batch = opensocial.request.RequestBatch() 87 | batch.add_request('me', 88 | opensocial.request.FetchPersonRequest(self.user_id)) 89 | batch.add_request('friends', 90 | opensocial.request.FetchPeopleRequest(self.user_id, 91 | '@friends')) 92 | batch.send(self.container) 93 | 94 | me = batch.get('me') 95 | friends = batch.get('friends') 96 | self.validate_user(me) 97 | self.validate_friends(friends) -------------------------------------------------------------------------------- /test/unit/openid/data/accept.txt: -------------------------------------------------------------------------------- 1 | # Accept: [Accept: header value from RFC2616, 2 | # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html] 3 | # Available: [whitespace-separated content types] 4 | # Expected: [Accept-header like list, containing the available content 5 | # types with their q-values] 6 | 7 | Accept: */* 8 | Available: text/plain 9 | Expected: text/plain; q=1.0 10 | 11 | Accept: */* 12 | Available: text/plain, text/html 13 | Expected: text/plain; q=1.0, text/html; q=1.0 14 | 15 | # The order matters 16 | Accept: */* 17 | Available: text/html, text/plain 18 | Expected: text/html; q=1.0, text/plain; q=1.0 19 | 20 | Accept: text/*, */*; q=0.9 21 | Available: text/plain, image/jpeg 22 | Expected: text/plain; q=1.0, image/jpeg; q=0.9 23 | 24 | Accept: text/*, */*; q=0.9 25 | Available: image/jpeg, text/plain 26 | Expected: text/plain; q=1.0, image/jpeg; q=0.9 27 | 28 | # wildcard subtypes still reject differing main types 29 | Accept: text/* 30 | Available: image/jpeg, text/plain 31 | Expected: text/plain; q=1.0 32 | 33 | Accept: text/html 34 | Available: text/html 35 | Expected: text/html; q=1.0 36 | 37 | Accept: text/html, text/* 38 | Available: text/html 39 | Expected: text/html; q=1.0 40 | 41 | Accept: text/html, text/* 42 | Available: text/plain, text/html 43 | Expected: text/plain; q=1.0, text/html; q=1.0 44 | 45 | Accept: text/html, text/*; q=0.9 46 | Available: text/plain, text/html 47 | Expected: text/html; q=1.0, text/plain; q=0.9 48 | 49 | # If a more specific type has a higher q-value, then the higher value wins 50 | Accept: text/*; q=0.9, text/html 51 | Available: text/plain, text/html 52 | Expected: text/html; q=1.0, text/plain; q=0.9 53 | 54 | Accept: */*, text/*; q=0.9, text/html; q=0.1 55 | Available: text/plain, text/html, image/monkeys 56 | Expected: image/monkeys; q=1.0, text/plain; q=0.9, text/html; q=0.1 57 | 58 | Accept: text/*, text/html; q=0 59 | Available: text/html 60 | Expected: 61 | 62 | Accept: text/*, text/html; q=0 63 | Available: text/html, text/plain 64 | Expected: text/plain; q=1.0 65 | 66 | Accept: text/html 67 | Available: text/plain 68 | Expected: 69 | 70 | Accept: application/xrds+xml, text/html; q=0.9 71 | Available: application/xrds+xml, text/html 72 | Expected: application/xrds+xml; q=1.0, text/html; q=0.9 73 | 74 | Accept: application/xrds+xml, */*; q=0.9 75 | Available: application/xrds+xml, text/html 76 | Expected: application/xrds+xml; q=1.0, text/html; q=0.9 77 | 78 | Accept: application/xrds+xml, application/xhtml+xml; q=0.9, text/html; q=0.8, text/xml; q=0.7 79 | Available: application/xrds+xml, text/html 80 | Expected: application/xrds+xml; q=1.0, text/html; q=0.8 81 | 82 | # See http://www.rfc-editor.org/rfc/rfc3023.txt, section A.13 83 | Accept: application/xrds 84 | Available: application/xrds+xml 85 | Expected: 86 | 87 | Accept: application/xrds+xml 88 | Available: application/xrds 89 | Expected: 90 | 91 | Accept: application/xml 92 | Available: application/xrds+xml 93 | Expected: 94 | 95 | Available: application/xrds+xml 96 | Accept: application/xml 97 | Expected: 98 | 99 | 100 | 101 | ################################################# 102 | # The tests below this line are documentation of how this library 103 | # works. If the implementation changes, it's acceptable to change the 104 | # test to reflect that. These are specified so that we can make sure 105 | # that the current implementation actually works the way that we 106 | # expect it to given these inputs. 107 | 108 | Accept: text/html;level=1 109 | Available: text/html 110 | Expected: text/html; q=1.0 111 | 112 | Accept: text/html; level=1, text/html; level=9; q=0.1 113 | Available: text/html 114 | Expected: text/html; q=1.0 115 | 116 | Accept: text/html; level=9; q=0.1, text/html; level=1 117 | Available: text/html 118 | Expected: text/html; q=1.0 119 | -------------------------------------------------------------------------------- /src/openid/kvform.py: -------------------------------------------------------------------------------- 1 | __all__ = ['seqToKV', 'kvToSeq', 'dictToKV', 'kvToDict'] 2 | 3 | from openid import oidutil 4 | 5 | import types 6 | 7 | class KVFormError(ValueError): 8 | pass 9 | 10 | def seqToKV(seq, strict=False): 11 | """Represent a sequence of pairs of strings as newline-terminated 12 | key:value pairs. The pairs are generated in the order given. 13 | 14 | @param seq: The pairs 15 | @type seq: [(str, (unicode|str))] 16 | 17 | @return: A string representation of the sequence 18 | @rtype: str 19 | """ 20 | def err(msg): 21 | formatted = 'seqToKV warning: %s: %r' % (msg, seq) 22 | if strict: 23 | raise KVFormError(formatted) 24 | else: 25 | oidutil.log(formatted) 26 | 27 | lines = [] 28 | for k, v in seq: 29 | if isinstance(k, types.StringType): 30 | k = k.decode('UTF8') 31 | elif not isinstance(k, types.UnicodeType): 32 | err('Converting key to string: %r' % k) 33 | k = str(k) 34 | 35 | if '\n' in k: 36 | raise KVFormError( 37 | 'Invalid input for seqToKV: key contains newline: %r' % (k,)) 38 | 39 | if ':' in k: 40 | raise KVFormError( 41 | 'Invalid input for seqToKV: key contains colon: %r' % (k,)) 42 | 43 | if k.strip() != k: 44 | err('Key has whitespace at beginning or end: %r' % (k,)) 45 | 46 | if isinstance(v, types.StringType): 47 | v = v.decode('UTF8') 48 | elif not isinstance(v, types.UnicodeType): 49 | err('Converting value to string: %r' % (v,)) 50 | v = str(v) 51 | 52 | if '\n' in v: 53 | raise KVFormError( 54 | 'Invalid input for seqToKV: value contains newline: %r' % (v,)) 55 | 56 | if v.strip() != v: 57 | err('Value has whitespace at beginning or end: %r' % (v,)) 58 | 59 | lines.append(k + ':' + v + '\n') 60 | 61 | return ''.join(lines).encode('UTF8') 62 | 63 | def kvToSeq(data, strict=False): 64 | """ 65 | 66 | After one parse, seqToKV and kvToSeq are inverses, with no warnings:: 67 | 68 | seq = kvToSeq(s) 69 | seqToKV(kvToSeq(seq)) == seq 70 | """ 71 | def err(msg): 72 | formatted = 'kvToSeq warning: %s: %r' % (msg, data) 73 | if strict: 74 | raise KVFormError(formatted) 75 | else: 76 | oidutil.log(formatted) 77 | 78 | lines = data.split('\n') 79 | if lines[-1]: 80 | err('Does not end in a newline') 81 | else: 82 | del lines[-1] 83 | 84 | pairs = [] 85 | line_num = 0 86 | for line in lines: 87 | line_num += 1 88 | 89 | # Ignore blank lines 90 | if not line.strip(): 91 | continue 92 | 93 | pair = line.split(':', 1) 94 | if len(pair) == 2: 95 | k, v = pair 96 | k_s = k.strip() 97 | if k_s != k: 98 | fmt = ('In line %d, ignoring leading or trailing ' 99 | 'whitespace in key %r') 100 | err(fmt % (line_num, k)) 101 | 102 | if not k_s: 103 | err('In line %d, got empty key' % (line_num,)) 104 | 105 | v_s = v.strip() 106 | if v_s != v: 107 | fmt = ('In line %d, ignoring leading or trailing ' 108 | 'whitespace in value %r') 109 | err(fmt % (line_num, v)) 110 | 111 | pairs.append((k_s.decode('UTF8'), v_s.decode('UTF8'))) 112 | else: 113 | err('Line %d does not contain a colon' % line_num) 114 | 115 | return pairs 116 | 117 | def dictToKV(d): 118 | seq = d.items() 119 | seq.sort() 120 | return seqToKV(seq) 121 | 122 | def kvToDict(s): 123 | return dict(kvToSeq(s)) 124 | -------------------------------------------------------------------------------- /src/opensocial/data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2007, 2008 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | 18 | __author__ = 'davidbyttow@google.com (David Byttow)' 19 | 20 | 21 | def extract_fields(json): 22 | """Extracts a JSON dict of fields. 23 | 24 | REST and RPC protocols use different JSON keys for OpenSocial objects. This 25 | abstracts that and handles both cases. 26 | 27 | Args: 28 | json: dict The JSON object. 29 | 30 | Returns: A JSON dict of field/value pairs. 31 | 32 | """ 33 | return json.get('entry') or json 34 | 35 | 36 | class Object(dict): 37 | """Generic container for opensocial.* objects.""" 38 | 39 | def get_field(self, name): 40 | """Retrieves a specific field value for this Object. 41 | 42 | N.B.: Deprecated in favor of type dict methods. 43 | 44 | Returns: The field value. 45 | 46 | """ 47 | return self.get(name) 48 | 49 | 50 | class Person(Object): 51 | """An opensocial.Person representation.""" 52 | 53 | def __init__(self, fields): 54 | super(Person, self).__init__(fields) 55 | 56 | def get_id(self): 57 | """Returns the id of this Person. 58 | 59 | Returns: The container-specific id of this Person. 60 | 61 | """ 62 | return self.get_field('id') 63 | 64 | def get_display_name(self): 65 | """Returns the full name of this Person. 66 | 67 | Returns: The full name of this Person. 68 | 69 | """ 70 | display_name = self.get_field('displayName') 71 | if display_name: 72 | return display_name 73 | names = self.get_field('name') 74 | if names: 75 | return '%s %s' % (names['givenName'], names['familyName']) 76 | return '' 77 | 78 | @staticmethod 79 | def parse_json(json): 80 | """Creates a Person object from a JSON dict of fields. 81 | Args: 82 | json: dict The Person fields. 83 | 84 | Returns: A Person object. 85 | 86 | """ 87 | return Person(extract_fields(json)) 88 | 89 | 90 | class AppData(Object): 91 | 92 | def __init__(self, data): 93 | super(AppData, self).__init__(data) 94 | 95 | @staticmethod 96 | def parse_json(json): 97 | return AppData(extract_fields(json)) 98 | 99 | 100 | class Collection(list): 101 | """Contains a collection of OpenSocial objects. 102 | 103 | Handles the parsing of a JSON object and creation of the associated OpenSocial 104 | data object. 105 | 106 | """ 107 | 108 | def __init__(self, items, start, total): 109 | for v in items: 110 | self.append(v) 111 | self.startIndex = start 112 | self.totalResults = total 113 | 114 | @staticmethod 115 | def parse_json(json, cls): 116 | """Creates a collection from a JSON object returned by an OpenSocial 117 | container. 118 | 119 | Args: 120 | json: dict The JSON object. 121 | cls: The OpenSocial data type to instantiate for each entry in the 122 | collection. 123 | 124 | Returns: A Collection of OpenSocial objects. 125 | 126 | """ 127 | 128 | start = json.get('startIndex') 129 | total = json.get('totalResults') 130 | items = [] 131 | json_list = json.get('entry') or json.get('list') 132 | for fields in json_list: 133 | items.append(cls(fields)) 134 | return Collection(items, start, total) 135 | -------------------------------------------------------------------------------- /test/unit/openid/test_accept.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os.path 3 | from openid.yadis import accept 4 | 5 | def getTestData(): 6 | """Read the test data off of disk 7 | 8 | () -> [(int, str)] 9 | """ 10 | filename = os.path.join(os.path.dirname(__file__), 'data', 'accept.txt') 11 | i = 1 12 | lines = [] 13 | for line in file(filename): 14 | lines.append((i, line)) 15 | i += 1 16 | return lines 17 | 18 | def chunk(lines): 19 | """Return groups of lines separated by whitespace or comments 20 | 21 | [(int, str)] -> [[(int, str)]] 22 | """ 23 | chunks = [] 24 | chunk = [] 25 | for lineno, line in lines: 26 | stripped = line.strip() 27 | if not stripped or stripped[0] == '#': 28 | if chunk: 29 | chunks.append(chunk) 30 | chunk = [] 31 | else: 32 | chunk.append((lineno, stripped)) 33 | 34 | if chunk: 35 | chunks.append(chunk) 36 | 37 | return chunks 38 | 39 | def parseLines(chunk): 40 | """Take the given chunk of lines and turn it into a test data dictionary 41 | 42 | [(int, str)] -> {str:(int, str)} 43 | """ 44 | items = {} 45 | for (lineno, line) in chunk: 46 | header, data = line.split(':', 1) 47 | header = header.lower() 48 | items[header] = (lineno, data.strip()) 49 | 50 | return items 51 | 52 | def parseAvailable(available_text): 53 | """Parse an Available: line's data 54 | 55 | str -> [str] 56 | """ 57 | return [s.strip() for s in available_text.split(',')] 58 | 59 | def parseExpected(expected_text): 60 | """Parse an Expected: line's data 61 | 62 | str -> [(str, float)] 63 | """ 64 | expected = [] 65 | if expected_text: 66 | for chunk in expected_text.split(','): 67 | chunk = chunk.strip() 68 | mtype, qstuff = chunk.split(';') 69 | mtype = mtype.strip() 70 | assert '/' in mtype 71 | qstuff = qstuff.strip() 72 | q, qstr = qstuff.split('=') 73 | assert q == 'q' 74 | qval = float(qstr) 75 | expected.append((mtype, qval)) 76 | 77 | return expected 78 | 79 | class MatchAcceptTest(unittest.TestCase): 80 | def __init__(self, descr, accept_header, available, expected): 81 | unittest.TestCase.__init__(self) 82 | self.accept_header = accept_header 83 | self.available = available 84 | self.expected = expected 85 | self.descr = descr 86 | 87 | def shortDescription(self): 88 | return self.descr 89 | 90 | def runTest(self): 91 | accepted = accept.parseAcceptHeader(self.accept_header) 92 | actual = accept.matchTypes(accepted, self.available) 93 | self.failUnlessEqual(self.expected, actual) 94 | 95 | def pyUnitTests(): 96 | lines = getTestData() 97 | chunks = chunk(lines) 98 | data_sets = map(parseLines, chunks) 99 | cases = [] 100 | for data in data_sets: 101 | lnos = [] 102 | lno, header = data['accept'] 103 | lnos.append(lno) 104 | lno, avail_data = data['available'] 105 | lnos.append(lno) 106 | try: 107 | available = parseAvailable(avail_data) 108 | except: 109 | print 'On line', lno 110 | raise 111 | 112 | lno, exp_data = data['expected'] 113 | lnos.append(lno) 114 | try: 115 | expected = parseExpected(exp_data) 116 | except: 117 | print 'On line', lno 118 | raise 119 | 120 | descr = 'MatchAcceptTest for lines %r' % (lnos,) 121 | case = MatchAcceptTest(descr, header, available, expected) 122 | cases.append(case) 123 | return unittest.TestSuite(cases) 124 | 125 | if __name__ == '__main__': 126 | runner = unittest.TextTestRunner() 127 | runner.run(loadTests()) 128 | -------------------------------------------------------------------------------- /examples/openid/djopenid/server/tests.py: -------------------------------------------------------------------------------- 1 | 2 | from django.test.testcases import TestCase 3 | from djopenid.server import views 4 | from djopenid import util 5 | 6 | from django.http import HttpRequest 7 | from django.contrib.sessions.middleware import SessionWrapper 8 | 9 | from openid.server.server import CheckIDRequest 10 | from openid.message import Message 11 | from openid.yadis.constants import YADIS_CONTENT_TYPE 12 | from openid.yadis.services import applyFilter 13 | 14 | def dummyRequest(): 15 | request = HttpRequest() 16 | request.session = SessionWrapper("test") 17 | request.META['HTTP_HOST'] = 'example.invalid' 18 | request.META['SERVER_PROTOCOL'] = 'HTTP' 19 | return request 20 | 21 | class TestProcessTrustResult(TestCase): 22 | def setUp(self): 23 | self.request = dummyRequest() 24 | 25 | id_url = util.getViewURL(self.request, views.idPage) 26 | 27 | # Set up the OpenID request we're responding to. 28 | op_endpoint = 'http://127.0.0.1:8080/endpoint' 29 | message = Message.fromPostArgs({ 30 | 'openid.mode': 'checkid_setup', 31 | 'openid.identity': id_url, 32 | 'openid.return_to': 'http://127.0.0.1/%s' % (self.id(),), 33 | 'openid.sreg.required': 'postcode', 34 | }) 35 | self.openid_request = CheckIDRequest.fromMessage(message, op_endpoint) 36 | 37 | views.setRequest(self.request, self.openid_request) 38 | 39 | 40 | def test_allow(self): 41 | self.request.POST['allow'] = 'Yes' 42 | 43 | response = views.processTrustResult(self.request) 44 | 45 | self.failUnlessEqual(response.status_code, 302) 46 | finalURL = response['location'] 47 | self.failUnless('openid.mode=id_res' in finalURL, finalURL) 48 | self.failUnless('openid.identity=' in finalURL, finalURL) 49 | self.failUnless('openid.sreg.postcode=12345' in finalURL, finalURL) 50 | 51 | def test_cancel(self): 52 | self.request.POST['cancel'] = 'Yes' 53 | 54 | response = views.processTrustResult(self.request) 55 | 56 | self.failUnlessEqual(response.status_code, 302) 57 | finalURL = response['location'] 58 | self.failUnless('openid.mode=cancel' in finalURL, finalURL) 59 | self.failIf('openid.identity=' in finalURL, finalURL) 60 | self.failIf('openid.sreg.postcode=12345' in finalURL, finalURL) 61 | 62 | 63 | 64 | class TestShowDecidePage(TestCase): 65 | def test_unreachableRealm(self): 66 | self.request = dummyRequest() 67 | 68 | id_url = util.getViewURL(self.request, views.idPage) 69 | 70 | # Set up the OpenID request we're responding to. 71 | op_endpoint = 'http://127.0.0.1:8080/endpoint' 72 | message = Message.fromPostArgs({ 73 | 'openid.mode': 'checkid_setup', 74 | 'openid.identity': id_url, 75 | 'openid.return_to': 'http://unreachable.invalid/%s' % (self.id(),), 76 | 'openid.sreg.required': 'postcode', 77 | }) 78 | self.openid_request = CheckIDRequest.fromMessage(message, op_endpoint) 79 | 80 | views.setRequest(self.request, self.openid_request) 81 | 82 | response = views.showDecidePage(self.request, self.openid_request) 83 | self.failUnless('trust_root_valid is Unreachable' in response.content, 84 | response) 85 | 86 | 87 | 88 | class TestGenericXRDS(TestCase): 89 | def test_genericRender(self): 90 | """Render an XRDS document with a single type URI and a single endpoint URL 91 | Parse it to see that it matches.""" 92 | request = dummyRequest() 93 | 94 | type_uris = ['A_TYPE'] 95 | endpoint_url = 'A_URL' 96 | response = util.renderXRDS(request, type_uris, [endpoint_url]) 97 | 98 | requested_url = 'http://requested.invalid/' 99 | (endpoint,) = applyFilter(requested_url, response.content) 100 | 101 | self.failUnlessEqual(YADIS_CONTENT_TYPE, response['Content-Type']) 102 | self.failUnlessEqual(type_uris, endpoint.type_uris) 103 | self.failUnlessEqual(endpoint_url, endpoint.uri) 104 | -------------------------------------------------------------------------------- /src/openid/store/memstore.py: -------------------------------------------------------------------------------- 1 | """A simple store using only in-process memory.""" 2 | 3 | from openid.store import nonce 4 | 5 | import copy 6 | import time 7 | 8 | class ServerAssocs(object): 9 | def __init__(self): 10 | self.assocs = {} 11 | 12 | def set(self, assoc): 13 | self.assocs[assoc.handle] = assoc 14 | 15 | def get(self, handle): 16 | return self.assocs.get(handle) 17 | 18 | def remove(self, handle): 19 | try: 20 | del self.assocs[handle] 21 | except KeyError: 22 | return False 23 | else: 24 | return True 25 | 26 | def best(self): 27 | """Returns association with the oldest issued date. 28 | 29 | or None if there are no associations. 30 | """ 31 | best = None 32 | for assoc in self.assocs.values(): 33 | if best is None or best.issued < assoc.issued: 34 | best = assoc 35 | return best 36 | 37 | def cleanup(self): 38 | """Remove expired associations. 39 | 40 | @return: tuple of (removed associations, remaining associations) 41 | """ 42 | remove = [] 43 | for handle, assoc in self.assocs.iteritems(): 44 | if assoc.getExpiresIn() == 0: 45 | remove.append(handle) 46 | for handle in remove: 47 | del self.assocs[handle] 48 | return len(remove), len(self.assocs) 49 | 50 | 51 | 52 | class MemoryStore(object): 53 | """In-process memory store. 54 | 55 | Use for single long-running processes. No persistence supplied. 56 | """ 57 | def __init__(self): 58 | self.server_assocs = {} 59 | self.nonces = {} 60 | 61 | def _getServerAssocs(self, server_url): 62 | try: 63 | return self.server_assocs[server_url] 64 | except KeyError: 65 | assocs = self.server_assocs[server_url] = ServerAssocs() 66 | return assocs 67 | 68 | def storeAssociation(self, server_url, assoc): 69 | assocs = self._getServerAssocs(server_url) 70 | assocs.set(copy.deepcopy(assoc)) 71 | 72 | def getAssociation(self, server_url, handle=None): 73 | assocs = self._getServerAssocs(server_url) 74 | if handle is None: 75 | return assocs.best() 76 | else: 77 | return assocs.get(handle) 78 | 79 | def removeAssociation(self, server_url, handle): 80 | assocs = self._getServerAssocs(server_url) 81 | return assocs.remove(handle) 82 | 83 | def useNonce(self, server_url, timestamp, salt): 84 | if abs(timestamp - time.time()) > nonce.SKEW: 85 | return False 86 | 87 | anonce = (str(server_url), int(timestamp), str(salt)) 88 | if anonce in self.nonces: 89 | return False 90 | else: 91 | self.nonces[anonce] = None 92 | return True 93 | 94 | def cleanupNonces(self): 95 | now = time.time() 96 | expired = [] 97 | for anonce in self.nonces.iterkeys(): 98 | if abs(anonce[1] - now) > nonce.SKEW: 99 | # removing items while iterating over the set could be bad. 100 | expired.append(anonce) 101 | 102 | for anonce in expired: 103 | del self.nonces[anonce] 104 | return len(expired) 105 | 106 | def cleanupAssociations(self): 107 | remove_urls = [] 108 | removed_assocs = 0 109 | for server_url, assocs in self.server_assocs.iteritems(): 110 | removed, remaining = assocs.cleanup() 111 | removed_assocs += removed 112 | if not remaining: 113 | remove_urls.append(server_url) 114 | 115 | # Remove entries from server_assocs that had none remaining. 116 | for server_url in remove_urls: 117 | del self.server_assocs[server_url] 118 | return removed_assocs 119 | 120 | def __eq__(self, other): 121 | return ((self.server_assocs == other.server_assocs) and 122 | (self.nonces == other.nonces)) 123 | 124 | def __ne__(self, other): 125 | return not (self == other) 126 | -------------------------------------------------------------------------------- /test/unit/openid/data/test1-parsehtml.txt: -------------------------------------------------------------------------------- 1 | found 2 | 3 | 4 | 5 | found 6 | 7 | 8 | 9 | found 10 | 11 | 12 | 13 | found 14 | 15 | 16 | 17 | found 18 | 19 | 20 | 21 | found 22 | 23 | 24 | 25 | found 26 | 27 | 28 | 29 | found 30 | 31 | 32 | 33 | EOF 34 | 35 |