summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2011-07-24 13:43:15 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2011-07-24 13:43:15 -0400
commitd6472e24fce0148fcd7c446347c2bea95dadcb7d (patch)
treeb8a28cbabccbd06303000f73ac1f486b7ebe644d
parent195923a015131f4b97b4bf752ad70e78d4886d58 (diff)
downloadaskbot-d6472e24fce0148fcd7c446347c2bea95dadcb7d.tar.gz
askbot-d6472e24fce0148fcd7c446347c2bea95dadcb7d.tar.bz2
askbot-d6472e24fce0148fcd7c446347c2bea95dadcb7d.zip
removed the bundled copy of python openid library
-rwxr-xr-x.gitignore1
-rw-r--r--askbot/deps/django_authopenid/forms.py2
-rw-r--r--askbot/deps/django_authopenid/util.py10
-rw-r--r--askbot/deps/django_authopenid/views.py8
-rw-r--r--askbot/deps/openid/__init__.py55
-rw-r--r--askbot/deps/openid/association.py555
-rw-r--r--askbot/deps/openid/consumer/__init__.py6
-rw-r--r--askbot/deps/openid/consumer/consumer.py1900
-rw-r--r--askbot/deps/openid/consumer/discover.py470
-rw-r--r--askbot/deps/openid/consumer/html_parse.py249
-rw-r--r--askbot/deps/openid/cryptutil.py220
-rw-r--r--askbot/deps/openid/dh.py42
-rw-r--r--askbot/deps/openid/extension.py46
-rw-r--r--askbot/deps/openid/extensions/__init__.py5
-rw-r--r--askbot/deps/openid/extensions/ax.py774
-rw-r--r--askbot/deps/openid/extensions/draft/__init__.py0
-rw-r--r--askbot/deps/openid/extensions/draft/pape2.py277
-rw-r--r--askbot/deps/openid/extensions/draft/pape5.py473
-rw-r--r--askbot/deps/openid/extensions/sreg.py518
-rw-r--r--askbot/deps/openid/fetchers.py427
-rw-r--r--askbot/deps/openid/kvform.py123
-rw-r--r--askbot/deps/openid/message.py631
-rw-r--r--askbot/deps/openid/oidutil.py190
-rw-r--r--askbot/deps/openid/server/__init__.py6
-rw-r--r--askbot/deps/openid/server/server.py1849
-rw-r--r--askbot/deps/openid/server/trustroot.py454
-rw-r--r--askbot/deps/openid/sreg.py7
-rw-r--r--askbot/deps/openid/store/__init__.py8
-rw-r--r--askbot/deps/openid/store/filestore.py426
-rw-r--r--askbot/deps/openid/store/interface.py197
-rw-r--r--askbot/deps/openid/store/memstore.py125
-rw-r--r--askbot/deps/openid/store/nonce.py98
-rw-r--r--askbot/deps/openid/store/sqlstore.py516
-rw-r--r--askbot/deps/openid/test/__init__.py0
-rw-r--r--askbot/deps/openid/test/cryptutil.py108
-rw-r--r--askbot/deps/openid/test/data/accept.txt118
-rw-r--r--askbot/deps/openid/test/data/example-xrds.xml14
-rw-r--r--askbot/deps/openid/test/data/openid-1.2-consumer-sqlitestore.dbbin7168 -> 0 bytes
-rw-r--r--askbot/deps/openid/test/data/test1-discover.txt137
-rw-r--r--askbot/deps/openid/test/data/test1-parsehtml.txt152
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid.html11
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid2.html11
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid2_xrds.xml12
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid2_xrds_no_local_id.xml11
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid_1_and_2.html11
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid_1_and_2_xrds.xml16
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml17
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid_and_yadis.html12
-rw-r--r--askbot/deps/openid/test/data/test_discover/openid_no_delegate.html10
-rw-r--r--askbot/deps/openid/test/data/test_discover/yadis_0entries.xml12
-rw-r--r--askbot/deps/openid/test/data/test_discover/yadis_2_bad_local_id.xml15
-rw-r--r--askbot/deps/openid/test/data/test_discover/yadis_2entries_delegate.xml22
-rw-r--r--askbot/deps/openid/test/data/test_discover/yadis_2entries_idp.xml21
-rw-r--r--askbot/deps/openid/test/data/test_discover/yadis_another_delegate.xml14
-rw-r--r--askbot/deps/openid/test/data/test_discover/yadis_idp.xml12
-rw-r--r--askbot/deps/openid/test/data/test_discover/yadis_idp_delegate.xml13
-rw-r--r--askbot/deps/openid/test/data/test_discover/yadis_no_delegate.xml11
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/README12
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/delegated-20060809-r1.xrds34
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/delegated-20060809-r2.xrds34
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/delegated-20060809.xrds34
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/no-xrd.xml7
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/not-xrds.xml2
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/prefixsometimes.xrds34
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/ref.xrds109
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/sometimesprefix.xrds34
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/spoof1.xrds25
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/spoof2.xrds25
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/spoof3.xrds37
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/status222.xrds9
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/subsegments.xrds58
-rw-r--r--askbot/deps/openid/test/data/test_etxrd/valid-populated-xrds.xml39
-rw-r--r--askbot/deps/openid/test/data/trustroot.txt150
-rw-r--r--askbot/deps/openid/test/datadriven.py47
-rw-r--r--askbot/deps/openid/test/dh.py70
-rw-r--r--askbot/deps/openid/test/dhpriv29
-rw-r--r--askbot/deps/openid/test/discoverdata.py125
-rw-r--r--askbot/deps/openid/test/kvform.py174
-rw-r--r--askbot/deps/openid/test/linkparse.py109
-rw-r--r--askbot/deps/openid/test/linkparse.txt584
-rw-r--r--askbot/deps/openid/test/n2b64650
-rw-r--r--askbot/deps/openid/test/oidutil.py176
-rw-r--r--askbot/deps/openid/test/storetest.py397
-rw-r--r--askbot/deps/openid/test/support.py51
-rw-r--r--askbot/deps/openid/test/test_accept.py127
-rw-r--r--askbot/deps/openid/test/test_association.py183
-rw-r--r--askbot/deps/openid/test/test_association_response.py340
-rw-r--r--askbot/deps/openid/test/test_auth_request.py206
-rw-r--r--askbot/deps/openid/test/test_ax.py626
-rw-r--r--askbot/deps/openid/test/test_consumer.py2097
-rw-r--r--askbot/deps/openid/test/test_discover.py783
-rw-r--r--askbot/deps/openid/test/test_etxrd.py194
-rw-r--r--askbot/deps/openid/test/test_examples.py185
-rw-r--r--askbot/deps/openid/test/test_extension.py36
-rw-r--r--askbot/deps/openid/test/test_fetchers.py285
-rw-r--r--askbot/deps/openid/test/test_htmldiscover.py21
-rw-r--r--askbot/deps/openid/test/test_message.py998
-rw-r--r--askbot/deps/openid/test/test_negotiation.py271
-rw-r--r--askbot/deps/openid/test/test_nonce.py104
-rw-r--r--askbot/deps/openid/test/test_openidyadis.py164
-rw-r--r--askbot/deps/openid/test/test_pape.py9
-rw-r--r--askbot/deps/openid/test/test_pape_draft2.py217
-rw-r--r--askbot/deps/openid/test/test_pape_draft5.py441
-rw-r--r--askbot/deps/openid/test/test_parsehtml.py82
-rw-r--r--askbot/deps/openid/test/test_rpverify.py246
-rw-r--r--askbot/deps/openid/test/test_server.py2064
-rw-r--r--askbot/deps/openid/test/test_services.py23
-rw-r--r--askbot/deps/openid/test/test_sreg.py484
-rw-r--r--askbot/deps/openid/test/test_symbol.py35
-rw-r--r--askbot/deps/openid/test/test_urinorm.py52
-rw-r--r--askbot/deps/openid/test/test_verifydisco.py270
-rw-r--r--askbot/deps/openid/test/test_xri.py102
-rw-r--r--askbot/deps/openid/test/test_xrires.py40
-rw-r--r--askbot/deps/openid/test/test_yadis_discover.py179
-rw-r--r--askbot/deps/openid/test/trustroot.py85
-rw-r--r--askbot/deps/openid/test/urinorm.txt87
-rw-r--r--askbot/deps/openid/urinorm.py202
-rw-r--r--askbot/deps/openid/yadis/__init__.py26
-rw-r--r--askbot/deps/openid/yadis/accept.py133
-rw-r--r--askbot/deps/openid/yadis/constants.py13
-rw-r--r--askbot/deps/openid/yadis/discover.py135
-rw-r--r--askbot/deps/openid/yadis/etxrd.py300
-rw-r--r--askbot/deps/openid/yadis/filters.py200
-rw-r--r--askbot/deps/openid/yadis/manager.py194
-rw-r--r--askbot/deps/openid/yadis/parsehtml.py197
-rw-r--r--askbot/deps/openid/yadis/services.py54
-rw-r--r--askbot/deps/openid/yadis/xri.py168
-rw-r--r--askbot/deps/openid/yadis/xrires.py123
-rw-r--r--setup.py1
129 files changed, 12 insertions, 27253 deletions
diff --git a/.gitignore b/.gitignore
index a95e1f45..ce223938 100755
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,4 @@ askbot/upfiles/avatars/
askbot/skins/common/media/mathjax/
/jinja2
*.tar.tz
+run
diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py
index 91534221..a23f771d 100644
--- a/askbot/deps/django_authopenid/forms.py
+++ b/askbot/deps/django_authopenid/forms.py
@@ -42,7 +42,7 @@ from askbot.utils.forms import NextUrlField, UserNameField, UserEmailField, SetP
# needed for some linux distributions like debian
try:
- from askbot.deps.openid.yadis import xri
+ from openid.yadis import xri
except ImportError:
from yadis import xri
diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py
index 44328a25..9dfbc596 100644
--- a/askbot/deps/django_authopenid/util.py
+++ b/askbot/deps/django_authopenid/util.py
@@ -3,10 +3,10 @@ import cgi
import urllib
import functools
import re
-from askbot.deps.openid.store.interface import OpenIDStore
-from askbot.deps.openid.association import Association as OIDAssociation
-from askbot.deps.openid.extensions import sreg
-from askbot.deps.openid import store as openid_store
+from openid.store.interface import OpenIDStore
+from openid.association import Association as OIDAssociation
+from openid.extensions import sreg
+from openid import store as openid_store
import oauth2 as oauth
from django.db.models.query import Q
@@ -24,7 +24,7 @@ from askbot.conf import settings as askbot_settings
# needed for some linux distributions like debian
try:
- from askbot.deps.openid.yadis import xri
+ from openid.yadis import xri
except:
from yadis import xri
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 07a67090..212e94ff 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -48,13 +48,13 @@ from django.utils.safestring import mark_safe
from django.core.mail import send_mail
from askbot.skins.loaders import render_into_skin, get_template
-from askbot.deps.openid.consumer.consumer import Consumer, \
+from openid.consumer.consumer import Consumer, \
SUCCESS, CANCEL, FAILURE, SETUP_NEEDED
-from askbot.deps.openid.consumer.discover import DiscoveryFailure
-from askbot.deps.openid.extensions import sreg
+from openid.consumer.discover import DiscoveryFailure
+from openid.extensions import sreg
# needed for some linux distributions like debian
try:
- from askbot.deps.openid.yadis import xri
+ from openid.yadis import xri
except ImportError:
from yadis import xri
diff --git a/askbot/deps/openid/__init__.py b/askbot/deps/openid/__init__.py
deleted file mode 100644
index 6be6538e..00000000
--- a/askbot/deps/openid/__init__.py
+++ /dev/null
@@ -1,55 +0,0 @@
-"""
-This package is an implementation of the OpenID specification in
-Python. It contains code for both server and consumer
-implementations. For information on implementing an OpenID consumer,
-see the C{L{openid.consumer.consumer}} module. For information on
-implementing an OpenID server, see the C{L{openid.server.server}}
-module.
-
-@contact: U{http://openid.net/developers/dev-mailing-lists/
- <http://openid.net/developers/dev-mailing-lists/}
-
-@copyright: (C) 2005-2008 JanRain, Inc.
-
-@license: Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- U{http://www.apache.org/licenses/LICENSE-2.0}
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions
- and limitations under the License.
-"""
-
-__version__ = '[library version:2.2.1]'[17:-1]
-
-__all__ = [
- 'association',
- 'consumer',
- 'cryptutil',
- 'dh',
- 'extension',
- 'extensions',
- 'fetchers',
- 'kvform',
- 'message',
- 'oidutil',
- 'server',
- 'sreg',
- 'store',
- 'urinorm',
- 'yadis',
- ]
-
-# Parse the version info
-try:
- version_info = map(int, __version__.split('.'))
-except ValueError:
- version_info = (None, None, None)
-else:
- if len(version_info) != 3:
- version_info = (None, None, None)
- else:
- version_info = tuple(version_info)
diff --git a/askbot/deps/openid/association.py b/askbot/deps/openid/association.py
deleted file mode 100644
index a5fafffc..00000000
--- a/askbot/deps/openid/association.py
+++ /dev/null
@@ -1,555 +0,0 @@
-# -*- test-case-name: openid.test.test_association -*-
-"""
-This module contains code for dealing with associations between
-consumers and servers. Associations contain a shared secret that is
-used to sign C{openid.mode=id_res} messages.
-
-Users of the library should not usually need to interact directly with
-associations. The L{store<openid.store>},
-L{server<openid.server.server>} and
-L{consumer<openid.consumer.consumer>} objects will create and manage
-the associations. The consumer and server code will make use of a
-C{L{SessionNegotiator}} when managing associations, which enables
-users to express a preference for what kind of associations should be
-allowed, and what kind of exchange should be done to establish the
-association.
-
-@var default_negotiator: A C{L{SessionNegotiator}} that allows all
- association types that are specified by the OpenID
- specification. It prefers to use HMAC-SHA1/DH-SHA1, if it's
- available. If HMAC-SHA256 is not supported by your Python runtime,
- HMAC-SHA256 and DH-SHA256 will not be available.
-
-@var encrypted_negotiator: A C{L{SessionNegotiator}} that
- does not support C{'no-encryption'} associations. It prefers
- HMAC-SHA1/DH-SHA1 association types if available.
-"""
-
-__all__ = [
- 'default_negotiator',
- 'encrypted_negotiator',
- 'SessionNegotiator',
- 'Association',
- ]
-
-import time
-
-from askbot.deps.openid import cryptutil
-from askbot.deps.openid import kvform
-from askbot.deps.openid import oidutil
-from askbot.deps.openid.message import OPENID_NS
-
-all_association_types = [
- 'HMAC-SHA1',
- 'HMAC-SHA256',
- ]
-
-if hasattr(cryptutil, 'hmacSha256'):
- supported_association_types = list(all_association_types)
-
- default_association_order = [
- ('HMAC-SHA1', 'DH-SHA1'),
- ('HMAC-SHA1', 'no-encryption'),
- ('HMAC-SHA256', 'DH-SHA256'),
- ('HMAC-SHA256', 'no-encryption'),
- ]
-
- only_encrypted_association_order = [
- ('HMAC-SHA1', 'DH-SHA1'),
- ('HMAC-SHA256', 'DH-SHA256'),
- ]
-else:
- supported_association_types = ['HMAC-SHA1']
-
- default_association_order = [
- ('HMAC-SHA1', 'DH-SHA1'),
- ('HMAC-SHA1', 'no-encryption'),
- ]
-
- only_encrypted_association_order = [
- ('HMAC-SHA1', 'DH-SHA1'),
- ]
-
-def getSessionTypes(assoc_type):
- """Return the allowed session types for a given association type"""
- assoc_to_session = {
- 'HMAC-SHA1': ['DH-SHA1', 'no-encryption'],
- 'HMAC-SHA256': ['DH-SHA256', 'no-encryption'],
- }
- return assoc_to_session.get(assoc_type, [])
-
-def checkSessionType(assoc_type, session_type):
- """Check to make sure that this pair of assoc type and session
- type are allowed"""
- if session_type not in getSessionTypes(assoc_type):
- raise ValueError(
- 'Session type %r not valid for assocation type %r'
- % (session_type, assoc_type))
-
-class SessionNegotiator(object):
- """A session negotiator controls the allowed and preferred
- association types and association session types. Both the
- C{L{Consumer<openid.consumer.consumer.Consumer>}} and
- C{L{Server<openid.server.server.Server>}} use negotiators when
- creating associations.
-
- You can create and use negotiators if you:
-
- - Do not want to do Diffie-Hellman key exchange because you use
- transport-layer encryption (e.g. SSL)
-
- - Want to use only SHA-256 associations
-
- - Do not want to support plain-text associations over a non-secure
- channel
-
- It is up to you to set a policy for what kinds of associations to
- accept. By default, the library will make any kind of association
- that is allowed in the OpenID 2.0 specification.
-
- Use of negotiators in the library
- =================================
-
- When a consumer makes an association request, it calls
- C{L{getAllowedType}} to get the preferred association type and
- association session type.
-
- The server gets a request for a particular association/session
- type and calls C{L{isAllowed}} to determine if it should
- create an association. If it is supported, negotiation is
- complete. If it is not, the server calls C{L{getAllowedType}} to
- get an allowed association type to return to the consumer.
-
- If the consumer gets an error response indicating that the
- requested association/session type is not supported by the server
- that contains an assocation/session type to try, it calls
- C{L{isAllowed}} to determine if it should try again with the
- given combination of association/session type.
-
- @ivar allowed_types: A list of association/session types that are
- allowed by the server. The order of the pairs in this list
- determines preference. If an association/session type comes
- earlier in the list, the library is more likely to use that
- type.
- @type allowed_types: [(str, str)]
- """
-
- def __init__(self, allowed_types):
- self.setAllowedTypes(allowed_types)
-
- def copy(self):
- return self.__class__(list(self.allowed_types))
-
- def setAllowedTypes(self, allowed_types):
- """Set the allowed association types, checking to make sure
- each combination is valid."""
- for (assoc_type, session_type) in allowed_types:
- checkSessionType(assoc_type, session_type)
-
- self.allowed_types = allowed_types
-
- def addAllowedType(self, assoc_type, session_type=None):
- """Add an association type and session type to the allowed
- types list. The assocation/session pairs are tried in the
- order that they are added."""
- if self.allowed_types is None:
- self.allowed_types = []
-
- if session_type is None:
- available = getSessionTypes(assoc_type)
-
- if not available:
- raise ValueError('No session available for association type %r'
- % (assoc_type,))
-
- for session_type in getSessionTypes(assoc_type):
- self.addAllowedType(assoc_type, session_type)
- else:
- checkSessionType(assoc_type, session_type)
- self.allowed_types.append((assoc_type, session_type))
-
-
- def isAllowed(self, assoc_type, session_type):
- """Is this combination of association type and session type allowed?"""
- assoc_good = (assoc_type, session_type) in self.allowed_types
- matches = session_type in getSessionTypes(assoc_type)
- return assoc_good and matches
-
- def getAllowedType(self):
- """Get a pair of assocation type and session type that are
- supported"""
- try:
- return self.allowed_types[0]
- except IndexError:
- return (None, None)
-
-default_negotiator = SessionNegotiator(default_association_order)
-encrypted_negotiator = SessionNegotiator(only_encrypted_association_order)
-
-def getSecretSize(assoc_type):
- if assoc_type == 'HMAC-SHA1':
- return 20
- elif assoc_type == 'HMAC-SHA256':
- return 32
- else:
- raise ValueError('Unsupported association type: %r' % (assoc_type,))
-
-class Association(object):
- """
- This class represents an association between a server and a
- consumer. In general, users of this library will never see
- instances of this object. The only exception is if you implement
- a custom C{L{OpenIDStore<openid.store.interface.OpenIDStore>}}.
-
- If you do implement such a store, it will need to store the values
- of the C{L{handle}}, C{L{secret}}, C{L{issued}}, C{L{lifetime}}, and
- C{L{assoc_type}} instance variables.
-
- @ivar handle: This is the handle the server gave this association.
-
- @type handle: C{str}
-
-
- @ivar secret: This is the shared secret the server generated for
- this association.
-
- @type secret: C{str}
-
-
- @ivar issued: This is the time this association was issued, in
- seconds since 00:00 GMT, January 1, 1970. (ie, a unix
- timestamp)
-
- @type issued: C{int}
-
-
- @ivar lifetime: This is the amount of time this association is
- good for, measured in seconds since the association was
- issued.
-
- @type lifetime: C{int}
-
-
- @ivar assoc_type: This is the type of association this instance
- represents. The only valid value of this field at this time
- is C{'HMAC-SHA1'}, but new types may be defined in the future.
-
- @type assoc_type: C{str}
-
-
- @sort: __init__, fromExpiresIn, getExpiresIn, __eq__, __ne__,
- handle, secret, issued, lifetime, assoc_type
- """
-
- # The ordering and name of keys as stored by serialize
- assoc_keys = [
- 'version',
- 'handle',
- 'secret',
- 'issued',
- 'lifetime',
- 'assoc_type',
- ]
-
-
- _macs = {
- 'HMAC-SHA1': cryptutil.hmacSha1,
- 'HMAC-SHA256': cryptutil.hmacSha256,
- }
-
-
- def fromExpiresIn(cls, expires_in, handle, secret, assoc_type):
- """
- This is an alternate constructor used by the OpenID consumer
- library to create associations. C{L{OpenIDStore
- <openid.store.interface.OpenIDStore>}} implementations
- shouldn't use this constructor.
-
-
- @param expires_in: This is the amount of time this association
- is good for, measured in seconds since the association was
- issued.
-
- @type expires_in: C{int}
-
-
- @param handle: This is the handle the server gave this
- association.
-
- @type handle: C{str}
-
-
- @param secret: This is the shared secret the server generated
- for this association.
-
- @type secret: C{str}
-
-
- @param assoc_type: This is the type of association this
- instance represents. The only valid value of this field
- at this time is C{'HMAC-SHA1'}, but new types may be
- defined in the future.
-
- @type assoc_type: C{str}
- """
- issued = int(time.time())
- lifetime = expires_in
- return cls(handle, secret, issued, lifetime, assoc_type)
-
- fromExpiresIn = classmethod(fromExpiresIn)
-
- def __init__(self, handle, secret, issued, lifetime, assoc_type):
- """
- This is the standard constructor for creating an association.
-
-
- @param handle: This is the handle the server gave this
- association.
-
- @type handle: C{str}
-
-
- @param secret: This is the shared secret the server generated
- for this association.
-
- @type secret: C{str}
-
-
- @param issued: This is the time this association was issued,
- in seconds since 00:00 GMT, January 1, 1970. (ie, a unix
- timestamp)
-
- @type issued: C{int}
-
-
- @param lifetime: This is the amount of time this association
- is good for, measured in seconds since the association was
- issued.
-
- @type lifetime: C{int}
-
-
- @param assoc_type: This is the type of association this
- instance represents. The only valid value of this field
- at this time is C{'HMAC-SHA1'}, but new types may be
- defined in the future.
-
- @type assoc_type: C{str}
- """
- if assoc_type not in all_association_types:
- fmt = '%r is not a supported association type'
- raise ValueError(fmt % (assoc_type,))
-
-# secret_size = getSecretSize(assoc_type)
-# if len(secret) != secret_size:
-# fmt = 'Wrong size secret (%s bytes) for association type %s'
-# raise ValueError(fmt % (len(secret), assoc_type))
-
- self.handle = handle
- self.secret = secret
- self.issued = issued
- self.lifetime = lifetime
- self.assoc_type = assoc_type
-
- def getExpiresIn(self, now=None):
- """
- This returns the number of seconds this association is still
- valid for, or C{0} if the association is no longer valid.
-
-
- @return: The number of seconds this association is still valid
- for, or C{0} if the association is no longer valid.
-
- @rtype: C{int}
- """
- if now is None:
- now = int(time.time())
-
- return max(0, self.issued + self.lifetime - now)
-
- expiresIn = property(getExpiresIn)
-
- def __eq__(self, other):
- """
- This checks to see if two C{L{Association}} instances
- represent the same association.
-
-
- @return: C{True} if the two instances represent the same
- association, C{False} otherwise.
-
- @rtype: C{bool}
- """
- return type(self) is type(other) and self.__dict__ == other.__dict__
-
- def __ne__(self, other):
- """
- This checks to see if two C{L{Association}} instances
- represent different associations.
-
-
- @return: C{True} if the two instances represent different
- associations, C{False} otherwise.
-
- @rtype: C{bool}
- """
- return not (self == other)
-
- def serialize(self):
- """
- Convert an association to KV form.
-
- @return: String in KV form suitable for deserialization by
- deserialize.
-
- @rtype: str
- """
- data = {
- 'version':'2',
- 'handle':self.handle,
- 'secret':oidutil.toBase64(self.secret),
- 'issued':str(int(self.issued)),
- 'lifetime':str(int(self.lifetime)),
- 'assoc_type':self.assoc_type
- }
-
- assert len(data) == len(self.assoc_keys)
- pairs = []
- for field_name in self.assoc_keys:
- pairs.append((field_name, data[field_name]))
-
- return kvform.seqToKV(pairs, strict=True)
-
- def deserialize(cls, assoc_s):
- """
- Parse an association as stored by serialize().
-
- inverse of serialize
-
-
- @param assoc_s: Association as serialized by serialize()
-
- @type assoc_s: str
-
-
- @return: instance of this class
- """
- pairs = kvform.kvToSeq(assoc_s, strict=True)
- keys = []
- values = []
- for k, v in pairs:
- keys.append(k)
- values.append(v)
-
- if keys != cls.assoc_keys:
- raise ValueError('Unexpected key values: %r', keys)
-
- version, handle, secret, issued, lifetime, assoc_type = values
- if version != '2':
- raise ValueError('Unknown version: %r' % version)
- issued = int(issued)
- lifetime = int(lifetime)
- secret = oidutil.fromBase64(secret)
- return cls(handle, secret, issued, lifetime, assoc_type)
-
- deserialize = classmethod(deserialize)
-
- def sign(self, pairs):
- """
- Generate a signature for a sequence of (key, value) pairs
-
-
- @param pairs: The pairs to sign, in order
-
- @type pairs: sequence of (str, str)
-
-
- @return: The binary signature of this sequence of pairs
-
- @rtype: str
- """
- kv = kvform.seqToKV(pairs)
-
- try:
- mac = self._macs[self.assoc_type]
- except KeyError:
- raise ValueError(
- 'Unknown association type: %r' % (self.assoc_type,))
-
- return mac(self.secret, kv)
-
-
- def getMessageSignature(self, message):
- """Return the signature of a message.
-
- If I am not a sign-all association, the message must have a
- signed list.
-
- @return: the signature, base64 encoded
-
- @rtype: str
-
- @raises ValueError: If there is no signed list and I am not a sign-all
- type of association.
- """
- pairs = self._makePairs(message)
- return oidutil.toBase64(self.sign(pairs))
-
- def signMessage(self, message):
- """Add a signature (and a signed list) to a message.
-
- @return: a new Message object with a signature
- @rtype: L{openid.message.Message}
- """
- if (message.hasKey(OPENID_NS, 'sig') or
- message.hasKey(OPENID_NS, 'signed')):
- raise ValueError('Message already has signed list or signature')
-
- extant_handle = message.getArg(OPENID_NS, 'assoc_handle')
- if extant_handle and extant_handle != self.handle:
- raise ValueError("Message has a different association handle")
-
- signed_message = message.copy()
- signed_message.setArg(OPENID_NS, 'assoc_handle', self.handle)
- message_keys = signed_message.toPostArgs().keys()
- signed_list = [k[7:] for k in message_keys
- if k.startswith('openid.')]
- signed_list.append('signed')
- signed_list.sort()
- signed_message.setArg(OPENID_NS, 'signed', ','.join(signed_list))
- sig = self.getMessageSignature(signed_message)
- signed_message.setArg(OPENID_NS, 'sig', sig)
- return signed_message
-
- def checkMessageSignature(self, message):
- """Given a message with a signature, calculate a new signature
- and return whether it matches the signature in the message.
-
- @raises ValueError: if the message has no signature or no signature
- can be calculated for it.
- """
- message_sig = message.getArg(OPENID_NS, 'sig')
- if not message_sig:
- raise ValueError("%s has no sig." % (message,))
- calculated_sig = self.getMessageSignature(message)
- return calculated_sig == message_sig
-
-
- def _makePairs(self, message):
- signed = message.getArg(OPENID_NS, 'signed')
- if not signed:
- raise ValueError('Message has no signed list: %s' % (message,))
-
- signed_list = signed.split(',')
- pairs = []
- data = message.toPostArgs()
- for field in signed_list:
- pairs.append((field, data.get('openid.' + field, '')))
- return pairs
-
- def __repr__(self):
- return "<%s.%s %s %s>" % (
- self.__class__.__module__,
- self.__class__.__name__,
- self.assoc_type,
- self.handle)
diff --git a/askbot/deps/openid/consumer/__init__.py b/askbot/deps/openid/consumer/__init__.py
deleted file mode 100644
index aab51a29..00000000
--- a/askbot/deps/openid/consumer/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-This package contains the portions of the library used only when
-implementing an OpenID consumer.
-"""
-
-__all__ = ['consumer', 'discover']
diff --git a/askbot/deps/openid/consumer/consumer.py b/askbot/deps/openid/consumer/consumer.py
deleted file mode 100644
index 64a2278c..00000000
--- a/askbot/deps/openid/consumer/consumer.py
+++ /dev/null
@@ -1,1900 +0,0 @@
-# -*- test-case-name: openid.test.test_consumer -*-
-"""OpenID support for Relying Parties (aka Consumers).
-
-This module documents the main interface with the OpenID consumer
-library. The only part of the library which has to be used and isn't
-documented in full here is the store required to create an
-C{L{Consumer}} instance. More on the abstract store type and
-concrete implementations of it that are provided in the documentation
-for the C{L{__init__<Consumer.__init__>}} method of the
-C{L{Consumer}} class.
-
-
-OVERVIEW
-========
-
- The OpenID identity verification process most commonly uses the
- following steps, as visible to the user of this library:
-
- 1. The user enters their OpenID into a field on the consumer's
- site, and hits a login button.
-
- 2. The consumer site discovers the user's OpenID provider using
- the Yadis protocol.
-
- 3. The consumer site sends the browser a redirect to the
- OpenID provider. This is the authentication request as
- described in the OpenID specification.
-
- 4. The OpenID provider's site sends the browser a redirect
- back to the consumer site. This redirect contains the
- provider's response to the authentication request.
-
- The most important part of the flow to note is the consumer's site
- must handle two separate HTTP requests in order to perform the
- full identity check.
-
-
-LIBRARY DESIGN
-==============
-
- This consumer library is designed with that flow in mind. The
- goal is to make it as easy as possible to perform the above steps
- securely.
-
- At a high level, there are two important parts in the consumer
- library. The first important part is this module, which contains
- the interface to actually use this library. The second is the
- C{L{openid.store.interface}} module, which describes the
- interface to use if you need to create a custom method for storing
- the state this library needs to maintain between requests.
-
- In general, the second part is less important for users of the
- library to know about, as several implementations are provided
- which cover a wide variety of situations in which consumers may
- use the library.
-
- This module contains a class, C{L{Consumer}}, with methods
- corresponding to the actions necessary in each of steps 2, 3, and
- 4 described in the overview. Use of this library should be as easy
- as creating an C{L{Consumer}} instance and calling the methods
- appropriate for the action the site wants to take.
-
-
-SESSIONS, STORES, AND STATELESS MODE
-====================================
-
- The C{L{Consumer}} object keeps track of two types of state:
-
- 1. State of the user's current authentication attempt. Things like
- the identity URL, the list of endpoints discovered for that
- URL, and in case where some endpoints are unreachable, the list
- of endpoints already tried. This state needs to be held from
- Consumer.begin() to Consumer.complete(), but it is only applicable
- to a single session with a single user agent, and at the end of
- the authentication process (i.e. when an OP replies with either
- C{id_res} or C{cancel}) it may be discarded.
-
- 2. State of relationships with servers, i.e. shared secrets
- (associations) with servers and nonces seen on signed messages.
- This information should persist from one session to the next and
- should not be bound to a particular user-agent.
-
-
- These two types of storage are reflected in the first two arguments of
- Consumer's constructor, C{session} and C{store}. C{session} is a
- dict-like object and we hope your web framework provides you with one
- of these bound to the user agent. C{store} is an instance of
- L{openid.store.interface.OpenIDStore}.
-
- Since the store does hold secrets shared between your application and the
- OpenID provider, you should be careful about how you use it in a shared
- hosting environment. If the filesystem or database permissions of your
- web host allow strangers to read from them, do not store your data there!
- If you have no safe place to store your data, construct your consumer
- with C{None} for the store, and it will operate only in stateless mode.
- Stateless mode may be slower, put more load on the OpenID provider, and
- trusts the provider to keep you safe from replay attacks.
-
-
- Several store implementation are provided, and the interface is
- fully documented so that custom stores can be used as well. See
- the documentation for the C{L{Consumer}} class for more
- information on the interface for stores. The implementations that
- are provided allow the consumer site to store the necessary data
- in several different ways, including several SQL databases and
- normal files on disk.
-
-
-IMMEDIATE MODE
-==============
-
- In the flow described above, the user may need to confirm to the
- OpenID provider that it's ok to disclose his or her identity.
- The provider may draw pages asking for information from the user
- before it redirects the browser back to the consumer's site. This
- is generally transparent to the consumer site, so it is typically
- ignored as an implementation detail.
-
- There can be times, however, where the consumer site wants to get
- a response immediately. When this is the case, the consumer can
- put the library in immediate mode. In immediate mode, there is an
- extra response possible from the server, which is essentially the
- server reporting that it doesn't have enough information to answer
- the question yet.
-
-
-USING THIS LIBRARY
-==================
-
- Integrating this library into an application is usually a
- relatively straightforward process. The process should basically
- follow this plan:
-
- Add an OpenID login field somewhere on your site. When an OpenID
- is entered in that field and the form is submitted, it should make
- a request to your site which includes that OpenID URL.
-
- First, the application should L{instantiate a Consumer<Consumer.__init__>}
- with a session for per-user state and store for shared state.
- using the store of choice.
-
- Next, the application should call the 'C{L{begin<Consumer.begin>}}' method on the
- C{L{Consumer}} instance. This method takes the OpenID URL. The
- C{L{begin<Consumer.begin>}} method returns an C{L{AuthRequest}}
- object.
-
- Next, the application should call the
- C{L{redirectURL<AuthRequest.redirectURL>}} method on the
- C{L{AuthRequest}} object. The parameter C{return_to} is the URL
- that the OpenID server will send the user back to after attempting
- to verify his or her identity. The C{realm} parameter is the
- URL (or URL pattern) that identifies your web site to the user
- when he or she is authorizing it. Send a redirect to the
- resulting URL to the user's browser.
-
- That's the first half of the authentication process. The second
- half of the process is done after the user's OpenID Provider sends the
- user's browser a redirect back to your site to complete their
- login.
-
- When that happens, the user will contact your site at the URL
- given as the C{return_to} URL to the
- C{L{redirectURL<AuthRequest.redirectURL>}} call made
- above. The request will have several query parameters added to
- the URL by the OpenID provider as the information necessary to
- finish the request.
-
- Get a C{L{Consumer}} instance with the same session and store as
- before and call its C{L{complete<Consumer.complete>}} method,
- passing in all the received query arguments.
-
- There are multiple possible return types possible from that
- method. These indicate whether or not the login was successful,
- and include any additional information appropriate for their type.
-
-@var SUCCESS: constant used as the status for
- L{SuccessResponse<openid.consumer.consumer.SuccessResponse>} objects.
-
-@var FAILURE: constant used as the status for
- L{FailureResponse<openid.consumer.consumer.FailureResponse>} objects.
-
-@var CANCEL: constant used as the status for
- L{CancelResponse<openid.consumer.consumer.CancelResponse>} objects.
-
-@var SETUP_NEEDED: constant used as the status for
- L{SetupNeededResponse<openid.consumer.consumer.SetupNeededResponse>}
- objects.
-"""
-
-import cgi
-import copy
-from urlparse import urlparse, urldefrag
-
-from askbot.deps.openid import fetchers
-
-from askbot.deps.openid.consumer.discover import discover, OpenIDServiceEndpoint, \
- DiscoveryFailure, OPENID_1_0_TYPE, OPENID_1_1_TYPE, OPENID_2_0_TYPE
-from askbot.deps.openid.message import Message, OPENID_NS, OPENID2_NS, OPENID1_NS, \
- IDENTIFIER_SELECT, no_default, BARE_NS
-from askbot.deps.openid import cryptutil
-from askbot.deps.openid import oidutil
-from askbot.deps.openid.association import Association, default_negotiator, \
- SessionNegotiator
-from askbot.deps.openid.dh import DiffieHellman
-from askbot.deps.openid.store.nonce import mkNonce, split as splitNonce
-from askbot.deps.openid.yadis.manager import Discovery
-from askbot.deps.openid import urinorm
-
-
-__all__ = ['AuthRequest', 'Consumer', 'SuccessResponse',
- 'SetupNeededResponse', 'CancelResponse', 'FailureResponse',
- 'SUCCESS', 'FAILURE', 'CANCEL', 'SETUP_NEEDED',
- ]
-
-
-def makeKVPost(request_message, server_url):
- """Make a Direct Request to an OpenID Provider and return the
- result as a Message object.
-
- @raises openid.fetchers.HTTPFetchingError: if an error is
- encountered in making the HTTP post.
-
- @rtype: L{openid.message.Message}
- """
- # XXX: TESTME
- resp = fetchers.fetch(server_url, body=request_message.toURLEncoded())
-
- # Process response in separate function that can be shared by async code.
- return _httpResponseToMessage(resp, server_url)
-
-
-def _httpResponseToMessage(response, server_url):
- """Adapt a POST response to a Message.
-
- @type response: L{openid.fetchers.HTTPResponse}
- @param response: Result of a POST to an OpenID endpoint.
-
- @rtype: L{openid.message.Message}
-
- @raises openid.fetchers.HTTPFetchingError: if the server returned a
- status of other than 200 or 400.
-
- @raises ServerError: if the server returned an OpenID error.
- """
- # Should this function be named Message.fromHTTPResponse instead?
- response_message = Message.fromKVForm(response.body)
- if response.status == 400:
- raise ServerError.fromMessage(response_message)
-
- elif response.status not in (200, 206):
- fmt = 'bad status code from server %s: %s'
- error_message = fmt % (server_url, response.status)
- raise fetchers.HTTPFetchingError(error_message)
-
- return response_message
-
-
-
-class Consumer(object):
- """An OpenID consumer implementation that performs discovery and
- does session management.
-
- @ivar consumer: an instance of an object implementing the OpenID
- protocol, but doing no discovery or session management.
-
- @type consumer: GenericConsumer
-
- @ivar session: A dictionary-like object representing the user's
- session data. This is used for keeping state of the OpenID
- transaction when the user is redirected to the server.
-
- @cvar session_key_prefix: A string that is prepended to session
- keys to ensure that they are unique. This variable may be
- changed to suit your application.
- """
- session_key_prefix = "_openid_consumer_"
-
- _token = 'last_token'
-
- _discover = staticmethod(discover)
-
- def __init__(self, session, store, consumer_class=None):
- """Initialize a Consumer instance.
-
- You should create a new instance of the Consumer object with
- every HTTP request that handles OpenID transactions.
-
- @param session: See L{the session instance variable<openid.consumer.consumer.Consumer.session>}
-
- @param store: an object that implements the interface in
- C{L{openid.store.interface.OpenIDStore}}. Several
- implementations are provided, to cover common database
- environments.
-
- @type store: C{L{openid.store.interface.OpenIDStore}}
-
- @see: L{openid.store.interface}
- @see: L{openid.store}
- """
- self.session = session
- if consumer_class is None:
- consumer_class = GenericConsumer
- self.consumer = consumer_class(store)
- self._token_key = self.session_key_prefix + self._token
-
- def begin(self, user_url, anonymous=False):
- """Start the OpenID authentication process. See steps 1-2 in
- the overview at the top of this file.
-
- @param user_url: Identity URL given by the user. This method
- performs a textual transformation of the URL to try and
- make sure it is normalized. For example, a user_url of
- example.com will be normalized to http://example.com/
- normalizing and resolving any redirects the server might
- issue.
-
- @type user_url: unicode
-
- @param anonymous: Whether to make an anonymous request of the OpenID
- provider. Such a request does not ask for an authorization
- assertion for an OpenID identifier, but may be used with
- extensions to pass other data. e.g. "I don't care who you are,
- but I'd like to know your time zone."
-
- @type anonymous: bool
-
- @returns: An object containing the discovered information will
- be returned, with a method for building a redirect URL to
- the server, as described in step 3 of the overview. This
- object may also be used to add extension arguments to the
- request, using its
- L{addExtensionArg<openid.consumer.consumer.AuthRequest.addExtensionArg>}
- method.
-
- @returntype: L{AuthRequest<openid.consumer.consumer.AuthRequest>}
-
- @raises openid.consumer.discover.DiscoveryFailure: when I fail to
- find an OpenID server for this URL. If the C{yadis} package
- is available, L{openid.consumer.discover.DiscoveryFailure} is
- an alias for C{yadis.discover.DiscoveryFailure}.
- """
- disco = Discovery(self.session, user_url, self.session_key_prefix)
- try:
- service = disco.getNextService(self._discover)
- except fetchers.HTTPFetchingError, why:
- raise DiscoveryFailure(
- 'Error fetching XRDS document: %s' % (why[0],), None)
-
- if service is None:
- raise DiscoveryFailure(
- 'No usable OpenID services found for %s' % (user_url,), None)
- else:
- return self.beginWithoutDiscovery(service, anonymous)
-
- def beginWithoutDiscovery(self, service, anonymous=False):
- """Start OpenID verification without doing OpenID server
- discovery. This method is used internally by Consumer.begin
- after discovery is performed, and exists to provide an
- interface for library users needing to perform their own
- discovery.
-
- @param service: an OpenID service endpoint descriptor. This
- object and factories for it are found in the
- L{openid.consumer.discover} module.
-
- @type service:
- L{OpenIDServiceEndpoint<openid.consumer.discover.OpenIDServiceEndpoint>}
-
- @returns: an OpenID authentication request object.
-
- @rtype: L{AuthRequest<openid.consumer.consumer.AuthRequest>}
-
- @See: Openid.consumer.consumer.Consumer.begin
- @see: openid.consumer.discover
- """
- auth_req = self.consumer.begin(service)
- self.session[self._token_key] = auth_req.endpoint
-
- try:
- auth_req.setAnonymous(anonymous)
- except ValueError, why:
- raise ProtocolError(str(why))
-
- return auth_req
-
- def complete(self, query, current_url):
- """Called to interpret the server's response to an OpenID
- request. It is called in step 4 of the flow described in the
- consumer overview.
-
- @param query: A dictionary of the query parameters for this
- HTTP request.
-
- @param current_url: The URL used to invoke the application.
- Extract the URL from your application's web
- request framework and specify it here to have it checked
- against the openid.return_to value in the response. If
- the return_to URL check fails, the status of the
- completion will be FAILURE.
-
- @returns: a subclass of Response. The type of response is
- indicated by the status attribute, which will be one of
- SUCCESS, CANCEL, FAILURE, or SETUP_NEEDED.
-
- @see: L{SuccessResponse<openid.consumer.consumer.SuccessResponse>}
- @see: L{CancelResponse<openid.consumer.consumer.CancelResponse>}
- @see: L{SetupNeededResponse<openid.consumer.consumer.SetupNeededResponse>}
- @see: L{FailureResponse<openid.consumer.consumer.FailureResponse>}
- """
-
- endpoint = self.session.get(self._token_key)
-
- message = Message.fromPostArgs(query)
- response = self.consumer.complete(message, endpoint, current_url)
-
- try:
- del self.session[self._token_key]
- except KeyError:
- pass
-
- if (response.status in ['success', 'cancel'] and
- response.identity_url is not None):
-
- disco = Discovery(self.session,
- response.identity_url,
- self.session_key_prefix)
- # This is OK to do even if we did not do discovery in
- # the first place.
- disco.cleanup(force=True)
-
- return response
-
- def setAssociationPreference(self, association_preferences):
- """Set the order in which association types/sessions should be
- attempted. For instance, to only allow HMAC-SHA256
- associations created with a DH-SHA256 association session:
-
- >>> consumer.setAssociationPreference([('HMAC-SHA256', 'DH-SHA256')])
-
- Any association type/association type pair that is not in this
- list will not be attempted at all.
-
- @param association_preferences: The list of allowed
- (association type, association session type) pairs that
- should be allowed for this consumer to use, in order from
- most preferred to least preferred.
- @type association_preferences: [(str, str)]
-
- @returns: None
-
- @see: C{L{openid.association.SessionNegotiator}}
- """
- self.consumer.negotiator = SessionNegotiator(association_preferences)
-
-class DiffieHellmanSHA1ConsumerSession(object):
- session_type = 'DH-SHA1'
- hash_func = staticmethod(cryptutil.sha1)
- secret_size = 20
- allowed_assoc_types = ['HMAC-SHA1']
-
- def __init__(self, dh=None):
- if dh is None:
- dh = DiffieHellman.fromDefaults()
-
- self.dh = dh
-
- def getRequest(self):
- cpub = cryptutil.longToBase64(self.dh.public)
-
- args = {'dh_consumer_public': cpub}
-
- if not self.dh.usingDefaultValues():
- args.update({
- 'dh_modulus': cryptutil.longToBase64(self.dh.modulus),
- 'dh_gen': cryptutil.longToBase64(self.dh.generator),
- })
-
- return args
-
- def extractSecret(self, response):
- dh_server_public64 = response.getArg(
- OPENID_NS, 'dh_server_public', no_default)
- enc_mac_key64 = response.getArg(OPENID_NS, 'enc_mac_key', no_default)
- dh_server_public = cryptutil.base64ToLong(dh_server_public64)
- enc_mac_key = oidutil.fromBase64(enc_mac_key64)
- return self.dh.xorSecret(dh_server_public, enc_mac_key, self.hash_func)
-
-class DiffieHellmanSHA256ConsumerSession(DiffieHellmanSHA1ConsumerSession):
- session_type = 'DH-SHA256'
- hash_func = staticmethod(cryptutil.sha256)
- secret_size = 32
- allowed_assoc_types = ['HMAC-SHA256']
-
-class PlainTextConsumerSession(object):
- session_type = 'no-encryption'
- allowed_assoc_types = ['HMAC-SHA1', 'HMAC-SHA256']
-
- def getRequest(self):
- return {}
-
- def extractSecret(self, response):
- mac_key64 = response.getArg(OPENID_NS, 'mac_key', no_default)
- return oidutil.fromBase64(mac_key64)
-
-class SetupNeededError(Exception):
- """Internally-used exception that indicates that an immediate-mode
- request cancelled."""
- def __init__(self, user_setup_url=None):
- Exception.__init__(self, user_setup_url)
- self.user_setup_url = user_setup_url
-
-class ProtocolError(ValueError):
- """Exception that indicates that a message violated the
- protocol. It is raised and caught internally to this file."""
-
-class TypeURIMismatch(ProtocolError):
- """A protocol error arising from type URIs mismatching
- """
-
- def __init__(self, expected, endpoint):
- ProtocolError.__init__(self, expected, endpoint)
- self.expected = expected
- self.endpoint = endpoint
-
- def __str__(self):
- s = '<%s.%s: Required type %s not found in %s for endpoint %s>' % (
- self.__class__.__module__, self.__class__.__name__,
- self.expected, self.endpoint.type_uris, self.endpoint)
- return s
-
-
-
-class ServerError(Exception):
- """Exception that is raised when the server returns a 400 response
- code to a direct request."""
-
- def __init__(self, error_text, error_code, message):
- Exception.__init__(self, error_text)
- self.error_text = error_text
- self.error_code = error_code
- self.message = message
-
- def fromMessage(cls, message):
- """Generate a ServerError instance, extracting the error text
- and the error code from the message."""
- error_text = message.getArg(
- OPENID_NS, 'error', '<no error message supplied>')
- error_code = message.getArg(OPENID_NS, 'error_code')
- return cls(error_text, error_code, message)
-
- fromMessage = classmethod(fromMessage)
-
-class GenericConsumer(object):
- """This is the implementation of the common logic for OpenID
- consumers. It is unaware of the application in which it is
- running.
-
- @ivar negotiator: An object that controls the kind of associations
- that the consumer makes. It defaults to
- C{L{openid.association.default_negotiator}}. Assign a
- different negotiator to it if you have specific requirements
- for how associations are made.
- @type negotiator: C{L{openid.association.SessionNegotiator}}
- """
-
- # The name of the query parameter that gets added to the return_to
- # URL when using OpenID1. You can change this value if you want or
- # need a different name, but don't make it start with openid,
- # because it's not a standard protocol thing for OpenID1. For
- # OpenID2, the library will take care of the nonce using standard
- # OpenID query parameter names.
- openid1_nonce_query_arg_name = 'janrain_nonce'
-
- # Another query parameter that gets added to the return_to for
- # OpenID 1; if the user's session state is lost, use this claimed
- # identifier to do discovery when verifying the response.
- openid1_return_to_identifier_name = 'openid1_claimed_id'
-
- session_types = {
- 'DH-SHA1':DiffieHellmanSHA1ConsumerSession,
- 'DH-SHA256':DiffieHellmanSHA256ConsumerSession,
- 'no-encryption':PlainTextConsumerSession,
- }
-
- _discover = staticmethod(discover)
-
- def __init__(self, store):
- self.store = store
- self.negotiator = default_negotiator.copy()
-
- def begin(self, service_endpoint):
- """Create an AuthRequest object for the specified
- service_endpoint. This method will create an association if
- necessary."""
- if self.store is None:
- assoc = None
- else:
- assoc = self._getAssociation(service_endpoint)
-
- request = AuthRequest(service_endpoint, assoc)
- request.return_to_args[self.openid1_nonce_query_arg_name] = mkNonce()
-
- if request.message.isOpenID1():
- request.return_to_args[self.openid1_return_to_identifier_name] = \
- request.endpoint.claimed_id
-
- return request
-
- def complete(self, message, endpoint, return_to):
- """Process the OpenID message, using the specified endpoint
- and return_to URL as context. This method will handle any
- OpenID message that is sent to the return_to URL.
- """
- mode = message.getArg(OPENID_NS, 'mode', '<No mode set>')
-
- modeMethod = getattr(self, '_complete_' + mode,
- self._completeInvalid)
-
- return modeMethod(message, endpoint, return_to)
-
- def _complete_cancel(self, message, endpoint, _):
- return CancelResponse(endpoint)
-
- def _complete_error(self, message, endpoint, _):
- error = message.getArg(OPENID_NS, 'error')
- contact = message.getArg(OPENID_NS, 'contact')
- reference = message.getArg(OPENID_NS, 'reference')
-
- return FailureResponse(endpoint, error, contact=contact,
- reference=reference)
-
- def _complete_setup_needed(self, message, endpoint, _):
- if not message.isOpenID2():
- return self._completeInvalid(message, endpoint, _)
-
- user_setup_url = message.getArg(OPENID2_NS, 'user_setup_url')
- return SetupNeededResponse(endpoint, user_setup_url)
-
- def _complete_id_res(self, message, endpoint, return_to):
- try:
- self._checkSetupNeeded(message)
- except SetupNeededError, why:
- return SetupNeededResponse(endpoint, why.user_setup_url)
- else:
- try:
- return self._doIdRes(message, endpoint, return_to)
- except (ProtocolError, DiscoveryFailure), why:
- return FailureResponse(endpoint, why[0])
-
- def _completeInvalid(self, message, endpoint, _):
- mode = message.getArg(OPENID_NS, 'mode', '<No mode set>')
- return FailureResponse(endpoint,
- 'Invalid openid.mode: %r' % (mode,))
-
- def _checkReturnTo(self, message, return_to):
- """Check an OpenID message and its openid.return_to value
- against a return_to URL from an application. Return True on
- success, False on failure.
- """
- # Check the openid.return_to args against args in the original
- # message.
- try:
- self._verifyReturnToArgs(message.toPostArgs())
- except ProtocolError, why:
- oidutil.log("Verifying return_to arguments: %s" % (why[0],))
- return False
-
- # Check the return_to base URL against the one in the message.
- msg_return_to = message.getArg(OPENID_NS, 'return_to')
-
- # The URL scheme, authority, and path MUST be the same between
- # the two URLs.
- app_parts = urlparse(urinorm.urinorm(return_to))
- msg_parts = urlparse(urinorm.urinorm(msg_return_to))
-
- # (addressing scheme, network location, path) must be equal in
- # both URLs.
- for part in range(0, 3):
- if app_parts[part] != msg_parts[part]:
- return False
-
- return True
-
- _makeKVPost = staticmethod(makeKVPost)
-
- def _checkSetupNeeded(self, message):
- """Check an id_res message to see if it is a
- checkid_immediate cancel response.
-
- @raises SetupNeededError: if it is a checkid_immediate cancellation
- """
- # In OpenID 1, we check to see if this is a cancel from
- # immediate mode by the presence of the user_setup_url
- # parameter.
- if message.isOpenID1():
- user_setup_url = message.getArg(OPENID1_NS, 'user_setup_url')
- if user_setup_url is not None:
- raise SetupNeededError(user_setup_url)
-
- def _doIdRes(self, message, endpoint, return_to):
- """Handle id_res responses that are not cancellations of
- immediate mode requests.
-
- @param message: the response paramaters.
- @param endpoint: the discovered endpoint object. May be None.
-
- @raises ProtocolError: If the message contents are not
- well-formed according to the OpenID specification. This
- includes missing fields or not signing fields that should
- be signed.
-
- @raises DiscoveryFailure: If the subject of the id_res message
- does not match the supplied endpoint, and discovery on the
- identifier in the message fails (this should only happen
- when using OpenID 2)
-
- @returntype: L{Response}
- """
- # Checks for presence of appropriate fields (and checks
- # signed list fields)
- self._idResCheckForFields(message)
-
- if not self._checkReturnTo(message, return_to):
- raise ProtocolError(
- "return_to does not match return URL. Expected %r, got %r"
- % (return_to, message.getArg(OPENID_NS, 'return_to')))
-
-
- # Verify discovery information:
- endpoint = self._verifyDiscoveryResults(message, endpoint)
- oidutil.log("Received id_res response from %s using association %s" %
- (endpoint.server_url,
- message.getArg(OPENID_NS, 'assoc_handle')))
-
- self._idResCheckSignature(message, endpoint.server_url)
-
- # Will raise a ProtocolError if the nonce is bad
- self._idResCheckNonce(message, endpoint)
-
- signed_list_str = message.getArg(OPENID_NS, 'signed', no_default)
- signed_list = signed_list_str.split(',')
- signed_fields = ["openid." + s for s in signed_list]
- return SuccessResponse(endpoint, message, signed_fields)
-
- def _idResGetNonceOpenID1(self, message, endpoint):
- """Extract the nonce from an OpenID 1 response. Return the
- nonce from the BARE_NS since we independently check the
- return_to arguments are the same as those in the response
- message.
-
- See the openid1_nonce_query_arg_name class variable
-
- @returns: The nonce as a string or None
- """
- return message.getArg(BARE_NS, self.openid1_nonce_query_arg_name)
-
- def _idResCheckNonce(self, message, endpoint):
- if message.isOpenID1():
- # This indicates that the nonce was generated by the consumer
- nonce = self._idResGetNonceOpenID1(message, endpoint)
- server_url = ''
- else:
- nonce = message.getArg(OPENID2_NS, 'response_nonce')
- server_url = endpoint.server_url
-
- if nonce is None:
- raise ProtocolError('Nonce missing from response')
-
- try:
- timestamp, salt = splitNonce(nonce)
- except ValueError, why:
- raise ProtocolError('Malformed nonce: %s' % (why[0],))
-
- if (self.store is not None and
- not self.store.useNonce(server_url, timestamp, salt)):
- raise ProtocolError('Nonce already used or out of range')
-
- def _idResCheckSignature(self, message, server_url):
- assoc_handle = message.getArg(OPENID_NS, 'assoc_handle')
- if self.store is None:
- assoc = None
- else:
- assoc = self.store.getAssociation(server_url, assoc_handle)
-
- if assoc:
- if assoc.getExpiresIn() <= 0:
- # XXX: It might be a good idea sometimes to re-start the
- # authentication with a new association. Doing it
- # automatically opens the possibility for
- # denial-of-service by a server that just returns expired
- # associations (or really short-lived associations)
- raise ProtocolError(
- 'Association with %s expired' % (server_url,))
-
- if not assoc.checkMessageSignature(message):
- raise ProtocolError('Bad signature')
-
- else:
- # It's not an association we know about. Stateless mode is our
- # only possible path for recovery.
- # XXX - async framework will not want to block on this call to
- # _checkAuth.
- if not self._checkAuth(message, server_url):
- raise ProtocolError('Server denied check_authentication')
-
- def _idResCheckForFields(self, message):
- # XXX: this should be handled by the code that processes the
- # response (that is, if a field is missing, we should not have
- # to explicitly check that it's present, just make sure that
- # the fields are actually being used by the rest of the code
- # in tests). Although, which fields are signed does need to be
- # checked somewhere.
- basic_fields = ['return_to', 'assoc_handle', 'sig', 'signed']
- basic_sig_fields = ['return_to', 'identity']
-
- require_fields = {
- OPENID2_NS: basic_fields + ['op_endpoint'],
- OPENID1_NS: basic_fields + ['identity'],
- }
-
- require_sigs = {
- OPENID2_NS: basic_sig_fields + ['response_nonce',
- 'claimed_id',
- 'assoc_handle',
- 'op_endpoint',],
- OPENID1_NS: basic_sig_fields,
- }
-
- for field in require_fields[message.getOpenIDNamespace()]:
- if not message.hasKey(OPENID_NS, field):
- raise ProtocolError('Missing required field %r' % (field,))
-
- signed_list_str = message.getArg(OPENID_NS, 'signed', no_default)
- signed_list = signed_list_str.split(',')
-
- for field in require_sigs[message.getOpenIDNamespace()]:
- # Field is present and not in signed list
- if message.hasKey(OPENID_NS, field) and field not in signed_list:
- raise ProtocolError('"%s" not signed' % (field,))
-
-
- def _verifyReturnToArgs(query):
- """Verify that the arguments in the return_to URL are present in this
- response.
- """
- message = Message.fromPostArgs(query)
- return_to = message.getArg(OPENID_NS, 'return_to')
-
- if return_to is None:
- raise ProtocolError('Response has no return_to')
-
- parsed_url = urlparse(return_to)
- rt_query = parsed_url[4]
- parsed_args = cgi.parse_qsl(rt_query)
-
- for rt_key, rt_value in parsed_args:
- try:
- value = query[rt_key]
- if rt_value != value:
- format = ("parameter %s value %r does not match "
- "return_to's value %r")
- raise ProtocolError(format % (rt_key, value, rt_value))
- except KeyError:
- format = "return_to parameter %s absent from query %r"
- raise ProtocolError(format % (rt_key, query))
-
- # Make sure all non-OpenID arguments in the response are also
- # in the signed return_to.
- bare_args = message.getArgs(BARE_NS)
- for pair in bare_args.iteritems():
- if pair not in parsed_args:
- raise ProtocolError("Parameter %s not in return_to URL" % (pair[0],))
-
- _verifyReturnToArgs = staticmethod(_verifyReturnToArgs)
-
- def _verifyDiscoveryResults(self, resp_msg, endpoint=None):
- """
- Extract the information from an OpenID assertion message and
- verify it against the original
-
- @param endpoint: The endpoint that resulted from doing discovery
- @param resp_msg: The id_res message object
-
- @returns: the verified endpoint
- """
- if resp_msg.getOpenIDNamespace() == OPENID2_NS:
- return self._verifyDiscoveryResultsOpenID2(resp_msg, endpoint)
- else:
- return self._verifyDiscoveryResultsOpenID1(resp_msg, endpoint)
-
-
- def _verifyDiscoveryResultsOpenID2(self, resp_msg, endpoint):
- to_match = OpenIDServiceEndpoint()
- to_match.type_uris = [OPENID_2_0_TYPE]
- to_match.claimed_id = resp_msg.getArg(OPENID2_NS, 'claimed_id')
- to_match.local_id = resp_msg.getArg(OPENID2_NS, 'identity')
-
- # Raises a KeyError when the op_endpoint is not present
- to_match.server_url = resp_msg.getArg(
- OPENID2_NS, 'op_endpoint', no_default)
-
- # claimed_id and identifier must both be present or both
- # be absent
- if (to_match.claimed_id is None and
- to_match.local_id is not None):
- raise ProtocolError(
- 'openid.identity is present without openid.claimed_id')
-
- elif (to_match.claimed_id is not None and
- to_match.local_id is None):
- raise ProtocolError(
- 'openid.claimed_id is present without openid.identity')
-
- # This is a response without identifiers, so there's really no
- # checking that we can do, so return an endpoint that's for
- # the specified `openid.op_endpoint'
- elif to_match.claimed_id is None:
- return OpenIDServiceEndpoint.fromOPEndpointURL(to_match.server_url)
-
- # The claimed ID doesn't match, so we have to do discovery
- # again. This covers not using sessions, OP identifier
- # endpoints and responses that didn't match the original
- # request.
- if not endpoint:
- oidutil.log('No pre-discovered information supplied.')
- endpoint = self._discoverAndVerify(to_match.claimed_id, [to_match])
- else:
- # The claimed ID matches, so we use the endpoint that we
- # discovered in initiation. This should be the most common
- # case.
- try:
- self._verifyDiscoverySingle(endpoint, to_match)
- except ProtocolError, e:
- oidutil.log(
- "Error attempting to use stored discovery information: " +
- str(e))
- oidutil.log("Attempting discovery to verify endpoint")
- endpoint = self._discoverAndVerify(
- to_match.claimed_id, [to_match])
-
- # The endpoint we return should have the claimed ID from the
- # message we just verified, fragment and all.
- if endpoint.claimed_id != to_match.claimed_id:
- endpoint = copy.copy(endpoint)
- endpoint.claimed_id = to_match.claimed_id
- return endpoint
-
- def _verifyDiscoveryResultsOpenID1(self, resp_msg, endpoint):
- claimed_id = resp_msg.getArg(BARE_NS, self.openid1_return_to_identifier_name)
-
- if endpoint is None and claimed_id is None:
- raise RuntimeError(
- 'When using OpenID 1, the claimed ID must be supplied, '
- 'either by passing it through as a return_to parameter '
- 'or by using a session, and supplied to the GenericConsumer '
- 'as the argument to complete()')
- elif endpoint is not None and claimed_id is None:
- claimed_id = endpoint.claimed_id
-
- to_match = OpenIDServiceEndpoint()
- to_match.type_uris = [OPENID_1_1_TYPE]
- to_match.local_id = resp_msg.getArg(OPENID1_NS, 'identity')
- # Restore delegate information from the initiation phase
- to_match.claimed_id = claimed_id
-
- if to_match.local_id is None:
- raise ProtocolError('Missing required field openid.identity')
-
- to_match_1_0 = copy.copy(to_match)
- to_match_1_0.type_uris = [OPENID_1_0_TYPE]
-
- if endpoint is not None:
- try:
- try:
- self._verifyDiscoverySingle(endpoint, to_match)
- except TypeURIMismatch:
- self._verifyDiscoverySingle(endpoint, to_match_1_0)
- except ProtocolError, e:
- oidutil.log("Error attempting to use stored discovery information: " +
- str(e))
- oidutil.log("Attempting discovery to verify endpoint")
- else:
- return endpoint
-
- # Endpoint is either bad (failed verification) or None
- return self._discoverAndVerify(claimed_id, [to_match, to_match_1_0])
-
- def _verifyDiscoverySingle(self, endpoint, to_match):
- """Verify that the given endpoint matches the information
- extracted from the OpenID assertion, and raise an exception if
- there is a mismatch.
-
- @type endpoint: openid.consumer.discover.OpenIDServiceEndpoint
- @type to_match: openid.consumer.discover.OpenIDServiceEndpoint
-
- @rtype: NoneType
-
- @raises ProtocolError: when the endpoint does not match the
- discovered information.
- """
- # Every type URI that's in the to_match endpoint has to be
- # present in the discovered endpoint.
- for type_uri in to_match.type_uris:
- if not endpoint.usesExtension(type_uri):
- raise TypeURIMismatch(type_uri, endpoint)
-
- # Fragments do not influence discovery, so we can't compare a
- # claimed identifier with a fragment to discovered information.
- defragged_claimed_id, _ = urldefrag(to_match.claimed_id)
- if defragged_claimed_id != endpoint.claimed_id:
- raise ProtocolError(
- 'Claimed ID does not match (different subjects!), '
- 'Expected %s, got %s' %
- (defragged_claimed_id, endpoint.claimed_id))
-
- if to_match.getLocalID() != endpoint.getLocalID():
- raise ProtocolError('local_id mismatch. Expected %s, got %s' %
- (to_match.getLocalID(), endpoint.getLocalID()))
-
- # If the server URL is None, this must be an OpenID 1
- # response, because op_endpoint is a required parameter in
- # OpenID 2. In that case, we don't actually care what the
- # discovered server_url is, because signature checking or
- # check_auth should take care of that check for us.
- if to_match.server_url is None:
- assert to_match.preferredNamespace() == OPENID1_NS, (
- """The code calling this must ensure that OpenID 2
- responses have a non-none `openid.op_endpoint' and
- that it is set as the `server_url' attribute of the
- `to_match' endpoint.""")
-
- elif to_match.server_url != endpoint.server_url:
- raise ProtocolError('OP Endpoint mismatch. Expected %s, got %s' %
- (to_match.server_url, endpoint.server_url))
-
- def _discoverAndVerify(self, claimed_id, to_match_endpoints):
- """Given an endpoint object created from the information in an
- OpenID response, perform discovery and verify the discovery
- results, returning the matching endpoint that is the result of
- doing that discovery.
-
- @type to_match: openid.consumer.discover.OpenIDServiceEndpoint
- @param to_match: The endpoint whose information we're confirming
-
- @rtype: openid.consumer.discover.OpenIDServiceEndpoint
- @returns: The result of performing discovery on the claimed
- identifier in `to_match'
-
- @raises DiscoveryFailure: when discovery fails.
- """
- oidutil.log('Performing discovery on %s' % (claimed_id,))
- _, services = self._discover(claimed_id)
- if not services:
- raise DiscoveryFailure('No OpenID information found at %s' %
- (claimed_id,), None)
- return self._verifyDiscoveredServices(claimed_id, services,
- to_match_endpoints)
-
-
- def _verifyDiscoveredServices(self, claimed_id, services, to_match_endpoints):
- """See @L{_discoverAndVerify}"""
-
- # Search the services resulting from discovery to find one
- # that matches the information from the assertion
- failure_messages = []
- for endpoint in services:
- for to_match_endpoint in to_match_endpoints:
- try:
- self._verifyDiscoverySingle(
- endpoint, to_match_endpoint)
- except ProtocolError, why:
- failure_messages.append(str(why))
- else:
- # It matches, so discover verification has
- # succeeded. Return this endpoint.
- return endpoint
- else:
- oidutil.log('Discovery verification failure for %s' %
- (claimed_id,))
- for failure_message in failure_messages:
- oidutil.log(' * Endpoint mismatch: ' + failure_message)
-
- raise DiscoveryFailure(
- 'No matching endpoint found after discovering %s'
- % (claimed_id,), None)
-
- def _checkAuth(self, message, server_url):
- """Make a check_authentication request to verify this message.
-
- @returns: True if the request is valid.
- @rtype: bool
- """
- oidutil.log('Using OpenID check_authentication')
- request = self._createCheckAuthRequest(message)
- if request is None:
- return False
- try:
- response = self._makeKVPost(request, server_url)
- except (fetchers.HTTPFetchingError, ServerError), e:
- oidutil.log('check_authentication failed: %s' % (e[0],))
- return False
- else:
- return self._processCheckAuthResponse(response, server_url)
-
- def _createCheckAuthRequest(self, message):
- """Generate a check_authentication request message given an
- id_res message.
- """
- signed = message.getArg(OPENID_NS, 'signed')
- if signed:
- for k in signed.split(','):
- oidutil.log(k)
- val = message.getAliasedArg(k)
-
- # Signed value is missing
- if val is None:
- oidutil.log('Missing signed field %r' % (k,))
- return None
-
- check_auth_message = message.copy()
- check_auth_message.setArg(OPENID_NS, 'mode', 'check_authentication')
- return check_auth_message
-
- def _processCheckAuthResponse(self, response, server_url):
- """Process the response message from a check_authentication
- request, invalidating associations if requested.
- """
- is_valid = response.getArg(OPENID_NS, 'is_valid', 'false')
-
- invalidate_handle = response.getArg(OPENID_NS, 'invalidate_handle')
- if invalidate_handle is not None:
- oidutil.log(
- 'Received "invalidate_handle" from server %s' % (server_url,))
- if self.store is None:
- oidutil.log('Unexpectedly got invalidate_handle without '
- 'a store!')
- else:
- self.store.removeAssociation(server_url, invalidate_handle)
-
- if is_valid == 'true':
- return True
- else:
- oidutil.log('Server responds that checkAuth call is not valid')
- return False
-
- def _getAssociation(self, endpoint):
- """Get an association for the endpoint's server_url.
-
- First try seeing if we have a good association in the
- store. If we do not, then attempt to negotiate an association
- with the server.
-
- If we negotiate a good association, it will get stored.
-
- @returns: A valid association for the endpoint's server_url or None
- @rtype: openid.association.Association or NoneType
- """
- assoc = self.store.getAssociation(endpoint.server_url)
-
- if assoc is None or assoc.expiresIn <= 0:
- assoc = self._negotiateAssociation(endpoint)
- if assoc is not None:
- self.store.storeAssociation(endpoint.server_url, assoc)
-
- return assoc
-
- def _negotiateAssociation(self, endpoint):
- """Make association requests to the server, attempting to
- create a new association.
-
- @returns: a new association object
-
- @rtype: L{openid.association.Association}
- """
- # Get our preferred session/association type from the negotiatior.
- assoc_type, session_type = self.negotiator.getAllowedType()
-
- try:
- assoc = self._requestAssociation(
- endpoint, assoc_type, session_type)
- except ServerError, why:
- supportedTypes = self._extractSupportedAssociationType(why,
- endpoint,
- assoc_type)
- if supportedTypes is not None:
- assoc_type, session_type = supportedTypes
- # Attempt to create an association from the assoc_type
- # and session_type that the server told us it
- # supported.
- try:
- assoc = self._requestAssociation(
- endpoint, assoc_type, session_type)
- except ServerError, why:
- # Do not keep trying, since it rejected the
- # association type that it told us to use.
- oidutil.log('Server %s refused its suggested association '
- 'type: session_type=%s, assoc_type=%s'
- % (endpoint.server_url, session_type,
- assoc_type))
- return None
- else:
- return assoc
- else:
- return assoc
-
- def _extractSupportedAssociationType(self, server_error, endpoint,
- assoc_type):
- """Handle ServerErrors resulting from association requests.
-
- @returns: If server replied with an C{unsupported-type} error,
- return a tuple of supported C{association_type}, C{session_type}.
- Otherwise logs the error and returns None.
- @rtype: tuple or None
- """
- # Any error message whose code is not 'unsupported-type'
- # should be considered a total failure.
- if server_error.error_code != 'unsupported-type' or \
- server_error.message.isOpenID1():
- oidutil.log(
- 'Server error when requesting an association from %r: %s'
- % (endpoint.server_url, server_error.error_text))
- return None
-
- # The server didn't like the association/session type
- # that we sent, and it sent us back a message that
- # might tell us how to handle it.
- oidutil.log(
- 'Unsupported association type %s: %s' % (assoc_type,
- server_error.error_text,))
-
- # Extract the session_type and assoc_type from the
- # error message
- assoc_type = server_error.message.getArg(OPENID_NS, 'assoc_type')
- session_type = server_error.message.getArg(OPENID_NS, 'session_type')
-
- if assoc_type is None or session_type is None:
- oidutil.log('Server responded with unsupported association '
- 'session but did not supply a fallback.')
- return None
- elif not self.negotiator.isAllowed(assoc_type, session_type):
- fmt = ('Server sent unsupported session/association type: '
- 'session_type=%s, assoc_type=%s')
- oidutil.log(fmt % (session_type, assoc_type))
- return None
- else:
- return assoc_type, session_type
-
-
- def _requestAssociation(self, endpoint, assoc_type, session_type):
- """Make and process one association request to this endpoint's
- OP endpoint URL.
-
- @returns: An association object or None if the association
- processing failed.
-
- @raises ServerError: when the remote OpenID server returns an error.
- """
- assoc_session, args = self._createAssociateRequest(
- endpoint, assoc_type, session_type)
-
- try:
- response = self._makeKVPost(args, endpoint.server_url)
- except fetchers.HTTPFetchingError, why:
- oidutil.log('openid.associate request failed: %s' % (why[0],))
- return None
-
- try:
- assoc = self._extractAssociation(response, assoc_session)
- except KeyError, why:
- oidutil.log('Missing required parameter in response from %s: %s'
- % (endpoint.server_url, why[0]))
- return None
- except ProtocolError, why:
- oidutil.log('Protocol error parsing response from %s: %s' % (
- endpoint.server_url, why[0]))
- return None
- else:
- return assoc
-
- def _createAssociateRequest(self, endpoint, assoc_type, session_type):
- """Create an association request for the given assoc_type and
- session_type.
-
- @param endpoint: The endpoint whose server_url will be
- queried. The important bit about the endpoint is whether
- it's in compatiblity mode (OpenID 1.1)
-
- @param assoc_type: The association type that the request
- should ask for.
- @type assoc_type: str
-
- @param session_type: The session type that should be used in
- the association request. The session_type is used to
- create an association session object, and that session
- object is asked for any additional fields that it needs to
- add to the request.
- @type session_type: str
-
- @returns: a pair of the association session object and the
- request message that will be sent to the server.
- @rtype: (association session type (depends on session_type),
- openid.message.Message)
- """
- session_type_class = self.session_types[session_type]
- assoc_session = session_type_class()
-
- args = {
- 'mode': 'associate',
- 'assoc_type': assoc_type,
- }
-
- if not endpoint.compatibilityMode():
- args['ns'] = OPENID2_NS
-
- # Leave out the session type if we're in compatibility mode
- # *and* it's no-encryption.
- if (not endpoint.compatibilityMode() or
- assoc_session.session_type != 'no-encryption'):
- args['session_type'] = assoc_session.session_type
-
- args.update(assoc_session.getRequest())
- message = Message.fromOpenIDArgs(args)
- return assoc_session, message
-
- def _getOpenID1SessionType(self, assoc_response):
- """Given an association response message, extract the OpenID
- 1.X session type.
-
- This function mostly takes care of the 'no-encryption' default
- behavior in OpenID 1.
-
- If the association type is plain-text, this function will
- return 'no-encryption'
-
- @returns: The association type for this message
- @rtype: str
-
- @raises KeyError: when the session_type field is absent.
- """
- # If it's an OpenID 1 message, allow session_type to default
- # to None (which signifies "no-encryption")
- session_type = assoc_response.getArg(OPENID1_NS, 'session_type')
-
- # Handle the differences between no-encryption association
- # respones in OpenID 1 and 2:
-
- # no-encryption is not really a valid session type for
- # OpenID 1, but we'll accept it anyway, while issuing a
- # warning.
- if session_type == 'no-encryption':
- oidutil.log('WARNING: OpenID server sent "no-encryption"'
- 'for OpenID 1.X')
-
- # Missing or empty session type is the way to flag a
- # 'no-encryption' response. Change the session type to
- # 'no-encryption' so that it can be handled in the same
- # way as OpenID 2 'no-encryption' respones.
- elif session_type == '' or session_type is None:
- session_type = 'no-encryption'
-
- return session_type
-
- def _extractAssociation(self, assoc_response, assoc_session):
- """Attempt to extract an association from the response, given
- the association response message and the established
- association session.
-
- @param assoc_response: The association response message from
- the server
- @type assoc_response: openid.message.Message
-
- @param assoc_session: The association session object that was
- used when making the request
- @type assoc_session: depends on the session type of the request
-
- @raises ProtocolError: when data is malformed
- @raises KeyError: when a field is missing
-
- @rtype: openid.association.Association
- """
- # Extract the common fields from the response, raising an
- # exception if they are not found
- assoc_type = assoc_response.getArg(
- OPENID_NS, 'assoc_type', no_default)
- assoc_handle = assoc_response.getArg(
- OPENID_NS, 'assoc_handle', no_default)
-
- # expires_in is a base-10 string. The Python parsing will
- # accept literals that have whitespace around them and will
- # accept negative values. Neither of these are really in-spec,
- # but we think it's OK to accept them.
- expires_in_str = assoc_response.getArg(
- OPENID_NS, 'expires_in', no_default)
- try:
- expires_in = int(expires_in_str)
- except ValueError, why:
- raise ProtocolError('Invalid expires_in field: %s' % (why[0],))
-
- # OpenID 1 has funny association session behaviour.
- if assoc_response.isOpenID1():
- session_type = self._getOpenID1SessionType(assoc_response)
- else:
- session_type = assoc_response.getArg(
- OPENID2_NS, 'session_type', no_default)
-
- # Session type mismatch
- if assoc_session.session_type != session_type:
- if (assoc_response.isOpenID1() and
- session_type == 'no-encryption'):
- # In OpenID 1, any association request can result in a
- # 'no-encryption' association response. Setting
- # assoc_session to a new no-encryption session should
- # make the rest of this function work properly for
- # that case.
- assoc_session = PlainTextConsumerSession()
- else:
- # Any other mismatch, regardless of protocol version
- # results in the failure of the association session
- # altogether.
- fmt = 'Session type mismatch. Expected %r, got %r'
- message = fmt % (assoc_session.session_type, session_type)
- raise ProtocolError(message)
-
- # Make sure assoc_type is valid for session_type
- if assoc_type not in assoc_session.allowed_assoc_types:
- fmt = 'Unsupported assoc_type for session %s returned: %s'
- raise ProtocolError(fmt % (assoc_session.session_type, assoc_type))
-
- # Delegate to the association session to extract the secret
- # from the response, however is appropriate for that session
- # type.
- try:
- secret = assoc_session.extractSecret(assoc_response)
- except ValueError, why:
- fmt = 'Malformed response for %s session: %s'
- raise ProtocolError(fmt % (assoc_session.session_type, why[0]))
-
- return Association.fromExpiresIn(
- expires_in, assoc_handle, secret, assoc_type)
-
-class AuthRequest(object):
- """An object that holds the state necessary for generating an
- OpenID authentication request. This object holds the association
- with the server and the discovered information with which the
- request will be made.
-
- It is separate from the consumer because you may wish to add
- things to the request before sending it on its way to the
- server. It also has serialization options that let you encode the
- authentication request as a URL or as a form POST.
- """
-
- def __init__(self, endpoint, assoc):
- """
- Creates a new AuthRequest object. This just stores each
- argument in an appropriately named field.
-
- Users of this library should not create instances of this
- class. Instances of this class are created by the library
- when needed.
- """
- self.assoc = assoc
- self.endpoint = endpoint
- self.return_to_args = {}
- self.message = Message(endpoint.preferredNamespace())
- self._anonymous = False
-
- def setAnonymous(self, is_anonymous):
- """Set whether this request should be made anonymously. If a
- request is anonymous, the identifier will not be sent in the
- request. This is only useful if you are making another kind of
- request with an extension in this request.
-
- Anonymous requests are not allowed when the request is made
- with OpenID 1.
-
- @raises ValueError: when attempting to set an OpenID1 request
- as anonymous
- """
- if is_anonymous and self.message.isOpenID1():
- raise ValueError('OpenID 1 requests MUST include the '
- 'identifier in the request')
- else:
- self._anonymous = is_anonymous
-
- def addExtension(self, extension_request):
- """Add an extension to this checkid request.
-
- @param extension_request: An object that implements the
- extension interface for adding arguments to an OpenID
- message.
- """
- extension_request.toMessage(self.message)
-
- def addExtensionArg(self, namespace, key, value):
- """Add an extension argument to this OpenID authentication
- request.
-
- Use caution when adding arguments, because they will be
- URL-escaped and appended to the redirect URL, which can easily
- get quite long.
-
- @param namespace: The namespace for the extension. For
- example, the simple registration extension uses the
- namespace C{sreg}.
-
- @type namespace: str
-
- @param key: The key within the extension namespace. For
- example, the nickname field in the simple registration
- extension's key is C{nickname}.
-
- @type key: str
-
- @param value: The value to provide to the server for this
- argument.
-
- @type value: str
- """
- self.message.setArg(namespace, key, value)
-
- def getMessage(self, realm, return_to=None, immediate=False):
- """Produce a L{openid.message.Message} representing this request.
-
- @param realm: The URL (or URL pattern) that identifies your
- web site to the user when she is authorizing it.
-
- @type realm: str
-
- @param return_to: The URL that the OpenID provider will send the
- user back to after attempting to verify her identity.
-
- Not specifying a return_to URL means that the user will not
- be returned to the site issuing the request upon its
- completion.
-
- @type return_to: str
-
- @param immediate: If True, the OpenID provider is to send back
- a response immediately, useful for behind-the-scenes
- authentication attempts. Otherwise the OpenID provider
- may engage the user before providing a response. This is
- the default case, as the user may need to provide
- credentials or approve the request before a positive
- response can be sent.
-
- @type immediate: bool
-
- @returntype: L{openid.message.Message}
- """
- if return_to:
- return_to = oidutil.appendArgs(return_to, self.return_to_args)
- elif immediate:
- raise ValueError(
- '"return_to" is mandatory when using "checkid_immediate"')
- elif self.message.isOpenID1():
- raise ValueError('"return_to" is mandatory for OpenID 1 requests')
- elif self.return_to_args:
- raise ValueError('extra "return_to" arguments were specified, '
- 'but no return_to was specified')
-
- if immediate:
- mode = 'checkid_immediate'
- else:
- mode = 'checkid_setup'
-
- message = self.message.copy()
- if message.isOpenID1():
- realm_key = 'trust_root'
- else:
- realm_key = 'realm'
-
- message.updateArgs(OPENID_NS,
- {
- realm_key:realm,
- 'mode':mode,
- 'return_to':return_to,
- })
-
- if not self._anonymous:
- if self.endpoint.isOPIdentifier():
- # This will never happen when we're in compatibility
- # mode, as long as isOPIdentifier() returns False
- # whenever preferredNamespace() returns OPENID1_NS.
- claimed_id = request_identity = IDENTIFIER_SELECT
- else:
- request_identity = self.endpoint.getLocalID()
- claimed_id = self.endpoint.claimed_id
-
- # This is true for both OpenID 1 and 2
- message.setArg(OPENID_NS, 'identity', request_identity)
-
- if message.isOpenID2():
- message.setArg(OPENID2_NS, 'claimed_id', claimed_id)
-
- if self.assoc:
- message.setArg(OPENID_NS, 'assoc_handle', self.assoc.handle)
- assoc_log_msg = 'with assocication %s' % (self.assoc.handle,)
- else:
- assoc_log_msg = 'using stateless mode.'
-
- oidutil.log("Generated %s request to %s %s" %
- (mode, self.endpoint.server_url, assoc_log_msg))
-
- return message
-
- def redirectURL(self, realm, return_to=None, immediate=False):
- """Returns a URL with an encoded OpenID request.
-
- The resulting URL is the OpenID provider's endpoint URL with
- parameters appended as query arguments. You should redirect
- the user agent to this URL.
-
- OpenID 2.0 endpoints also accept POST requests, see
- C{L{shouldSendRedirect}} and C{L{formMarkup}}.
-
- @param realm: The URL (or URL pattern) that identifies your
- web site to the user when she is authorizing it.
-
- @type realm: str
-
- @param return_to: The URL that the OpenID provider will send the
- user back to after attempting to verify her identity.
-
- Not specifying a return_to URL means that the user will not
- be returned to the site issuing the request upon its
- completion.
-
- @type return_to: str
-
- @param immediate: If True, the OpenID provider is to send back
- a response immediately, useful for behind-the-scenes
- authentication attempts. Otherwise the OpenID provider
- may engage the user before providing a response. This is
- the default case, as the user may need to provide
- credentials or approve the request before a positive
- response can be sent.
-
- @type immediate: bool
-
- @returns: The URL to redirect the user agent to.
-
- @returntype: str
- """
- message = self.getMessage(realm, return_to, immediate)
- return message.toURL(self.endpoint.server_url)
-
- def formMarkup(self, realm, return_to=None, immediate=False,
- form_tag_attrs=None):
- """Get html for a form to submit this request to the IDP.
-
- @param form_tag_attrs: Dictionary of attributes to be added to
- the form tag. 'accept-charset' and 'enctype' have defaults
- that can be overridden. If a value is supplied for
- 'action' or 'method', it will be replaced.
- @type form_tag_attrs: {unicode: unicode}
- """
- message = self.getMessage(realm, return_to, immediate)
- return message.toFormMarkup(self.endpoint.server_url,
- form_tag_attrs)
-
- def htmlMarkup(self, realm, return_to=None, immediate=False,
- form_tag_attrs=None):
- """Get an autosubmitting HTML page that submits this request to the
- IDP. This is just a wrapper for formMarkup.
-
- @see: formMarkup
-
- @returns: str
- """
- return oidutil.autoSubmitHTML(self.formMarkup(realm,
- return_to,
- immediate,
- form_tag_attrs))
-
- def shouldSendRedirect(self):
- """Should this OpenID authentication request be sent as a HTTP
- redirect or as a POST (form submission)?
-
- @rtype: bool
- """
- return self.endpoint.compatibilityMode()
-
-FAILURE = 'failure'
-SUCCESS = 'success'
-CANCEL = 'cancel'
-SETUP_NEEDED = 'setup_needed'
-
-class Response(object):
- status = None
-
- def setEndpoint(self, endpoint):
- self.endpoint = endpoint
- if endpoint is None:
- self.identity_url = None
- else:
- self.identity_url = endpoint.claimed_id
-
- def getDisplayIdentifier(self):
- """Return the display identifier for this response.
-
- The display identifier is related to the Claimed Identifier, but the
- two are not always identical. The display identifier is something the
- user should recognize as what they entered, whereas the response's
- claimed identifier (in the L{identity_url} attribute) may have extra
- information for better persistence.
-
- URLs will be stripped of their fragments for display. XRIs will
- display the human-readable identifier (i-name) instead of the
- persistent identifier (i-number).
-
- Use the display identifier in your user interface. Use
- L{identity_url} for querying your database or authorization server.
- """
- if self.endpoint is not None:
- return self.endpoint.getDisplayIdentifier()
- return None
-
-class SuccessResponse(Response):
- """A response with a status of SUCCESS. Indicates that this request is a
- successful acknowledgement from the OpenID server that the
- supplied URL is, indeed controlled by the requesting agent.
-
- @ivar identity_url: The identity URL that has been authenticated; the Claimed Identifier.
- See also L{getDisplayIdentifier}.
-
- @ivar endpoint: The endpoint that authenticated the identifier. You
- may access other discovered information related to this endpoint,
- such as the CanonicalID of an XRI, through this object.
- @type endpoint: L{OpenIDServiceEndpoint<openid.consumer.discover.OpenIDServiceEndpoint>}
-
- @ivar signed_fields: The arguments in the server's response that
- were signed and verified.
-
- @cvar status: SUCCESS
- """
-
- status = SUCCESS
-
- def __init__(self, endpoint, message, signed_fields=None):
- # Don't use setEndpoint, because endpoint should never be None
- # for a successfull transaction.
- self.endpoint = endpoint
- self.identity_url = endpoint.claimed_id
-
- self.message = message
-
- if signed_fields is None:
- signed_fields = []
- self.signed_fields = signed_fields
-
- def isOpenID1(self):
- """Was this authentication response an OpenID 1 authentication
- response?
- """
- return self.message.isOpenID1()
-
- def isSigned(self, ns_uri, ns_key):
- """Return whether a particular key is signed, regardless of
- its namespace alias
- """
- return self.message.getKey(ns_uri, ns_key) in self.signed_fields
-
- def getSigned(self, ns_uri, ns_key, default=None):
- """Return the specified signed field if available,
- otherwise return default
- """
- if self.isSigned(ns_uri, ns_key):
- return self.message.getArg(ns_uri, ns_key, default)
- else:
- return default
-
- def getSignedNS(self, ns_uri):
- """Get signed arguments from the response message. Return a
- dict of all arguments in the specified namespace. If any of
- the arguments are not signed, return None.
- """
- msg_args = self.message.getArgs(ns_uri)
-
- for key in msg_args.iterkeys():
- if not self.isSigned(ns_uri, key):
- oidutil.log("SuccessResponse.getSignedNS: (%s, %s) not signed."
- % (ns_uri, key))
- return None
-
- return msg_args
-
- def extensionResponse(self, namespace_uri, require_signed):
- """Return response arguments in the specified namespace.
-
- @param namespace_uri: The namespace URI of the arguments to be
- returned.
-
- @param require_signed: True if the arguments should be among
- those signed in the response, False if you don't care.
-
- If require_signed is True and the arguments are not signed,
- return None.
- """
- if require_signed:
- return self.getSignedNS(namespace_uri)
- else:
- return self.message.getArgs(namespace_uri)
-
- def getReturnTo(self):
- """Get the openid.return_to argument from this response.
-
- This is useful for verifying that this request was initiated
- by this consumer.
-
- @returns: The return_to URL supplied to the server on the
- initial request, or C{None} if the response did not contain
- an C{openid.return_to} argument.
-
- @returntype: str
- """
- return self.getSigned(OPENID_NS, 'return_to')
-
- def __eq__(self, other):
- return (
- (self.endpoint == other.endpoint) and
- (self.identity_url == other.identity_url) and
- (self.message == other.message) and
- (self.signed_fields == other.signed_fields) and
- (self.status == other.status))
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- return '<%s.%s id=%r signed=%r>' % (
- self.__class__.__module__,
- self.__class__.__name__,
- self.identity_url, self.signed_fields)
-
-
-class FailureResponse(Response):
- """A response with a status of FAILURE. Indicates that the OpenID
- protocol has failed. This could be locally or remotely triggered.
-
- @ivar identity_url: The identity URL for which authenitcation was
- attempted, if it can be determined. Otherwise, None.
-
- @ivar message: A message indicating why the request failed, if one
- is supplied. otherwise, None.
-
- @cvar status: FAILURE
- """
-
- status = FAILURE
-
- def __init__(self, endpoint, message=None, contact=None,
- reference=None):
- self.setEndpoint(endpoint)
- self.message = message
- self.contact = contact
- self.reference = reference
-
- def __repr__(self):
- return "<%s.%s id=%r message=%r>" % (
- self.__class__.__module__, self.__class__.__name__,
- self.identity_url, self.message)
-
-
-class CancelResponse(Response):
- """A response with a status of CANCEL. Indicates that the user
- cancelled the OpenID authentication request.
-
- @ivar identity_url: The identity URL for which authenitcation was
- attempted, if it can be determined. Otherwise, None.
-
- @cvar status: CANCEL
- """
-
- status = CANCEL
-
- def __init__(self, endpoint):
- self.setEndpoint(endpoint)
-
-class SetupNeededResponse(Response):
- """A response with a status of SETUP_NEEDED. Indicates that the
- request was in immediate mode, and the server is unable to
- authenticate the user without further interaction.
-
- @ivar identity_url: The identity URL for which authenitcation was
- attempted.
-
- @ivar setup_url: A URL that can be used to send the user to the
- server to set up for authentication. The user should be
- redirected in to the setup_url, either in the current window
- or in a new browser window. C{None} in OpenID 2.0.
-
- @cvar status: SETUP_NEEDED
- """
-
- status = SETUP_NEEDED
-
- def __init__(self, endpoint, setup_url=None):
- self.setEndpoint(endpoint)
- self.setup_url = setup_url
diff --git a/askbot/deps/openid/consumer/discover.py b/askbot/deps/openid/consumer/discover.py
deleted file mode 100644
index d7a0c2a3..00000000
--- a/askbot/deps/openid/consumer/discover.py
+++ /dev/null
@@ -1,470 +0,0 @@
-# -*- test-case-name: openid.test.test_discover -*-
-"""Functions to discover OpenID endpoints from identifiers.
-"""
-
-__all__ = [
- 'DiscoveryFailure',
- 'OPENID_1_0_NS',
- 'OPENID_1_0_TYPE',
- 'OPENID_1_1_TYPE',
- 'OPENID_2_0_TYPE',
- 'OPENID_IDP_2_0_TYPE',
- 'OpenIDServiceEndpoint',
- 'discover',
- ]
-
-import urlparse
-
-from askbot.deps.openid import oidutil, fetchers, urinorm
-
-from askbot.deps.openid import yadis
-from askbot.deps.openid.yadis.etxrd import nsTag, XRDSError, XRD_NS_2_0
-from askbot.deps.openid.yadis.services import applyFilter as extractServices
-from askbot.deps.openid.yadis.discover import discover as yadisDiscover
-from askbot.deps.openid.yadis.discover import DiscoveryFailure
-from askbot.deps.openid.yadis import xrires, filters
-from askbot.deps.openid.yadis import xri
-
-from askbot.deps.openid.consumer import html_parse
-
-OPENID_1_0_NS = 'http://openid.net/xmlns/1.0'
-OPENID_IDP_2_0_TYPE = 'http://specs.openid.net/auth/2.0/server'
-OPENID_2_0_TYPE = 'http://specs.openid.net/auth/2.0/signon'
-OPENID_1_1_TYPE = 'http://openid.net/signon/1.1'
-OPENID_1_0_TYPE = 'http://openid.net/signon/1.0'
-
-from askbot.deps.openid.message import OPENID1_NS as OPENID_1_0_MESSAGE_NS
-from askbot.deps.openid.message import OPENID2_NS as OPENID_2_0_MESSAGE_NS
-
-class OpenIDServiceEndpoint(object):
- """Object representing an OpenID service endpoint.
-
- @ivar identity_url: the verified identifier.
- @ivar canonicalID: For XRI, the persistent identifier.
- """
-
- # OpenID service type URIs, listed in order of preference. The
- # ordering of this list affects yadis and XRI service discovery.
- openid_type_uris = [
- OPENID_IDP_2_0_TYPE,
-
- OPENID_2_0_TYPE,
- OPENID_1_1_TYPE,
- OPENID_1_0_TYPE,
- ]
-
- def __init__(self):
- self.claimed_id = None
- self.server_url = None
- self.type_uris = []
- self.local_id = None
- self.canonicalID = None
- self.used_yadis = False # whether this came from an XRDS
- self.display_identifier = None
-
- def usesExtension(self, extension_uri):
- return extension_uri in self.type_uris
-
- def preferredNamespace(self):
- if (OPENID_IDP_2_0_TYPE in self.type_uris or
- OPENID_2_0_TYPE in self.type_uris):
- return OPENID_2_0_MESSAGE_NS
- else:
- return OPENID_1_0_MESSAGE_NS
-
- def supportsType(self, type_uri):
- """Does this endpoint support this type?
-
- I consider C{/server} endpoints to implicitly support C{/signon}.
- """
- return (
- (type_uri in self.type_uris) or
- (type_uri == OPENID_2_0_TYPE and self.isOPIdentifier())
- )
-
- def getDisplayIdentifier(self):
- """Return the display_identifier if set, else return the claimed_id.
- """
- if self.display_identifier is not None:
- return self.display_identifier
- if self.claimed_id is None:
- return None
- else:
- return urlparse.urldefrag(self.claimed_id)[0]
-
- def compatibilityMode(self):
- return self.preferredNamespace() != OPENID_2_0_MESSAGE_NS
-
- def isOPIdentifier(self):
- return OPENID_IDP_2_0_TYPE in self.type_uris
-
- def parseService(self, yadis_url, uri, type_uris, service_element):
- """Set the state of this object based on the contents of the
- service element."""
- self.type_uris = type_uris
- self.server_url = uri
- self.used_yadis = True
-
- if not self.isOPIdentifier():
- # XXX: This has crappy implications for Service elements
- # that contain both 'server' and 'signon' Types. But
- # that's a pathological configuration anyway, so I don't
- # think I care.
- self.local_id = findOPLocalIdentifier(service_element,
- self.type_uris)
- self.claimed_id = yadis_url
-
- def getLocalID(self):
- """Return the identifier that should be sent as the
- openid.identity parameter to the server."""
- # I looked at this conditional and thought "ah-hah! there's the bug!"
- # but Python actually makes that one big expression somehow, i.e.
- # "x is x is x" is not the same thing as "(x is x) is x".
- # That's pretty weird, dude. -- kmt, 1/07
- if (self.local_id is self.canonicalID is None):
- return self.claimed_id
- else:
- return self.local_id or self.canonicalID
-
- def fromBasicServiceEndpoint(cls, endpoint):
- """Create a new instance of this class from the endpoint
- object passed in.
-
- @return: None or OpenIDServiceEndpoint for this endpoint object"""
- type_uris = endpoint.matchTypes(cls.openid_type_uris)
-
- # If any Type URIs match and there is an endpoint URI
- # specified, then this is an OpenID endpoint
- if type_uris and endpoint.uri is not None:
- openid_endpoint = cls()
- openid_endpoint.parseService(
- endpoint.yadis_url,
- endpoint.uri,
- endpoint.type_uris,
- endpoint.service_element)
- else:
- openid_endpoint = None
-
- return openid_endpoint
-
- fromBasicServiceEndpoint = classmethod(fromBasicServiceEndpoint)
-
- def fromHTML(cls, uri, html):
- """Parse the given document as HTML looking for an OpenID <link
- rel=...>
-
- @rtype: [OpenIDServiceEndpoint]
- """
- discovery_types = [
- (OPENID_2_0_TYPE, 'openid2.provider', 'openid2.local_id'),
- (OPENID_1_1_TYPE, 'openid.server', 'openid.delegate'),
- ]
-
- link_attrs = html_parse.parseLinkAttrs(html)
- services = []
- for type_uri, op_endpoint_rel, local_id_rel in discovery_types:
- op_endpoint_url = html_parse.findFirstHref(
- link_attrs, op_endpoint_rel)
- if op_endpoint_url is None:
- continue
-
- service = cls()
- service.claimed_id = uri
- service.local_id = html_parse.findFirstHref(
- link_attrs, local_id_rel)
- service.server_url = op_endpoint_url
- service.type_uris = [type_uri]
-
- services.append(service)
-
- return services
-
- fromHTML = classmethod(fromHTML)
-
-
- def fromXRDS(cls, uri, xrds):
- """Parse the given document as XRDS looking for OpenID services.
-
- @rtype: [OpenIDServiceEndpoint]
-
- @raises XRDSError: When the XRDS does not parse.
-
- @since: 2.1.0
- """
- return extractServices(uri, xrds, cls)
-
- fromXRDS = classmethod(fromXRDS)
-
-
- def fromDiscoveryResult(cls, discoveryResult):
- """Create endpoints from a DiscoveryResult.
-
- @type discoveryResult: L{DiscoveryResult}
-
- @rtype: list of L{OpenIDServiceEndpoint}
-
- @raises XRDSError: When the XRDS does not parse.
-
- @since: 2.1.0
- """
- if discoveryResult.isXRDS():
- method = cls.fromXRDS
- else:
- method = cls.fromHTML
- return method(discoveryResult.normalized_uri,
- discoveryResult.response_text)
-
- fromDiscoveryResult = classmethod(fromDiscoveryResult)
-
-
- def fromOPEndpointURL(cls, op_endpoint_url):
- """Construct an OP-Identifier OpenIDServiceEndpoint object for
- a given OP Endpoint URL
-
- @param op_endpoint_url: The URL of the endpoint
- @rtype: OpenIDServiceEndpoint
- """
- service = cls()
- service.server_url = op_endpoint_url
- service.type_uris = [OPENID_IDP_2_0_TYPE]
- return service
-
- fromOPEndpointURL = classmethod(fromOPEndpointURL)
-
-
- def __str__(self):
- return ("<%s.%s "
- "server_url=%r "
- "claimed_id=%r "
- "local_id=%r "
- "canonicalID=%r "
- "used_yadis=%s "
- ">"
- % (self.__class__.__module__, self.__class__.__name__,
- self.server_url,
- self.claimed_id,
- self.local_id,
- self.canonicalID,
- self.used_yadis))
-
-
-
-def findOPLocalIdentifier(service_element, type_uris):
- """Find the OP-Local Identifier for this xrd:Service element.
-
- This considers openid:Delegate to be a synonym for xrd:LocalID if
- both OpenID 1.X and OpenID 2.0 types are present. If only OpenID
- 1.X is present, it returns the value of openid:Delegate. If only
- OpenID 2.0 is present, it returns the value of xrd:LocalID. If
- there is more than one LocalID tag and the values are different,
- it raises a DiscoveryFailure. This is also triggered when the
- xrd:LocalID and openid:Delegate tags are different.
-
- @param service_element: The xrd:Service element
- @type service_element: ElementTree.Node
-
- @param type_uris: The xrd:Type values present in this service
- element. This function could extract them, but higher level
- code needs to do that anyway.
- @type type_uris: [str]
-
- @raises DiscoveryFailure: when discovery fails.
-
- @returns: The OP-Local Identifier for this service element, if one
- is present, or None otherwise.
- @rtype: str or unicode or NoneType
- """
- # XXX: Test this function on its own!
-
- # Build the list of tags that could contain the OP-Local Identifier
- local_id_tags = []
- if (OPENID_1_1_TYPE in type_uris or
- OPENID_1_0_TYPE in type_uris):
- local_id_tags.append(nsTag(OPENID_1_0_NS, 'Delegate'))
-
- if OPENID_2_0_TYPE in type_uris:
- local_id_tags.append(nsTag(XRD_NS_2_0, 'LocalID'))
-
- # Walk through all the matching tags and make sure that they all
- # have the same value
- local_id = None
- for local_id_tag in local_id_tags:
- for local_id_element in service_element.findall(local_id_tag):
- if local_id is None:
- local_id = local_id_element.text
- elif local_id != local_id_element.text:
- format = 'More than one %r tag found in one service element'
- message = format % (local_id_tag,)
- raise DiscoveryFailure(message, None)
-
- return local_id
-
-def normalizeURL(url):
- """Normalize a URL, converting normalization failures to
- DiscoveryFailure"""
- try:
- normalized = urinorm.urinorm(url)
- except ValueError, why:
- raise DiscoveryFailure('Normalizing identifier: %s' % (why[0],), None)
- else:
- return urlparse.urldefrag(normalized)[0]
-
-def normalizeXRI(xri):
- """Normalize an XRI, stripping its scheme if present"""
- if xri.startswith("xri://"):
- xri = xri[6:]
- return xri
-
-def arrangeByType(service_list, preferred_types):
- """Rearrange service_list in a new list so services are ordered by
- types listed in preferred_types. Return the new list."""
-
- def enumerate(elts):
- """Return an iterable that pairs the index of an element with
- that element.
-
- For Python 2.2 compatibility"""
- return zip(range(len(elts)), elts)
-
- def bestMatchingService(service):
- """Return the index of the first matching type, or something
- higher if no type matches.
-
- This provides an ordering in which service elements that
- contain a type that comes earlier in the preferred types list
- come before service elements that come later. If a service
- element has more than one type, the most preferred one wins.
- """
- for i, t in enumerate(preferred_types):
- if preferred_types[i] in service.type_uris:
- return i
-
- return len(preferred_types)
-
- # Build a list with the service elements in tuples whose
- # comparison will prefer the one with the best matching service
- prio_services = [(bestMatchingService(s), orig_index, s)
- for (orig_index, s) in enumerate(service_list)]
- prio_services.sort()
-
- # Now that the services are sorted by priority, remove the sort
- # keys from the list.
- for i in range(len(prio_services)):
- prio_services[i] = prio_services[i][2]
-
- return prio_services
-
-def getOPOrUserServices(openid_services):
- """Extract OP Identifier services. If none found, return the
- rest, sorted with most preferred first according to
- OpenIDServiceEndpoint.openid_type_uris.
-
- openid_services is a list of OpenIDServiceEndpoint objects.
-
- Returns a list of OpenIDServiceEndpoint objects."""
-
- op_services = arrangeByType(openid_services, [OPENID_IDP_2_0_TYPE])
-
- openid_services = arrangeByType(openid_services,
- OpenIDServiceEndpoint.openid_type_uris)
-
- return op_services or openid_services
-
-def discoverYadis(uri):
- """Discover OpenID services for a URI. Tries Yadis and falls back
- on old-style <link rel='...'> discovery if Yadis fails.
-
- @param uri: normalized identity URL
- @type uri: str
-
- @return: (claimed_id, services)
- @rtype: (str, list(OpenIDServiceEndpoint))
-
- @raises DiscoveryFailure: when discovery fails.
- """
- # Might raise a yadis.discover.DiscoveryFailure if no document
- # came back for that URI at all. I don't think falling back
- # to OpenID 1.0 discovery on the same URL will help, so don't
- # bother to catch it.
- response = yadisDiscover(uri)
-
- yadis_url = response.normalized_uri
- body = response.response_text
- try:
- openid_services = OpenIDServiceEndpoint.fromXRDS(yadis_url, body)
- except XRDSError:
- # Does not parse as a Yadis XRDS file
- openid_services = []
-
- if not openid_services:
- # Either not an XRDS or there are no OpenID services.
-
- if response.isXRDS():
- # if we got the Yadis content-type or followed the Yadis
- # header, re-fetch the document without following the Yadis
- # header, with no Accept header.
- return discoverNoYadis(uri)
-
- # Try to parse the response as HTML.
- # <link rel="...">
- openid_services = OpenIDServiceEndpoint.fromHTML(yadis_url, body)
-
- return (yadis_url, getOPOrUserServices(openid_services))
-
-def discoverXRI(iname):
- endpoints = []
- iname = normalizeXRI(iname)
- try:
- canonicalID, services = xrires.ProxyResolver().query(
- iname, OpenIDServiceEndpoint.openid_type_uris)
-
- if canonicalID is None:
- raise XRDSError('No CanonicalID found for XRI %r' % (iname,))
-
- flt = filters.mkFilter(OpenIDServiceEndpoint)
- for service_element in services:
- endpoints.extend(flt.getServiceEndpoints(iname, service_element))
- except XRDSError:
- oidutil.log('xrds error on ' + iname)
-
- for endpoint in endpoints:
- # Is there a way to pass this through the filter to the endpoint
- # constructor instead of tacking it on after?
- endpoint.canonicalID = canonicalID
- endpoint.claimed_id = canonicalID
- endpoint.display_identifier = iname
-
- # FIXME: returned xri should probably be in some normal form
- return iname, getOPOrUserServices(endpoints)
-
-
-def discoverNoYadis(uri):
- http_resp = fetchers.fetch(uri)
- if http_resp.status not in (200, 206):
- raise DiscoveryFailure(
- 'HTTP Response status from identity URL host is not 200. '
- 'Got status %r' % (http_resp.status,), http_resp)
-
- claimed_id = http_resp.final_url
- openid_services = OpenIDServiceEndpoint.fromHTML(
- claimed_id, http_resp.body)
- return claimed_id, openid_services
-
-def discoverURI(uri):
- parsed = urlparse.urlparse(uri)
- if parsed[0] and parsed[1]:
- if parsed[0] not in ['http', 'https']:
- raise DiscoveryFailure('URI scheme is not HTTP or HTTPS', None)
- else:
- uri = 'http://' + uri
-
- uri = normalizeURL(uri)
- claimed_id, openid_services = discoverYadis(uri)
- claimed_id = normalizeURL(claimed_id)
- return claimed_id, openid_services
-
-def discover(identifier):
- if xri.identifierScheme(identifier) == "XRI":
- return discoverXRI(identifier)
- else:
- return discoverURI(identifier)
diff --git a/askbot/deps/openid/consumer/html_parse.py b/askbot/deps/openid/consumer/html_parse.py
deleted file mode 100644
index 880dfda6..00000000
--- a/askbot/deps/openid/consumer/html_parse.py
+++ /dev/null
@@ -1,249 +0,0 @@
-"""
-This module implements a VERY limited parser that finds <link> tags in
-the head of HTML or XHTML documents and parses out their attributes
-according to the OpenID spec. It is a liberal parser, but it requires
-these things from the data in order to work:
-
- - There must be an open <html> tag
-
- - There must be an open <head> tag inside of the <html> tag
-
- - Only <link>s that are found inside of the <head> tag are parsed
- (this is by design)
-
- - The parser follows the OpenID specification in resolving the
- attributes of the link tags. This means that the attributes DO NOT
- get resolved as they would by an XML or HTML parser. In particular,
- only certain entities get replaced, and href attributes do not get
- resolved relative to a base URL.
-
-From http://openid.net/specs.bml#linkrel:
-
- - The openid.server URL MUST be an absolute URL. OpenID consumers
- MUST NOT attempt to resolve relative URLs.
-
- - The openid.server URL MUST NOT include entities other than &amp;,
- &lt;, &gt;, and &quot;.
-
-The parser ignores SGML comments and <![CDATA[blocks]]>. Both kinds of
-quoting are allowed for attributes.
-
-The parser deals with invalid markup in these ways:
-
- - Tag names are not case-sensitive
-
- - The <html> tag is accepted even when it is not at the top level
-
- - The <head> tag is accepted even when it is not a direct child of
- the <html> tag, but a <html> tag must be an ancestor of the <head>
- tag
-
- - <link> tags are accepted even when they are not direct children of
- the <head> tag, but a <head> tag must be an ancestor of the <link>
- tag
-
- - If there is no closing tag for an open <html> or <head> tag, the
- remainder of the document is viewed as being inside of the tag. If
- there is no closing tag for a <link> tag, the link tag is treated
- as a short tag. Exceptions to this rule are that <html> closes
- <html> and <body> or <head> closes <head>
-
- - Attributes of the <link> tag are not required to be quoted.
-
- - In the case of duplicated attribute names, the attribute coming
- last in the tag will be the value returned.
-
- - Any text that does not parse as an attribute within a link tag will
- be ignored. (e.g. <link pumpkin rel='openid.server' /> will ignore
- pumpkin)
-
- - If there are more than one <html> or <head> tag, the parser only
- looks inside of the first one.
-
- - The contents of <script> tags are ignored entirely, except unclosed
- <script> tags. Unclosed <script> tags are ignored.
-
- - Any other invalid markup is ignored, including unclosed SGML
- comments and unclosed <![CDATA[blocks.
-"""
-
-__all__ = ['parseLinkAttrs']
-
-import re
-
-flags = ( re.DOTALL # Match newlines with '.'
- | re.IGNORECASE
- | re.VERBOSE # Allow comments and whitespace in patterns
- | re.UNICODE # Make \b respect Unicode word boundaries
- )
-
-# Stuff to remove before we start looking for tags
-removed_re = re.compile(r'''
- # Comments
- <!--.*?-->
-
- # CDATA blocks
-| <!\[CDATA\[.*?\]\]>
-
- # script blocks
-| <script\b
-
- # make sure script is not an XML namespace
- (?!:)
-
- [^>]*>.*?</script>
-
-''', flags)
-
-tag_expr = r'''
-# Starts with the tag name at a word boundary, where the tag name is
-# not a namespace
-<%(tag_name)s\b(?!:)
-
-# All of the stuff up to a ">", hopefully attributes.
-(?P<attrs>[^>]*?)
-
-(?: # Match a short tag
- />
-
-| # Match a full tag
- >
-
- (?P<contents>.*?)
-
- # Closed by
- (?: # One of the specified close tags
- </?%(closers)s\s*>
-
- # End of the string
- | \Z
-
- )
-
-)
-'''
-
-def tagMatcher(tag_name, *close_tags):
- if close_tags:
- options = '|'.join((tag_name,) + close_tags)
- closers = '(?:%s)' % (options,)
- else:
- closers = tag_name
-
- expr = tag_expr % locals()
- return re.compile(expr, flags)
-
-# Must contain at least an open html and an open head tag
-html_find = tagMatcher('html')
-head_find = tagMatcher('head', 'body')
-link_find = re.compile(r'<link\b(?!:)', flags)
-
-attr_find = re.compile(r'''
-# Must start with a sequence of word-characters, followed by an equals sign
-(?P<attr_name>\w+)=
-
-# Then either a quoted or unquoted attribute
-(?:
-
- # Match everything that\'s between matching quote marks
- (?P<qopen>["\'])(?P<q_val>.*?)(?P=qopen)
-|
-
- # If the value is not quoted, match up to whitespace
- (?P<unq_val>(?:[^\s<>/]|/(?!>))+)
-)
-
-|
-
-(?P<end_link>[<>])
-''', flags)
-
-# Entity replacement:
-replacements = {
- 'amp':'&',
- 'lt':'<',
- 'gt':'>',
- 'quot':'"',
- }
-
-ent_replace = re.compile(r'&(%s);' % '|'.join(replacements.keys()))
-def replaceEnt(mo):
- "Replace the entities that are specified by OpenID"
- return replacements.get(mo.group(1), mo.group())
-
-def parseLinkAttrs(html):
- """Find all link tags in a string representing a HTML document and
- return a list of their attributes.
-
- @param html: the text to parse
- @type html: str or unicode
-
- @return: A list of dictionaries of attributes, one for each link tag
- @rtype: [[(type(html), type(html))]]
- """
- stripped = removed_re.sub('', html)
- html_mo = html_find.search(stripped)
- if html_mo is None or html_mo.start('contents') == -1:
- return []
-
- start, end = html_mo.span('contents')
- head_mo = head_find.search(stripped, start, end)
- if head_mo is None or head_mo.start('contents') == -1:
- return []
-
- start, end = head_mo.span('contents')
- link_mos = link_find.finditer(stripped, head_mo.start(), head_mo.end())
-
- matches = []
- for link_mo in link_mos:
- start = link_mo.start() + 5
- link_attrs = {}
- for attr_mo in attr_find.finditer(stripped, start):
- if attr_mo.lastgroup == 'end_link':
- break
-
- # Either q_val or unq_val must be present, but not both
- # unq_val is a True (non-empty) value if it is present
- attr_name, q_val, unq_val = attr_mo.group(
- 'attr_name', 'q_val', 'unq_val')
- attr_val = ent_replace.sub(replaceEnt, unq_val or q_val)
-
- link_attrs[attr_name] = attr_val
-
- matches.append(link_attrs)
-
- return matches
-
-def relMatches(rel_attr, target_rel):
- """Does this target_rel appear in the rel_str?"""
- # XXX: TESTME
- rels = rel_attr.strip().split()
- for rel in rels:
- rel = rel.lower()
- if rel == target_rel:
- return 1
-
- return 0
-
-def linkHasRel(link_attrs, target_rel):
- """Does this link have target_rel as a relationship?"""
- # XXX: TESTME
- rel_attr = link_attrs.get('rel')
- return rel_attr and relMatches(rel_attr, target_rel)
-
-def findLinksRel(link_attrs_list, target_rel):
- """Filter the list of link attributes on whether it has target_rel
- as a relationship."""
- # XXX: TESTME
- matchesTarget = lambda attrs: linkHasRel(attrs, target_rel)
- return filter(matchesTarget, link_attrs_list)
-
-def findFirstHref(link_attrs_list, target_rel):
- """Return the value of the href attribute for the first link tag
- in the list that has target_rel as a relationship."""
- # XXX: TESTME
- matches = findLinksRel(link_attrs_list, target_rel)
- if not matches:
- return None
- first = matches[0]
- return first.get('href')
diff --git a/askbot/deps/openid/cryptutil.py b/askbot/deps/openid/cryptutil.py
deleted file mode 100644
index 8d4bef8a..00000000
--- a/askbot/deps/openid/cryptutil.py
+++ /dev/null
@@ -1,220 +0,0 @@
-"""Module containing a cryptographic-quality source of randomness and
-other cryptographically useful functionality
-
-Python 2.4 needs no external support for this module, nor does Python
-2.3 on a system with /dev/urandom.
-
-Other configurations will need a quality source of random bytes and
-access to a function that will convert binary strings to long
-integers. This module will work with the Python Cryptography Toolkit
-(pycrypto) if it is present. pycrypto can be found with a search
-engine, but is currently found at:
-
-http://www.amk.ca/python/code/crypto
-"""
-
-__all__ = [
- 'base64ToLong',
- 'binaryToLong',
- 'hmacSha1',
- 'hmacSha256',
- 'longToBase64',
- 'longToBinary',
- 'randomString',
- 'randrange',
- 'sha1',
- 'sha256',
- ]
-
-import hmac
-import os
-import random
-
-from askbot.deps.openid.oidutil import toBase64, fromBase64
-
-try:
- import hashlib
-except ImportError:
- import sha as sha1_module
-
- try:
- from Crypto.Hash import SHA256 as sha256_module
- except ImportError:
- sha256_module = None
-
-else:
- class HashContainer(object):
- def __init__(self, hash_constructor):
- self.new = hash_constructor
- self.digest_size = hash_constructor().digest_size
-
- sha1_module = HashContainer(hashlib.sha1)
- sha256_module = HashContainer(hashlib.sha256)
-
-def hmacSha1(key, text):
- return hmac.new(key, text, sha1_module).digest()
-
-def sha1(s):
- return sha1_module.new(s).digest()
-
-if sha256_module is not None:
- def hmacSha256(key, text):
- return hmac.new(key, text, sha256_module).digest()
-
- def sha256(s):
- return sha256_module.new(s).digest()
-
- SHA256_AVAILABLE = True
-
-else:
- _no_sha256 = NotImplementedError(
- 'Use Python 2.5, install pycrypto or install hashlib to use SHA256')
-
- def hmacSha256(unused_key, unused_text):
- raise _no_sha256
-
- def sha256(s):
- raise _no_sha256
-
- SHA256_AVAILABLE = False
-
-try:
- from Crypto.Util.number import long_to_bytes, bytes_to_long
-except ImportError:
- import pickle
- try:
- # Check Python compatiblity by raising an exception on import
- # if the needed functionality is not present. Present in
- # Python >= 2.3
- pickle.encode_long
- pickle.decode_long
- except AttributeError:
- raise ImportError(
- 'No functionality for serializing long integers found')
-
- # Present in Python >= 2.4
- try:
- reversed
- except NameError:
- def reversed(seq):
- return map(seq.__getitem__, xrange(len(seq) - 1, -1, -1))
-
- def longToBinary(l):
- if l == 0:
- return '\x00'
-
- return ''.join(reversed(pickle.encode_long(l)))
-
- def binaryToLong(s):
- return pickle.decode_long(''.join(reversed(s)))
-else:
- # We have pycrypto
-
- def longToBinary(l):
- if l < 0:
- raise ValueError('This function only supports positive integers')
-
- bytes = long_to_bytes(l)
- if ord(bytes[0]) > 127:
- return '\x00' + bytes
- else:
- return bytes
-
- def binaryToLong(bytes):
- if not bytes:
- raise ValueError('Empty string passed to strToLong')
-
- if ord(bytes[0]) > 127:
- raise ValueError('This function only supports positive integers')
-
- return bytes_to_long(bytes)
-
-# A cryptographically safe source of random bytes
-try:
- getBytes = os.urandom
-except AttributeError:
- try:
- from Crypto.Util.randpool import RandomPool
- except ImportError:
- # Fall back on /dev/urandom, if present. It would be nice to
- # have Windows equivalent here, but for now, require pycrypto
- # on Windows.
- try:
- _urandom = file('/dev/urandom', 'rb')
- except IOError:
- raise ImportError('No adequate source of randomness found!')
- else:
- def getBytes(n):
- bytes = []
- while n:
- chunk = _urandom.read(n)
- n -= len(chunk)
- bytes.append(chunk)
- assert n >= 0
- return ''.join(bytes)
- else:
- _pool = RandomPool()
- def getBytes(n, pool=_pool):
- if pool.entropy < n:
- pool.randomize()
- return pool.get_bytes(n)
-
-# A randrange function that works for longs
-try:
- randrange = random.SystemRandom().randrange
-except AttributeError:
- # In Python 2.2's random.Random, randrange does not support
- # numbers larger than sys.maxint for randrange. For simplicity,
- # use this implementation for any Python that does not have
- # random.SystemRandom
- from math import log, ceil
-
- _duplicate_cache = {}
- def randrange(start, stop=None, step=1):
- if stop is None:
- stop = start
- start = 0
-
- r = (stop - start) // step
- try:
- (duplicate, nbytes) = _duplicate_cache[r]
- except KeyError:
- rbytes = longToBinary(r)
- if rbytes[0] == '\x00':
- nbytes = len(rbytes) - 1
- else:
- nbytes = len(rbytes)
-
- mxrand = (256 ** nbytes)
-
- # If we get a number less than this, then it is in the
- # duplicated range.
- duplicate = mxrand % r
-
- if len(_duplicate_cache) > 10:
- _duplicate_cache.clear()
-
- _duplicate_cache[r] = (duplicate, nbytes)
-
- while 1:
- bytes = '\x00' + getBytes(nbytes)
- n = binaryToLong(bytes)
- # Keep looping if this value is in the low duplicated range
- if n >= duplicate:
- break
-
- return start + (n % r) * step
-
-def longToBase64(l):
- return toBase64(longToBinary(l))
-
-def base64ToLong(s):
- return binaryToLong(fromBase64(s))
-
-def randomString(length, chrs=None):
- """Produce a string of length random bytes, chosen from chrs."""
- if chrs is None:
- return getBytes(length)
- else:
- n = len(chrs)
- return ''.join([chrs[randrange(n)] for _ in xrange(length)])
diff --git a/askbot/deps/openid/dh.py b/askbot/deps/openid/dh.py
deleted file mode 100644
index 7dbb758d..00000000
--- a/askbot/deps/openid/dh.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from askbot.deps.openid import cryptutil
-from askbot.deps.openid import oidutil
-
-def strxor(x, y):
- if len(x) != len(y):
- raise ValueError('Inputs to strxor must have the same length')
-
- xor = lambda (a, b): chr(ord(a) ^ ord(b))
- return "".join(map(xor, zip(x, y)))
-
-class DiffieHellman(object):
- DEFAULT_MOD = 155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443L
-
- DEFAULT_GEN = 2
-
- def fromDefaults(cls):
- return cls(cls.DEFAULT_MOD, cls.DEFAULT_GEN)
-
- fromDefaults = classmethod(fromDefaults)
-
- def __init__(self, modulus, generator):
- self.modulus = long(modulus)
- self.generator = long(generator)
-
- self._setPrivate(cryptutil.randrange(1, modulus - 1))
-
- def _setPrivate(self, private):
- """This is here to make testing easier"""
- self.private = private
- self.public = pow(self.generator, self.private, self.modulus)
-
- def usingDefaultValues(self):
- return (self.modulus == self.DEFAULT_MOD and
- self.generator == self.DEFAULT_GEN)
-
- def getSharedSecret(self, composite):
- return pow(composite, self.private, self.modulus)
-
- def xorSecret(self, composite, secret, hash_func):
- dh_shared = self.getSharedSecret(composite)
- hashed_dh_shared = hash_func(cryptutil.longToBinary(dh_shared))
- return strxor(secret, hashed_dh_shared)
diff --git a/askbot/deps/openid/extension.py b/askbot/deps/openid/extension.py
deleted file mode 100644
index d6ec0044..00000000
--- a/askbot/deps/openid/extension.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from askbot.deps.openid import message as message_module
-
-class Extension(object):
- """An interface for OpenID extensions.
-
- @ivar ns_uri: The namespace to which to add the arguments for this
- extension
- """
- ns_uri = None
- ns_alias = None
-
- def getExtensionArgs(self):
- """Get the string arguments that should be added to an OpenID
- message for this extension.
-
- @returns: A dictionary of completely non-namespaced arguments
- to be added. For example, if the extension's alias is
- 'uncle', and this method returns {'meat':'Hot Rats'}, the
- final message will contain {'openid.uncle.meat':'Hot Rats'}
- """
- raise NotImplementedError
-
- def toMessage(self, message=None):
- """Add the arguments from this extension to the provided
- message, or create a new message containing only those
- arguments.
-
- @returns: The message with the extension arguments added
- """
- if message is None:
- warnings.warn('Passing None to Extension.toMessage is deprecated. '
- 'Creating a message assuming you want OpenID 2.',
- DeprecationWarning, stacklevel=2)
- message = message_module.Message(message_module.OPENID2_NS)
-
- implicit = message.isOpenID1()
-
- try:
- message.namespaces.addAlias(self.ns_uri, self.ns_alias,
- implicit=implicit)
- except KeyError:
- if message.namespaces.getAlias(self.ns_uri) != self.ns_alias:
- raise
-
- message.updateArgs(self.ns_uri, self.getExtensionArgs())
- return message
diff --git a/askbot/deps/openid/extensions/__init__.py b/askbot/deps/openid/extensions/__init__.py
deleted file mode 100644
index e27aa75f..00000000
--- a/askbot/deps/openid/extensions/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""OpenID Extension modules."""
-
-__all__ = ['ax', 'pape', 'sreg']
-
-from askbot.deps.openid.extensions.draft import pape5 as pape
diff --git a/askbot/deps/openid/extensions/ax.py b/askbot/deps/openid/extensions/ax.py
deleted file mode 100644
index 9ba89b93..00000000
--- a/askbot/deps/openid/extensions/ax.py
+++ /dev/null
@@ -1,774 +0,0 @@
-# -*- test-case-name: openid.test.test_ax -*-
-"""Implements the OpenID Attribute Exchange specification, version 1.0.
-
-@since: 2.1.0
-"""
-
-__all__ = [
- 'AttributeRequest',
- 'FetchRequest',
- 'FetchResponse',
- 'StoreRequest',
- 'StoreResponse',
- ]
-
-from askbot.deps.openid import extension
-from askbot.deps.openid.server.trustroot import TrustRoot
-from askbot.deps.openid.message import NamespaceMap, OPENID_NS
-
-# Use this as the 'count' value for an attribute in a FetchRequest to
-# ask for as many values as the OP can provide.
-UNLIMITED_VALUES = "unlimited"
-
-# Minimum supported alias length in characters. Here for
-# completeness.
-MINIMUM_SUPPORTED_ALIAS_LENGTH = 32
-
-def checkAlias(alias):
- """
- Check an alias for invalid characters; raise AXError if any are
- found. Return None if the alias is valid.
- """
- if ',' in alias:
- raise AXError("Alias %r must not contain comma" % (alias,))
- if '.' in alias:
- raise AXError("Alias %r must not contain period" % (alias,))
-
-
-class AXError(ValueError):
- """Results from data that does not meet the attribute exchange 1.0
- specification"""
-
-
-class NotAXMessage(AXError):
- """Raised when there is no Attribute Exchange mode in the message."""
-
- def __repr__(self):
- return self.__class__.__name__
-
- def __str__(self):
- return self.__class__.__name__
-
-
-class AXMessage(extension.Extension):
- """Abstract class containing common code for attribute exchange messages
-
- @cvar ns_alias: The preferred namespace alias for attribute
- exchange messages
-
- @cvar mode: The type of this attribute exchange message. This must
- be overridden in subclasses.
- """
-
- # This class is abstract, so it's OK that it doesn't override the
- # abstract method in Extension:
- #
- #pylint:disable-msg=W0223
-
- ns_alias = 'ax'
- mode = None
- ns_uri = 'http://openid.net/srv/ax/1.0'
-
- def _checkMode(self, ax_args):
- """Raise an exception if the mode in the attribute exchange
- arguments does not match what is expected for this class.
-
- @raises NotAXMessage: When there is no mode value in ax_args at all.
-
- @raises AXError: When mode does not match.
- """
- mode = ax_args.get('mode')
- if mode != self.mode:
- if not mode:
- raise NotAXMessage()
- else:
- raise AXError(
- 'Expected mode %r; got %r' % (self.mode, mode))
-
- def _newArgs(self):
- """Return a set of attribute exchange arguments containing the
- basic information that must be in every attribute exchange
- message.
- """
- return {'mode':self.mode}
-
-
-class AttrInfo(object):
- """Represents a single attribute in an attribute exchange
- request. This should be added to an AXRequest object in order to
- request the attribute.
-
- @ivar required: Whether the attribute will be marked as required
- when presented to the subject of the attribute exchange
- request.
- @type required: bool
-
- @ivar count: How many values of this type to request from the
- subject. Defaults to one.
- @type count: int
-
- @ivar type_uri: The identifier that determines what the attribute
- represents and how it is serialized. For example, one type URI
- representing dates could represent a Unix timestamp in base 10
- and another could represent a human-readable string.
- @type type_uri: str
-
- @ivar alias: The name that should be given to this alias in the
- request. If it is not supplied, a generic name will be
- assigned. For example, if you want to call a Unix timestamp
- value 'tstamp', set its alias to that value. If two attributes
- in the same message request to use the same alias, the request
- will fail to be generated.
- @type alias: str or NoneType
- """
-
- # It's OK that this class doesn't have public methods (it's just a
- # holder for a bunch of attributes):
- #
- #pylint:disable-msg=R0903
-
- def __init__(self, type_uri, count=1, required=False, alias=None):
- self.required = required
- self.count = count
- self.type_uri = type_uri
- self.alias = alias
-
- if self.alias is not None:
- checkAlias(self.alias)
-
- def wantsUnlimitedValues(self):
- """
- When processing a request for this attribute, the OP should
- call this method to determine whether all available attribute
- values were requested. If self.count == UNLIMITED_VALUES,
- this returns True. Otherwise this returns False, in which
- case self.count is an integer.
- """
- return self.count == UNLIMITED_VALUES
-
-def toTypeURIs(namespace_map, alias_list_s):
- """Given a namespace mapping and a string containing a
- comma-separated list of namespace aliases, return a list of type
- URIs that correspond to those aliases.
-
- @param namespace_map: The mapping from namespace URI to alias
- @type namespace_map: openid.message.NamespaceMap
-
- @param alias_list_s: The string containing the comma-separated
- list of aliases. May also be None for convenience.
- @type alias_list_s: str or NoneType
-
- @returns: The list of namespace URIs that corresponds to the
- supplied list of aliases. If the string was zero-length or
- None, an empty list will be returned.
-
- @raise KeyError: If an alias is present in the list of aliases but
- is not present in the namespace map.
- """
- uris = []
-
- if alias_list_s:
- for alias in alias_list_s.split(','):
- type_uri = namespace_map.getNamespaceURI(alias)
- if type_uri is None:
- raise KeyError(
- 'No type is defined for attribute name %r' % (alias,))
- else:
- uris.append(type_uri)
-
- return uris
-
-
-class FetchRequest(AXMessage):
- """An attribute exchange 'fetch_request' message. This message is
- sent by a relying party when it wishes to obtain attributes about
- the subject of an OpenID authentication request.
-
- @ivar requested_attributes: The attributes that have been
- requested thus far, indexed by the type URI.
- @type requested_attributes: {str:AttrInfo}
-
- @ivar update_url: A URL that will accept responses for this
- attribute exchange request, even in the absence of the user
- who made this request.
- """
- mode = 'fetch_request'
-
- def __init__(self, update_url=None):
- AXMessage.__init__(self)
- self.requested_attributes = {}
- self.update_url = update_url
-
- def add(self, attribute):
- """Add an attribute to this attribute exchange request.
-
- @param attribute: The attribute that is being requested
- @type attribute: C{L{AttrInfo}}
-
- @returns: None
-
- @raise KeyError: when the requested attribute is already
- present in this fetch request.
- """
- if attribute.type_uri in self.requested_attributes:
- raise KeyError('The attribute %r has already been requested'
- % (attribute.type_uri,))
-
- self.requested_attributes[attribute.type_uri] = attribute
-
- def getExtensionArgs(self):
- """Get the serialized form of this attribute fetch request.
-
- @returns: The fetch request message parameters
- @rtype: {unicode:unicode}
- """
- aliases = NamespaceMap()
-
- required = []
- if_available = []
-
- ax_args = self._newArgs()
-
- for type_uri, attribute in self.requested_attributes.iteritems():
- if attribute.alias is None:
- alias = aliases.add(type_uri)
- else:
- # This will raise an exception when the second
- # attribute with the same alias is added. I think it
- # would be better to complain at the time that the
- # attribute is added to this object so that the code
- # that is adding it is identified in the stack trace,
- # but it's more work to do so, and it won't be 100%
- # accurate anyway, since the attributes are
- # mutable. So for now, just live with the fact that
- # we'll learn about the error later.
- #
- # The other possible approach is to hide the error and
- # generate a new alias on the fly. I think that would
- # probably be bad.
- alias = aliases.addAlias(type_uri, attribute.alias)
-
- if attribute.required:
- required.append(alias)
- else:
- if_available.append(alias)
-
- if attribute.count != 1:
- ax_args['count.' + alias] = str(attribute.count)
-
- ax_args['type.' + alias] = type_uri
-
- if required:
- ax_args['required'] = ','.join(required)
-
- if if_available:
- ax_args['if_available'] = ','.join(if_available)
-
- return ax_args
-
- def getRequiredAttrs(self):
- """Get the type URIs for all attributes that have been marked
- as required.
-
- @returns: A list of the type URIs for attributes that have
- been marked as required.
- @rtype: [str]
- """
- required = []
- for type_uri, attribute in self.requested_attributes.iteritems():
- if attribute.required:
- required.append(type_uri)
-
- return required
-
- def fromOpenIDRequest(cls, openid_request):
- """Extract a FetchRequest from an OpenID message
-
- @param openid_request: The OpenID authentication request
- containing the attribute fetch request
- @type openid_request: C{L{openid.server.server.CheckIDRequest}}
-
- @rtype: C{L{FetchRequest}} or C{None}
- @returns: The FetchRequest extracted from the message or None, if
- the message contained no AX extension.
-
- @raises KeyError: if the AuthRequest is not consistent in its use
- of namespace aliases.
-
- @raises AXError: When parseExtensionArgs would raise same.
-
- @see: L{parseExtensionArgs}
- """
- message = openid_request.message
- ax_args = message.getArgs(cls.ns_uri)
- self = cls()
- try:
- self.parseExtensionArgs(ax_args)
- except NotAXMessage, err:
- return None
-
- if self.update_url:
- # Update URL must match the openid.realm of the underlying
- # OpenID 2 message.
- realm = message.getArg(OPENID_NS, 'realm',
- message.getArg(OPENID_NS, 'return_to'))
-
- if not realm:
- raise AXError(("Cannot validate update_url %r " +
- "against absent realm") % (self.update_url,))
-
- tr = TrustRoot.parse(realm)
- if not tr.validateURL(self.update_url):
- raise AXError("Update URL %r failed validation against realm %r" %
- (self.update_url, realm,))
-
- return self
-
- fromOpenIDRequest = classmethod(fromOpenIDRequest)
-
- def parseExtensionArgs(self, ax_args):
- """Given attribute exchange arguments, populate this FetchRequest.
-
- @param ax_args: Attribute Exchange arguments from the request.
- As returned from L{Message.getArgs<openid.message.Message.getArgs>}.
- @type ax_args: dict
-
- @raises KeyError: if the message is not consistent in its use
- of namespace aliases.
-
- @raises NotAXMessage: If ax_args does not include an Attribute Exchange
- mode.
-
- @raises AXError: If the data to be parsed does not follow the
- attribute exchange specification. At least when
- 'if_available' or 'required' is not specified for a
- particular attribute type.
- """
- # Raises an exception if the mode is not the expected value
- self._checkMode(ax_args)
-
- aliases = NamespaceMap()
-
- for key, value in ax_args.iteritems():
- if key.startswith('type.'):
- alias = key[5:]
- type_uri = value
- aliases.addAlias(type_uri, alias)
-
- count_key = 'count.' + alias
- count_s = ax_args.get(count_key)
- if count_s:
- try:
- count = int(count_s)
- if count <= 0:
- raise AXError("Count %r must be greater than zero, got %r" % (count_key, count_s,))
- except ValueError:
- if count_s != UNLIMITED_VALUES:
- raise AXError("Invalid count value for %r: %r" % (count_key, count_s,))
- count = count_s
- else:
- count = 1
-
- self.add(AttrInfo(type_uri, alias=alias, count=count))
-
- required = toTypeURIs(aliases, ax_args.get('required'))
-
- for type_uri in required:
- self.requested_attributes[type_uri].required = True
-
- if_available = toTypeURIs(aliases, ax_args.get('if_available'))
-
- all_type_uris = required + if_available
-
- for type_uri in aliases.iterNamespaceURIs():
- if type_uri not in all_type_uris:
- raise AXError(
- 'Type URI %r was in the request but not '
- 'present in "required" or "if_available"' % (type_uri,))
-
- self.update_url = ax_args.get('update_url')
-
- def iterAttrs(self):
- """Iterate over the AttrInfo objects that are
- contained in this fetch_request.
- """
- return self.requested_attributes.itervalues()
-
- def __iter__(self):
- """Iterate over the attribute type URIs in this fetch_request
- """
- return iter(self.requested_attributes)
-
- def has_key(self, type_uri):
- """Is the given type URI present in this fetch_request?
- """
- return type_uri in self.requested_attributes
-
- __contains__ = has_key
-
-
-class AXKeyValueMessage(AXMessage):
- """An abstract class that implements a message that has attribute
- keys and values. It contains the common code between
- fetch_response and store_request.
- """
-
- # This class is abstract, so it's OK that it doesn't override the
- # abstract method in Extension:
- #
- #pylint:disable-msg=W0223
-
- def __init__(self):
- AXMessage.__init__(self)
- self.data = {}
-
- def addValue(self, type_uri, value):
- """Add a single value for the given attribute type to the
- message. If there are already values specified for this type,
- this value will be sent in addition to the values already
- specified.
-
- @param type_uri: The URI for the attribute
-
- @param value: The value to add to the response to the relying
- party for this attribute
- @type value: unicode
-
- @returns: None
- """
- try:
- values = self.data[type_uri]
- except KeyError:
- values = self.data[type_uri] = []
-
- values.append(value)
-
- def setValues(self, type_uri, values):
- """Set the values for the given attribute type. This replaces
- any values that have already been set for this attribute.
-
- @param type_uri: The URI for the attribute
-
- @param values: A list of values to send for this attribute.
- @type values: [unicode]
- """
-
- self.data[type_uri] = values
-
- def _getExtensionKVArgs(self, aliases=None):
- """Get the extension arguments for the key/value pairs
- contained in this message.
-
- @param aliases: An alias mapping. Set to None if you don't
- care about the aliases for this request.
- """
- if aliases is None:
- aliases = NamespaceMap()
-
- ax_args = {}
-
- for type_uri, values in self.data.iteritems():
- alias = aliases.add(type_uri)
-
- ax_args['type.' + alias] = type_uri
- ax_args['count.' + alias] = str(len(values))
-
- for i, value in enumerate(values):
- key = 'value.%s.%d' % (alias, i + 1)
- ax_args[key] = value
-
- return ax_args
-
- def parseExtensionArgs(self, ax_args):
- """Parse attribute exchange key/value arguments into this
- object.
-
- @param ax_args: The attribute exchange fetch_response
- arguments, with namespacing removed.
- @type ax_args: {unicode:unicode}
-
- @returns: None
-
- @raises ValueError: If the message has bad values for
- particular fields
-
- @raises KeyError: If the namespace mapping is bad or required
- arguments are missing
- """
- self._checkMode(ax_args)
-
- aliases = NamespaceMap()
-
- for key, value in ax_args.iteritems():
- if key.startswith('type.'):
- type_uri = value
- alias = key[5:]
- checkAlias(alias)
- aliases.addAlias(type_uri, alias)
-
- for type_uri, alias in aliases.iteritems():
- try:
- count_s = ax_args['count.' + alias]
- except KeyError:
- value = ax_args['value.' + alias]
-
- if value == u'':
- values = []
- else:
- values = [value]
- else:
- count = int(count_s)
- values = []
- for i in range(1, count + 1):
- value_key = 'value.%s.%d' % (alias, i)
- value = ax_args[value_key]
- values.append(value)
-
- self.data[type_uri] = values
-
- def getSingle(self, type_uri, default=None):
- """Get a single value for an attribute. If no value was sent
- for this attribute, use the supplied default. If there is more
- than one value for this attribute, this method will fail.
-
- @type type_uri: str
- @param type_uri: The URI for the attribute
-
- @param default: The value to return if the attribute was not
- sent in the fetch_response.
-
- @returns: The value of the attribute in the fetch_response
- message, or the default supplied
- @rtype: unicode or NoneType
-
- @raises ValueError: If there is more than one value for this
- parameter in the fetch_response message.
- @raises KeyError: If the attribute was not sent in this response
- """
- values = self.data.get(type_uri)
- if not values:
- return default
- elif len(values) == 1:
- return values[0]
- else:
- raise AXError(
- 'More than one value present for %r' % (type_uri,))
-
- def get(self, type_uri):
- """Get the list of values for this attribute in the
- fetch_response.
-
- XXX: what to do if the values are not present? default
- parameter? this is funny because it's always supposed to
- return a list, so the default may break that, though it's
- provided by the user's code, so it might be okay. If no
- default is supplied, should the return be None or []?
-
- @param type_uri: The URI of the attribute
-
- @returns: The list of values for this attribute in the
- response. May be an empty list.
- @rtype: [unicode]
-
- @raises KeyError: If the attribute was not sent in the response
- """
- return self.data[type_uri]
-
- def count(self, type_uri):
- """Get the number of responses for a particular attribute in
- this fetch_response message.
-
- @param type_uri: The URI of the attribute
-
- @returns: The number of values sent for this attribute
-
- @raises KeyError: If the attribute was not sent in the
- response. KeyError will not be raised if the number of
- values was zero.
- """
- return len(self.get(type_uri))
-
-
-class FetchResponse(AXKeyValueMessage):
- """A fetch_response attribute exchange message
- """
- mode = 'fetch_response'
-
- def __init__(self, request=None, update_url=None):
- """
- @param request: When supplied, I will use namespace aliases
- that match those in this request. I will also check to
- make sure I do not respond with attributes that were not
- requested.
-
- @type request: L{FetchRequest}
-
- @param update_url: By default, C{update_url} is taken from the
- request. But if you do not supply the request, you may set
- the C{update_url} here.
-
- @type update_url: str
- """
- AXKeyValueMessage.__init__(self)
- self.update_url = update_url
- self.request = request
-
- def getExtensionArgs(self):
- """Serialize this object into arguments in the attribute
- exchange namespace
-
- @returns: The dictionary of unqualified attribute exchange
- arguments that represent this fetch_response.
- @rtype: {unicode;unicode}
- """
-
- aliases = NamespaceMap()
-
- zero_value_types = []
-
- if self.request is not None:
- # Validate the data in the context of the request (the
- # same attributes should be present in each, and the
- # counts in the response must be no more than the counts
- # in the request)
-
- for type_uri in self.data:
- if type_uri not in self.request:
- raise KeyError(
- 'Response attribute not present in request: %r'
- % (type_uri,))
-
- for attr_info in self.request.iterAttrs():
- # Copy the aliases from the request so that reading
- # the response in light of the request is easier
- if attr_info.alias is None:
- aliases.add(attr_info.type_uri)
- else:
- aliases.addAlias(attr_info.type_uri, attr_info.alias)
-
- try:
- values = self.data[attr_info.type_uri]
- except KeyError:
- values = []
- zero_value_types.append(attr_info)
-
- if (attr_info.count != UNLIMITED_VALUES) and \
- (attr_info.count < len(values)):
- raise AXError(
- 'More than the number of requested values were '
- 'specified for %r' % (attr_info.type_uri,))
-
- kv_args = self._getExtensionKVArgs(aliases)
-
- # Add the KV args into the response with the args that are
- # unique to the fetch_response
- ax_args = self._newArgs()
-
- # For each requested attribute, put its type/alias and count
- # into the response even if no data were returned.
- for attr_info in zero_value_types:
- alias = aliases.getAlias(attr_info.type_uri)
- kv_args['type.' + alias] = attr_info.type_uri
- kv_args['count.' + alias] = '0'
-
- update_url = ((self.request and self.request.update_url)
- or self.update_url)
-
- if update_url:
- ax_args['update_url'] = update_url
-
- ax_args.update(kv_args)
-
- return ax_args
-
- def parseExtensionArgs(self, ax_args):
- """@see: {Extension.parseExtensionArgs<openid.extension.Extension.parseExtensionArgs>}"""
- super(FetchResponse, self).parseExtensionArgs(ax_args)
- self.update_url = ax_args.get('update_url')
-
- def fromSuccessResponse(cls, success_response, signed=True):
- """Construct a FetchResponse object from an OpenID library
- SuccessResponse object.
-
- @param success_response: A successful id_res response object
- @type success_response: openid.consumer.consumer.SuccessResponse
-
- @param signed: Whether non-signed args should be
- processsed. If True (the default), only signed arguments
- will be processsed.
- @type signed: bool
-
- @returns: A FetchResponse containing the data from the OpenID
- message, or None if the SuccessResponse did not contain AX
- extension data.
-
- @raises AXError: when the AX data cannot be parsed.
- """
- self = cls()
- ax_args = success_response.extensionResponse(self.ns_uri, signed)
-
- try:
- self.parseExtensionArgs(ax_args)
- except NotAXMessage, err:
- return None
- else:
- return self
-
- fromSuccessResponse = classmethod(fromSuccessResponse)
-
-
-class StoreRequest(AXKeyValueMessage):
- """A store request attribute exchange message representation
- """
- mode = 'store_request'
-
- def __init__(self, aliases=None):
- """
- @param aliases: The namespace aliases to use when making this
- store request. Leave as None to use defaults.
- """
- super(StoreRequest, self).__init__()
- self.aliases = aliases
-
- def getExtensionArgs(self):
- """
- @see: L{Extension.getExtensionArgs<openid.extension.Extension.getExtensionArgs>}
- """
- ax_args = self._newArgs()
- kv_args = self._getExtensionKVArgs(self.aliases)
- ax_args.update(kv_args)
- return ax_args
-
-
-class StoreResponse(AXMessage):
- """An indication that the store request was processed along with
- this OpenID transaction.
- """
-
- SUCCESS_MODE = 'store_response_success'
- FAILURE_MODE = 'store_response_failure'
-
- def __init__(self, succeeded=True, error_message=None):
- AXMessage.__init__(self)
-
- if succeeded and error_message is not None:
- raise AXError('An error message may only be included in a '
- 'failing fetch response')
- if succeeded:
- self.mode = self.SUCCESS_MODE
- else:
- self.mode = self.FAILURE_MODE
-
- self.error_message = error_message
-
- def succeeded(self):
- """Was this response a success response?"""
- return self.mode == self.SUCCESS_MODE
-
- def getExtensionArgs(self):
- """@see: {Extension.getExtensionArgs<openid.extension.Extension.getExtensionArgs>}"""
- ax_args = self._newArgs()
- if not self.succeeded() and self.error_message:
- ax_args['error'] = self.error_message
-
- return ax_args
diff --git a/askbot/deps/openid/extensions/draft/__init__.py b/askbot/deps/openid/extensions/draft/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/askbot/deps/openid/extensions/draft/__init__.py
+++ /dev/null
diff --git a/askbot/deps/openid/extensions/draft/pape2.py b/askbot/deps/openid/extensions/draft/pape2.py
deleted file mode 100644
index 13e4acd2..00000000
--- a/askbot/deps/openid/extensions/draft/pape2.py
+++ /dev/null
@@ -1,277 +0,0 @@
-"""An implementation of the OpenID Provider Authentication Policy
-Extension 1.0
-
-@see: http://openid.net/developers/specs/
-
-@since: 2.1.0
-"""
-
-__all__ = [
- 'Request',
- 'Response',
- 'ns_uri',
- 'AUTH_PHISHING_RESISTANT',
- 'AUTH_MULTI_FACTOR',
- 'AUTH_MULTI_FACTOR_PHYSICAL',
- ]
-
-from askbot.deps.openid.extension import Extension
-import re
-
-ns_uri = "http://specs.openid.net/extensions/pape/1.0"
-
-AUTH_MULTI_FACTOR_PHYSICAL = \
- 'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical'
-AUTH_MULTI_FACTOR = \
- 'http://schemas.openid.net/pape/policies/2007/06/multi-factor'
-AUTH_PHISHING_RESISTANT = \
- 'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant'
-
-TIME_VALIDATOR = re.compile('^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$')
-
-class Request(Extension):
- """A Provider Authentication Policy request, sent from a relying
- party to a provider
-
- @ivar preferred_auth_policies: The authentication policies that
- the relying party prefers
- @type preferred_auth_policies: [str]
-
- @ivar max_auth_age: The maximum time, in seconds, that the relying
- party wants to allow to have elapsed before the user must
- re-authenticate
- @type max_auth_age: int or NoneType
- """
-
- ns_alias = 'pape'
-
- def __init__(self, preferred_auth_policies=None, max_auth_age=None):
- super(Request, self).__init__()
- if not preferred_auth_policies:
- preferred_auth_policies = []
-
- self.preferred_auth_policies = preferred_auth_policies
- self.max_auth_age = max_auth_age
-
- def __nonzero__(self):
- return bool(self.preferred_auth_policies or
- self.max_auth_age is not None)
-
- def addPolicyURI(self, policy_uri):
- """Add an acceptable authentication policy URI to this request
-
- This method is intended to be used by the relying party to add
- acceptable authentication types to the request.
-
- @param policy_uri: The identifier for the preferred type of
- authentication.
- @see: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#auth_policies
- """
- if policy_uri not in self.preferred_auth_policies:
- self.preferred_auth_policies.append(policy_uri)
-
- def getExtensionArgs(self):
- """@see: C{L{Extension.getExtensionArgs}}
- """
- ns_args = {
- 'preferred_auth_policies':' '.join(self.preferred_auth_policies)
- }
-
- if self.max_auth_age is not None:
- ns_args['max_auth_age'] = str(self.max_auth_age)
-
- return ns_args
-
- def fromOpenIDRequest(cls, request):
- """Instantiate a Request object from the arguments in a
- C{checkid_*} OpenID message
- """
- self = cls()
- args = request.message.getArgs(self.ns_uri)
-
- if args == {}:
- return None
-
- self.parseExtensionArgs(args)
- return self
-
- fromOpenIDRequest = classmethod(fromOpenIDRequest)
-
- def parseExtensionArgs(self, args):
- """Set the state of this request to be that expressed in these
- PAPE arguments
-
- @param args: The PAPE arguments without a namespace
-
- @rtype: None
-
- @raises ValueError: When the max_auth_age is not parseable as
- an integer
- """
-
- # preferred_auth_policies is a space-separated list of policy URIs
- self.preferred_auth_policies = []
-
- policies_str = args.get('preferred_auth_policies')
- if policies_str:
- for uri in policies_str.split(' '):
- if uri not in self.preferred_auth_policies:
- self.preferred_auth_policies.append(uri)
-
- # max_auth_age is base-10 integer number of seconds
- max_auth_age_str = args.get('max_auth_age')
- self.max_auth_age = None
-
- if max_auth_age_str:
- try:
- self.max_auth_age = int(max_auth_age_str)
- except ValueError:
- pass
-
- def preferredTypes(self, supported_types):
- """Given a list of authentication policy URIs that a provider
- supports, this method returns the subsequence of those types
- that are preferred by the relying party.
-
- @param supported_types: A sequence of authentication policy
- type URIs that are supported by a provider
-
- @returns: The sub-sequence of the supported types that are
- preferred by the relying party. This list will be ordered
- in the order that the types appear in the supported_types
- sequence, and may be empty if the provider does not prefer
- any of the supported authentication types.
-
- @returntype: [str]
- """
- return filter(self.preferred_auth_policies.__contains__,
- supported_types)
-
-Request.ns_uri = ns_uri
-
-
-class Response(Extension):
- """A Provider Authentication Policy response, sent from a provider
- to a relying party
- """
-
- ns_alias = 'pape'
-
- def __init__(self, auth_policies=None, auth_time=None,
- nist_auth_level=None):
- super(Response, self).__init__()
- if auth_policies:
- self.auth_policies = auth_policies
- else:
- self.auth_policies = []
-
- self.auth_time = auth_time
- self.nist_auth_level = nist_auth_level
-
- def addPolicyURI(self, policy_uri):
- """Add a authentication policy to this response
-
- This method is intended to be used by the provider to add a
- policy that the provider conformed to when authenticating the user.
-
- @param policy_uri: The identifier for the preferred type of
- authentication.
- @see: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#auth_policies
- """
- if policy_uri not in self.auth_policies:
- self.auth_policies.append(policy_uri)
-
- def fromSuccessResponse(cls, success_response):
- """Create a C{L{Response}} object from a successful OpenID
- library response
- (C{L{openid.consumer.consumer.SuccessResponse}}) response
- message
-
- @param success_response: A SuccessResponse from consumer.complete()
- @type success_response: C{L{openid.consumer.consumer.SuccessResponse}}
-
- @rtype: Response or None
- @returns: A provider authentication policy response from the
- data that was supplied with the C{id_res} response or None
- if the provider sent no signed PAPE response arguments.
- """
- self = cls()
-
- # PAPE requires that the args be signed.
- args = success_response.getSignedNS(self.ns_uri)
-
- # Only try to construct a PAPE response if the arguments were
- # signed in the OpenID response. If not, return None.
- if args is not None:
- self.parseExtensionArgs(args)
- return self
- else:
- return None
-
- def parseExtensionArgs(self, args, strict=False):
- """Parse the provider authentication policy arguments into the
- internal state of this object
-
- @param args: unqualified provider authentication policy
- arguments
-
- @param strict: Whether to raise an exception when bad data is
- encountered
-
- @returns: None. The data is parsed into the internal fields of
- this object.
- """
- policies_str = args.get('auth_policies')
- if policies_str and policies_str != 'none':
- self.auth_policies = policies_str.split(' ')
-
- nist_level_str = args.get('nist_auth_level')
- if nist_level_str:
- try:
- nist_level = int(nist_level_str)
- except ValueError:
- if strict:
- raise ValueError('nist_auth_level must be an integer between '
- 'zero and four, inclusive')
- else:
- self.nist_auth_level = None
- else:
- if 0 <= nist_level < 5:
- self.nist_auth_level = nist_level
-
- auth_time = args.get('auth_time')
- if auth_time:
- if TIME_VALIDATOR.match(auth_time):
- self.auth_time = auth_time
- elif strict:
- raise ValueError("auth_time must be in RFC3339 format")
-
- fromSuccessResponse = classmethod(fromSuccessResponse)
-
- def getExtensionArgs(self):
- """@see: C{L{Extension.getExtensionArgs}}
- """
- if len(self.auth_policies) == 0:
- ns_args = {
- 'auth_policies':'none',
- }
- else:
- ns_args = {
- 'auth_policies':' '.join(self.auth_policies),
- }
-
- if self.nist_auth_level is not None:
- if self.nist_auth_level not in range(0, 5):
- raise ValueError('nist_auth_level must be an integer between '
- 'zero and four, inclusive')
- ns_args['nist_auth_level'] = str(self.nist_auth_level)
-
- if self.auth_time is not None:
- if not TIME_VALIDATOR.match(self.auth_time):
- raise ValueError('auth_time must be in RFC3339 format')
-
- ns_args['auth_time'] = self.auth_time
-
- return ns_args
-
-Response.ns_uri = ns_uri
diff --git a/askbot/deps/openid/extensions/draft/pape5.py b/askbot/deps/openid/extensions/draft/pape5.py
deleted file mode 100644
index 4ec6f3ab..00000000
--- a/askbot/deps/openid/extensions/draft/pape5.py
+++ /dev/null
@@ -1,473 +0,0 @@
-"""An implementation of the OpenID Provider Authentication Policy
-Extension 1.0, Draft 5
-
-@see: http://openid.net/developers/specs/
-
-@since: 2.1.0
-"""
-
-__all__ = [
- 'Request',
- 'Response',
- 'ns_uri',
- 'AUTH_PHISHING_RESISTANT',
- 'AUTH_MULTI_FACTOR',
- 'AUTH_MULTI_FACTOR_PHYSICAL',
- 'LEVELS_NIST',
- 'LEVELS_JISA',
- ]
-
-from askbot.deps.openid.extension import Extension
-import warnings
-import re
-
-ns_uri = "http://specs.openid.net/extensions/pape/1.0"
-
-AUTH_MULTI_FACTOR_PHYSICAL = \
- 'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical'
-AUTH_MULTI_FACTOR = \
- 'http://schemas.openid.net/pape/policies/2007/06/multi-factor'
-AUTH_PHISHING_RESISTANT = \
- 'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant'
-AUTH_NONE = \
- 'http://schemas.openid.net/pape/policies/2007/06/none'
-
-TIME_VALIDATOR = re.compile('^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$')
-
-LEVELS_NIST = 'http://csrc.nist.gov/publications/nistpubs/800-63/SP800-63V1_0_2.pdf'
-LEVELS_JISA = 'http://www.jisa.or.jp/spec/auth_level.html'
-
-class PAPEExtension(Extension):
- _default_auth_level_aliases = {
- 'nist': LEVELS_NIST,
- 'jisa': LEVELS_JISA,
- }
-
- def __init__(self):
- self.auth_level_aliases = self._default_auth_level_aliases.copy()
-
- def _addAuthLevelAlias(self, auth_level_uri, alias=None):
- """Add an auth level URI alias to this request.
-
- @param auth_level_uri: The auth level URI to send in the
- request.
-
- @param alias: The namespace alias to use for this auth level
- in this message. May be None if the alias is not
- important.
- """
- if alias is None:
- try:
- alias = self._getAlias(auth_level_uri)
- except KeyError:
- alias = self._generateAlias()
- else:
- existing_uri = self.auth_level_aliases.get(alias)
- if existing_uri is not None and existing_uri != auth_level_uri:
- raise KeyError('Attempting to redefine alias %r from %r to %r',
- alias, existing_uri, auth_level_uri)
-
- self.auth_level_aliases[alias] = auth_level_uri
-
- def _generateAlias(self):
- """Return an unused auth level alias"""
- for i in xrange(1000):
- alias = 'cust%d' % (i,)
- if alias not in self.auth_level_aliases:
- return alias
-
- raise RuntimeError('Could not find an unused alias (tried 1000!)')
-
- def _getAlias(self, auth_level_uri):
- """Return the alias for the specified auth level URI.
-
- @raises KeyError: if no alias is defined
- """
- for (alias, existing_uri) in self.auth_level_aliases.iteritems():
- if auth_level_uri == existing_uri:
- return alias
-
- raise KeyError(auth_level_uri)
-
-class Request(PAPEExtension):
- """A Provider Authentication Policy request, sent from a relying
- party to a provider
-
- @ivar preferred_auth_policies: The authentication policies that
- the relying party prefers
- @type preferred_auth_policies: [str]
-
- @ivar max_auth_age: The maximum time, in seconds, that the relying
- party wants to allow to have elapsed before the user must
- re-authenticate
- @type max_auth_age: int or NoneType
-
- @ivar preferred_auth_level_types: Ordered list of authentication
- level namespace URIs
-
- @type preferred_auth_level_types: [str]
- """
-
- ns_alias = 'pape'
-
- def __init__(self, preferred_auth_policies=None, max_auth_age=None,
- preferred_auth_level_types=None):
- super(Request, self).__init__()
- if preferred_auth_policies is None:
- preferred_auth_policies = []
-
- self.preferred_auth_policies = preferred_auth_policies
- self.max_auth_age = max_auth_age
- self.preferred_auth_level_types = []
-
- if preferred_auth_level_types is not None:
- for auth_level in preferred_auth_level_types:
- self.addAuthLevel(auth_level)
-
- def __nonzero__(self):
- return bool(self.preferred_auth_policies or
- self.max_auth_age is not None or
- self.preferred_auth_level_types)
-
- def addPolicyURI(self, policy_uri):
- """Add an acceptable authentication policy URI to this request
-
- This method is intended to be used by the relying party to add
- acceptable authentication types to the request.
-
- @param policy_uri: The identifier for the preferred type of
- authentication.
- @see: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-05.html#auth_policies
- """
- if policy_uri not in self.preferred_auth_policies:
- self.preferred_auth_policies.append(policy_uri)
-
- def addAuthLevel(self, auth_level_uri, alias=None):
- self._addAuthLevelAlias(auth_level_uri, alias)
- if auth_level_uri not in self.preferred_auth_level_types:
- self.preferred_auth_level_types.append(auth_level_uri)
-
- def getExtensionArgs(self):
- """@see: C{L{Extension.getExtensionArgs}}
- """
- ns_args = {
- 'preferred_auth_policies':' '.join(self.preferred_auth_policies),
- }
-
- if self.max_auth_age is not None:
- ns_args['max_auth_age'] = str(self.max_auth_age)
-
- if self.preferred_auth_level_types:
- preferred_types = []
-
- for auth_level_uri in self.preferred_auth_level_types:
- alias = self._getAlias(auth_level_uri)
- ns_args['auth_level.ns.%s' % (alias,)] = auth_level_uri
- preferred_types.append(alias)
-
- ns_args['preferred_auth_level_types'] = ' '.join(preferred_types)
-
- return ns_args
-
- def fromOpenIDRequest(cls, request):
- """Instantiate a Request object from the arguments in a
- C{checkid_*} OpenID message
- """
- self = cls()
- args = request.message.getArgs(self.ns_uri)
- is_openid1 = request.message.isOpenID1()
-
- if args == {}:
- return None
-
- self.parseExtensionArgs(args, is_openid1)
- return self
-
- fromOpenIDRequest = classmethod(fromOpenIDRequest)
-
- def parseExtensionArgs(self, args, is_openid1, strict=False):
- """Set the state of this request to be that expressed in these
- PAPE arguments
-
- @param args: The PAPE arguments without a namespace
-
- @param strict: Whether to raise an exception if the input is
- out of spec or otherwise malformed. If strict is false,
- malformed input will be ignored.
-
- @param is_openid1: Whether the input should be treated as part
- of an OpenID1 request
-
- @rtype: None
-
- @raises ValueError: When the max_auth_age is not parseable as
- an integer
- """
-
- # preferred_auth_policies is a space-separated list of policy URIs
- self.preferred_auth_policies = []
-
- policies_str = args.get('preferred_auth_policies')
- if policies_str:
- for uri in policies_str.split(' '):
- if uri not in self.preferred_auth_policies:
- self.preferred_auth_policies.append(uri)
-
- # max_auth_age is base-10 integer number of seconds
- max_auth_age_str = args.get('max_auth_age')
- self.max_auth_age = None
-
- if max_auth_age_str:
- try:
- self.max_auth_age = int(max_auth_age_str)
- except ValueError:
- if strict:
- raise
-
- # Parse auth level information
- preferred_auth_level_types = args.get('preferred_auth_level_types')
- if preferred_auth_level_types:
- aliases = preferred_auth_level_types.strip().split()
-
- for alias in aliases:
- key = 'auth_level.ns.%s' % (alias,)
- try:
- uri = args[key]
- except KeyError:
- if is_openid1:
- uri = self._default_auth_level_aliases.get(alias)
- else:
- uri = None
-
- if uri is None:
- if strict:
- raise ValueError('preferred auth level %r is not '
- 'defined in this message' % (alias,))
- else:
- self.addAuthLevel(uri, alias)
-
- def preferredTypes(self, supported_types):
- """Given a list of authentication policy URIs that a provider
- supports, this method returns the subsequence of those types
- that are preferred by the relying party.
-
- @param supported_types: A sequence of authentication policy
- type URIs that are supported by a provider
-
- @returns: The sub-sequence of the supported types that are
- preferred by the relying party. This list will be ordered
- in the order that the types appear in the supported_types
- sequence, and may be empty if the provider does not prefer
- any of the supported authentication types.
-
- @returntype: [str]
- """
- return filter(self.preferred_auth_policies.__contains__,
- supported_types)
-
-Request.ns_uri = ns_uri
-
-
-class Response(PAPEExtension):
- """A Provider Authentication Policy response, sent from a provider
- to a relying party
-
- @ivar auth_policies: List of authentication policies conformed to
- by this OpenID assertion, represented as policy URIs
- """
-
- ns_alias = 'pape'
-
- def __init__(self, auth_policies=None, auth_time=None,
- auth_levels=None):
- super(Response, self).__init__()
- if auth_policies:
- self.auth_policies = auth_policies
- else:
- self.auth_policies = []
-
- self.auth_time = auth_time
- self.auth_levels = {}
-
- if auth_levels is None:
- auth_levels = {}
-
- for uri, level in auth_levels.iteritems():
- self.setAuthLevel(uri, level)
-
- def setAuthLevel(self, level_uri, level, alias=None):
- """Set the value for the given auth level type.
-
- @param level: string representation of an authentication level
- valid for level_uri
-
- @param alias: An optional namespace alias for the given auth
- level URI. May be omitted if the alias is not
- significant. The library will use a reasonable default for
- widely-used auth level types.
- """
- self._addAuthLevelAlias(level_uri, alias)
- self.auth_levels[level_uri] = level
-
- def getAuthLevel(self, level_uri):
- """Return the auth level for the specified auth level
- identifier
-
- @returns: A string that should map to the auth levels defined
- for the auth level type
-
- @raises KeyError: If the auth level type is not present in
- this message
- """
- return self.auth_levels[level_uri]
-
- def _getNISTAuthLevel(self):
- try:
- return int(self.getAuthLevel(LEVELS_NIST))
- except KeyError:
- return None
-
- nist_auth_level = property(
- _getNISTAuthLevel,
- doc="Backward-compatibility accessor for the NIST auth level")
-
- def addPolicyURI(self, policy_uri):
- """Add a authentication policy to this response
-
- This method is intended to be used by the provider to add a
- policy that the provider conformed to when authenticating the user.
-
- @param policy_uri: The identifier for the preferred type of
- authentication.
- @see: http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#auth_policies
- """
- if policy_uri == AUTH_NONE:
- raise RuntimeError(
- 'To send no policies, do not set any on the response.')
-
- if policy_uri not in self.auth_policies:
- self.auth_policies.append(policy_uri)
-
- def fromSuccessResponse(cls, success_response):
- """Create a C{L{Response}} object from a successful OpenID
- library response
- (C{L{openid.consumer.consumer.SuccessResponse}}) response
- message
-
- @param success_response: A SuccessResponse from consumer.complete()
- @type success_response: C{L{openid.consumer.consumer.SuccessResponse}}
-
- @rtype: Response or None
- @returns: A provider authentication policy response from the
- data that was supplied with the C{id_res} response or None
- if the provider sent no signed PAPE response arguments.
- """
- self = cls()
-
- # PAPE requires that the args be signed.
- args = success_response.getSignedNS(self.ns_uri)
- is_openid1 = success_response.isOpenID1()
-
- # Only try to construct a PAPE response if the arguments were
- # signed in the OpenID response. If not, return None.
- if args is not None:
- self.parseExtensionArgs(args, is_openid1)
- return self
- else:
- return None
-
- def parseExtensionArgs(self, args, is_openid1, strict=False):
- """Parse the provider authentication policy arguments into the
- internal state of this object
-
- @param args: unqualified provider authentication policy
- arguments
-
- @param strict: Whether to raise an exception when bad data is
- encountered
-
- @returns: None. The data is parsed into the internal fields of
- this object.
- """
- policies_str = args.get('auth_policies')
- if policies_str:
- auth_policies = policies_str.split(' ')
- elif strict:
- raise ValueError('Missing auth_policies')
- else:
- auth_policies = []
-
- if (len(auth_policies) > 1 and strict and AUTH_NONE in auth_policies):
- raise ValueError('Got some auth policies, as well as the special '
- '"none" URI: %r' % (auth_policies,))
-
- if 'none' in auth_policies:
- msg = '"none" used as a policy URI (see PAPE draft < 5)'
- if strict:
- raise ValueError(msg)
- else:
- warnings.warn(msg, stacklevel=2)
-
- auth_policies = [u for u in auth_policies
- if u not in ['none', AUTH_NONE]]
-
- self.auth_policies = auth_policies
-
- for (key, val) in args.iteritems():
- if key.startswith('auth_level.'):
- alias = key[11:]
-
- # skip the already-processed namespace declarations
- if alias.startswith('ns.'):
- continue
-
- try:
- uri = args['auth_level.ns.%s' % (alias,)]
- except KeyError:
- if is_openid1:
- uri = self._default_auth_level_aliases.get(alias)
- else:
- uri = None
-
- if uri is None:
- if strict:
- raise ValueError(
- 'Undefined auth level alias: %r' % (alias,))
- else:
- self.setAuthLevel(uri, val, alias)
-
- auth_time = args.get('auth_time')
- if auth_time:
- if TIME_VALIDATOR.match(auth_time):
- self.auth_time = auth_time
- elif strict:
- raise ValueError("auth_time must be in RFC3339 format")
-
- fromSuccessResponse = classmethod(fromSuccessResponse)
-
- def getExtensionArgs(self):
- """@see: C{L{Extension.getExtensionArgs}}
- """
- if len(self.auth_policies) == 0:
- ns_args = {
- 'auth_policies': AUTH_NONE,
- }
- else:
- ns_args = {
- 'auth_policies':' '.join(self.auth_policies),
- }
-
- for level_type, level in self.auth_levels.iteritems():
- alias = self._getAlias(level_type)
- ns_args['auth_level.ns.%s' % (alias,)] = level_type
- ns_args['auth_level.%s' % (alias,)] = str(level)
-
- if self.auth_time is not None:
- if not TIME_VALIDATOR.match(self.auth_time):
- raise ValueError('auth_time must be in RFC3339 format')
-
- ns_args['auth_time'] = self.auth_time
-
- return ns_args
-
-Response.ns_uri = ns_uri
diff --git a/askbot/deps/openid/extensions/sreg.py b/askbot/deps/openid/extensions/sreg.py
deleted file mode 100644
index 7e89af47..00000000
--- a/askbot/deps/openid/extensions/sreg.py
+++ /dev/null
@@ -1,518 +0,0 @@
-"""Simple registration request and response parsing and object representation
-
-This module contains objects representing simple registration requests
-and responses that can be used with both OpenID relying parties and
-OpenID providers.
-
- 1. The relying party creates a request object and adds it to the
- C{L{AuthRequest<openid.consumer.consumer.AuthRequest>}} object
- before making the C{checkid_} request to the OpenID provider::
-
- auth_request.addExtension(SRegRequest(required=['email']))
-
- 2. The OpenID provider extracts the simple registration request from
- the OpenID request using C{L{SRegRequest.fromOpenIDRequest}},
- gets the user's approval and data, creates a C{L{SRegResponse}}
- object and adds it to the C{id_res} response::
-
- sreg_req = SRegRequest.fromOpenIDRequest(checkid_request)
- # [ get the user's approval and data, informing the user that
- # the fields in sreg_response were requested ]
- sreg_resp = SRegResponse.extractResponse(sreg_req, user_data)
- sreg_resp.toMessage(openid_response.fields)
-
- 3. The relying party uses C{L{SRegResponse.fromSuccessResponse}} to
- extract the data from the OpenID response::
-
- sreg_resp = SRegResponse.fromSuccessResponse(success_response)
-
-@since: 2.0
-
-@var sreg_data_fields: The names of the data fields that are listed in
- the sreg spec, and a description of them in English
-
-@var sreg_uri: The preferred URI to use for the simple registration
- namespace and XRD Type value
-"""
-
-from askbot.deps.openid.message import registerNamespaceAlias, \
- NamespaceAliasRegistrationError
-from askbot.deps.openid.extension import Extension
-from askbot.deps.openid import oidutil
-
-try:
- basestring #pylint:disable-msg=W0104
-except NameError:
- # For Python 2.2
- basestring = (str, unicode) #pylint:disable-msg=W0622
-
-__all__ = [
- 'SRegRequest',
- 'SRegResponse',
- 'data_fields',
- 'ns_uri',
- 'ns_uri_1_0',
- 'ns_uri_1_1',
- 'supportsSReg',
- ]
-
-# The data fields that are listed in the sreg spec
-data_fields = {
- 'fullname':'Full Name',
- 'nickname':'Nickname',
- 'dob':'Date of Birth',
- 'email':'E-mail Address',
- 'gender':'Gender',
- 'postcode':'Postal Code',
- 'country':'Country',
- 'language':'Language',
- 'timezone':'Time Zone',
- }
-
-def checkFieldName(field_name):
- """Check to see that the given value is a valid simple
- registration data field name.
-
- @raise ValueError: if the field name is not a valid simple
- registration data field name
- """
- if field_name not in data_fields:
- raise ValueError('%r is not a defined simple registration field' %
- (field_name,))
-
-# URI used in the wild for Yadis documents advertising simple
-# registration support
-ns_uri_1_0 = 'http://openid.net/sreg/1.0'
-
-# URI in the draft specification for simple registration 1.1
-# <http://openid.net/specs/openid-simple-registration-extension-1_1-01.html>
-ns_uri_1_1 = 'http://openid.net/extensions/sreg/1.1'
-
-# This attribute will always hold the preferred URI to use when adding
-# sreg support to an XRDS file or in an OpenID namespace declaration.
-ns_uri = ns_uri_1_1
-
-try:
- registerNamespaceAlias(ns_uri_1_1, 'sreg')
-except NamespaceAliasRegistrationError, e:
- oidutil.log('registerNamespaceAlias(%r, %r) failed: %s' % (ns_uri_1_1,
- 'sreg', str(e),))
-
-def supportsSReg(endpoint):
- """Does the given endpoint advertise support for simple
- registration?
-
- @param endpoint: The endpoint object as returned by OpenID discovery
- @type endpoint: openid.consumer.discover.OpenIDEndpoint
-
- @returns: Whether an sreg type was advertised by the endpoint
- @rtype: bool
- """
- return (endpoint.usesExtension(ns_uri_1_1) or
- endpoint.usesExtension(ns_uri_1_0))
-
-class SRegNamespaceError(ValueError):
- """The simple registration namespace was not found and could not
- be created using the expected name (there's another extension
- using the name 'sreg')
-
- This is not I{illegal}, for OpenID 2, although it probably
- indicates a problem, since it's not expected that other extensions
- will re-use the alias that is in use for OpenID 1.
-
- If this is an OpenID 1 request, then there is no recourse. This
- should not happen unless some code has modified the namespaces for
- the message that is being processed.
- """
-
-def getSRegNS(message):
- """Extract the simple registration namespace URI from the given
- OpenID message. Handles OpenID 1 and 2, as well as both sreg
- namespace URIs found in the wild, as well as missing namespace
- definitions (for OpenID 1)
-
- @param message: The OpenID message from which to parse simple
- registration fields. This may be a request or response message.
- @type message: C{L{openid.message.Message}}
-
- @returns: the sreg namespace URI for the supplied message. The
- message may be modified to define a simple registration
- namespace.
- @rtype: C{str}
-
- @raise ValueError: when using OpenID 1 if the message defines
- the 'sreg' alias to be something other than a simple
- registration type.
- """
- # See if there exists an alias for one of the two defined simple
- # registration types.
- for sreg_ns_uri in [ns_uri_1_1, ns_uri_1_0]:
- alias = message.namespaces.getAlias(sreg_ns_uri)
- if alias is not None:
- break
- else:
- # There is no alias for either of the types, so try to add
- # one. We default to using the modern value (1.1)
- sreg_ns_uri = ns_uri_1_1
- try:
- message.namespaces.addAlias(ns_uri_1_1, 'sreg')
- except KeyError, why:
- # An alias for the string 'sreg' already exists, but it's
- # defined for something other than simple registration
- raise SRegNamespaceError(why[0])
-
- # we know that sreg_ns_uri defined, because it's defined in the
- # else clause of the loop as well, so disable the warning
- return sreg_ns_uri #pylint:disable-msg=W0631
-
-class SRegRequest(Extension):
- """An object to hold the state of a simple registration request.
-
- @ivar required: A list of the required fields in this simple
- registration request
- @type required: [str]
-
- @ivar optional: A list of the optional fields in this simple
- registration request
- @type optional: [str]
-
- @ivar policy_url: The policy URL that was provided with the request
- @type policy_url: str or NoneType
-
- @group Consumer: requestField, requestFields, getExtensionArgs, addToOpenIDRequest
- @group Server: fromOpenIDRequest, parseExtensionArgs
- """
-
- ns_alias = 'sreg'
-
- def __init__(self, required=None, optional=None, policy_url=None,
- sreg_ns_uri=ns_uri):
- """Initialize an empty simple registration request"""
- Extension.__init__(self)
- self.required = []
- self.optional = []
- self.policy_url = policy_url
- self.ns_uri = sreg_ns_uri
-
- if required:
- self.requestFields(required, required=True, strict=True)
-
- if optional:
- self.requestFields(optional, required=False, strict=True)
-
- # Assign getSRegNS to a static method so that it can be
- # overridden for testing.
- _getSRegNS = staticmethod(getSRegNS)
-
- def fromOpenIDRequest(cls, request):
- """Create a simple registration request that contains the
- fields that were requested in the OpenID request with the
- given arguments
-
- @param request: The OpenID request
- @type request: openid.server.CheckIDRequest
-
- @returns: The newly created simple registration request
- @rtype: C{L{SRegRequest}}
- """
- self = cls()
-
- # Since we're going to mess with namespace URI mapping, don't
- # mutate the object that was passed in.
- message = request.message.copy()
-
- self.ns_uri = self._getSRegNS(message)
- args = message.getArgs(self.ns_uri)
- self.parseExtensionArgs(args)
-
- return self
-
- fromOpenIDRequest = classmethod(fromOpenIDRequest)
-
- def parseExtensionArgs(self, args, strict=False):
- """Parse the unqualified simple registration request
- parameters and add them to this object.
-
- This method is essentially the inverse of
- C{L{getExtensionArgs}}. This method restores the serialized simple
- registration request fields.
-
- If you are extracting arguments from a standard OpenID
- checkid_* request, you probably want to use C{L{fromOpenIDRequest}},
- which will extract the sreg namespace and arguments from the
- OpenID request. This method is intended for cases where the
- OpenID server needs more control over how the arguments are
- parsed than that method provides.
-
- >>> args = message.getArgs(ns_uri)
- >>> request.parseExtensionArgs(args)
-
- @param args: The unqualified simple registration arguments
- @type args: {str:str}
-
- @param strict: Whether requests with fields that are not
- defined in the simple registration specification should be
- tolerated (and ignored)
- @type strict: bool
-
- @returns: None; updates this object
- """
- for list_name in ['required', 'optional']:
- required = (list_name == 'required')
- items = args.get(list_name)
- if items:
- for field_name in items.split(','):
- try:
- self.requestField(field_name, required, strict)
- except ValueError:
- if strict:
- raise
-
- self.policy_url = args.get('policy_url')
-
- def allRequestedFields(self):
- """A list of all of the simple registration fields that were
- requested, whether they were required or optional.
-
- @rtype: [str]
- """
- return self.required + self.optional
-
- def wereFieldsRequested(self):
- """Have any simple registration fields been requested?
-
- @rtype: bool
- """
- return bool(self.allRequestedFields())
-
- def __contains__(self, field_name):
- """Was this field in the request?"""
- return (field_name in self.required or
- field_name in self.optional)
-
- def requestField(self, field_name, required=False, strict=False):
- """Request the specified field from the OpenID user
-
- @param field_name: the unqualified simple registration field name
- @type field_name: str
-
- @param required: whether the given field should be presented
- to the user as being a required to successfully complete
- the request
-
- @param strict: whether to raise an exception when a field is
- added to a request more than once
-
- @raise ValueError: when the field requested is not a simple
- registration field or strict is set and the field was
- requested more than once
- """
- checkFieldName(field_name)
-
- if strict:
- if field_name in self.required or field_name in self.optional:
- raise ValueError('That field has already been requested')
- else:
- if field_name in self.required:
- return
-
- if field_name in self.optional:
- if required:
- self.optional.remove(field_name)
- else:
- return
-
- if required:
- self.required.append(field_name)
- else:
- self.optional.append(field_name)
-
- def requestFields(self, field_names, required=False, strict=False):
- """Add the given list of fields to the request
-
- @param field_names: The simple registration data fields to request
- @type field_names: [str]
-
- @param required: Whether these values should be presented to
- the user as required
-
- @param strict: whether to raise an exception when a field is
- added to a request more than once
-
- @raise ValueError: when a field requested is not a simple
- registration field or strict is set and a field was
- requested more than once
- """
- if isinstance(field_names, basestring):
- raise TypeError('Fields should be passed as a list of '
- 'strings (not %r)' % (type(field_names),))
-
- for field_name in field_names:
- self.requestField(field_name, required, strict=strict)
-
- def getExtensionArgs(self):
- """Get a dictionary of unqualified simple registration
- arguments representing this request.
-
- This method is essentially the inverse of
- C{L{parseExtensionArgs}}. This method serializes the simple
- registration request fields.
-
- @rtype: {str:str}
- """
- args = {}
-
- if self.required:
- args['required'] = ','.join(self.required)
-
- if self.optional:
- args['optional'] = ','.join(self.optional)
-
- if self.policy_url:
- args['policy_url'] = self.policy_url
-
- return args
-
-class SRegResponse(Extension):
- """Represents the data returned in a simple registration response
- inside of an OpenID C{id_res} response. This object will be
- created by the OpenID server, added to the C{id_res} response
- object, and then extracted from the C{id_res} message by the
- Consumer.
-
- @ivar data: The simple registration data, keyed by the unqualified
- simple registration name of the field (i.e. nickname is keyed
- by C{'nickname'})
-
- @ivar ns_uri: The URI under which the simple registration data was
- stored in the response message.
-
- @group Server: extractResponse
- @group Consumer: fromSuccessResponse
- @group Read-only dictionary interface: keys, iterkeys, items, iteritems,
- __iter__, get, __getitem__, keys, has_key
- """
-
- ns_alias = 'sreg'
-
- def __init__(self, data=None, sreg_ns_uri=ns_uri):
- Extension.__init__(self)
- if data is None:
- self.data = {}
- else:
- self.data = data
-
- self.ns_uri = sreg_ns_uri
-
- def extractResponse(cls, request, data):
- """Take a C{L{SRegRequest}} and a dictionary of simple
- registration values and create a C{L{SRegResponse}}
- object containing that data.
-
- @param request: The simple registration request object
- @type request: SRegRequest
-
- @param data: The simple registration data for this
- response, as a dictionary from unqualified simple
- registration field name to string (unicode) value. For
- instance, the nickname should be stored under the key
- 'nickname'.
- @type data: {str:str}
-
- @returns: a simple registration response object
- @rtype: SRegResponse
- """
- self = cls()
- self.ns_uri = request.ns_uri
- for field in request.allRequestedFields():
- value = data.get(field)
- if value is not None:
- self.data[field] = value
- return self
-
- extractResponse = classmethod(extractResponse)
-
- # Assign getSRegArgs to a static method so that it can be
- # overridden for testing
- _getSRegNS = staticmethod(getSRegNS)
-
- def fromSuccessResponse(cls, success_response, signed_only=True):
- """Create a C{L{SRegResponse}} object from a successful OpenID
- library response
- (C{L{openid.consumer.consumer.SuccessResponse}}) response
- message
-
- @param success_response: A SuccessResponse from consumer.complete()
- @type success_response: C{L{openid.consumer.consumer.SuccessResponse}}
-
- @param signed_only: Whether to process only data that was
- signed in the id_res message from the server.
- @type signed_only: bool
-
- @rtype: SRegResponse
- @returns: A simple registration response containing the data
- that was supplied with the C{id_res} response.
- """
- self = cls()
- self.ns_uri = self._getSRegNS(success_response.message)
- if signed_only:
- args = success_response.getSignedNS(self.ns_uri)
- else:
- args = success_response.message.getArgs(self.ns_uri)
-
- if not args:
- return None
-
- for field_name in data_fields:
- if field_name in args:
- self.data[field_name] = args[field_name]
-
- return self
-
- fromSuccessResponse = classmethod(fromSuccessResponse)
-
- def getExtensionArgs(self):
- """Get the fields to put in the simple registration namespace
- when adding them to an id_res message.
-
- @see: openid.extension
- """
- return self.data
-
- # Read-only dictionary interface
- def get(self, field_name, default=None):
- """Like dict.get, except that it checks that the field name is
- defined by the simple registration specification"""
- checkFieldName(field_name)
- return self.data.get(field_name, default)
-
- def items(self):
- """All of the data values in this simple registration response
- """
- return self.data.items()
-
- def iteritems(self):
- return self.data.iteritems()
-
- def keys(self):
- return self.data.keys()
-
- def iterkeys(self):
- return self.data.iterkeys()
-
- def has_key(self, key):
- return key in self
-
- def __contains__(self, field_name):
- checkFieldName(field_name)
- return field_name in self.data
-
- def __iter__(self):
- return iter(self.data)
-
- def __getitem__(self, field_name):
- checkFieldName(field_name)
- return self.data[field_name]
-
- def __nonzero__(self):
- return bool(self.data)
diff --git a/askbot/deps/openid/fetchers.py b/askbot/deps/openid/fetchers.py
deleted file mode 100644
index 11ab47fb..00000000
--- a/askbot/deps/openid/fetchers.py
+++ /dev/null
@@ -1,427 +0,0 @@
-# -*- test-case-name: openid.test.test_fetchers -*-
-"""
-This module contains the HTTP fetcher interface and several implementations.
-"""
-
-__all__ = ['fetch', 'getDefaultFetcher', 'setDefaultFetcher', 'HTTPResponse',
- 'HTTPFetcher', 'createHTTPFetcher', 'HTTPFetchingError',
- 'HTTPError']
-
-import urllib2
-import time
-import cStringIO
-import sys
-
-from askbot.deps import openid
-import askbot.deps.openid.urinorm
-
-# Try to import httplib2 for caching support
-# http://bitworking.org/projects/httplib2/
-try:
- import httplib2
-except ImportError:
- # httplib2 not available
- httplib2 = None
-
-# try to import pycurl, which will let us use CurlHTTPFetcher
-try:
- import pycurl
-except ImportError:
- pycurl = None
-
-USER_AGENT = "python-openid/%s (%s)" % (openid.__version__, sys.platform)
-MAX_RESPONSE_KB = 1024
-
-def fetch(url, body=None, headers=None):
- """Invoke the fetch method on the default fetcher. Most users
- should need only this method.
-
- @raises Exception: any exceptions that may be raised by the default fetcher
- """
- fetcher = getDefaultFetcher()
- return fetcher.fetch(url, body, headers)
-
-def createHTTPFetcher():
- """Create a default HTTP fetcher instance
-
- prefers Curl to urllib2."""
- if pycurl is None:
- fetcher = Urllib2Fetcher()
- else:
- fetcher = CurlHTTPFetcher()
-
- return fetcher
-
-# Contains the currently set HTTP fetcher. If it is set to None, the
-# library will call createHTTPFetcher() to set it. Do not access this
-# variable outside of this module.
-_default_fetcher = None
-
-def getDefaultFetcher():
- """Return the default fetcher instance
- if no fetcher has been set, it will create a default fetcher.
-
- @return: the default fetcher
- @rtype: HTTPFetcher
- """
- global _default_fetcher
-
- if _default_fetcher is None:
- setDefaultFetcher(createHTTPFetcher())
-
- return _default_fetcher
-
-def setDefaultFetcher(fetcher, wrap_exceptions=True):
- """Set the default fetcher
-
- @param fetcher: The fetcher to use as the default HTTP fetcher
- @type fetcher: HTTPFetcher
-
- @param wrap_exceptions: Whether to wrap exceptions thrown by the
- fetcher wil HTTPFetchingError so that they may be caught
- easier. By default, exceptions will be wrapped. In general,
- unwrapped fetchers are useful for debugging of fetching errors
- or if your fetcher raises well-known exceptions that you would
- like to catch.
- @type wrap_exceptions: bool
- """
- global _default_fetcher
- if fetcher is None or not wrap_exceptions:
- _default_fetcher = fetcher
- else:
- _default_fetcher = ExceptionWrappingFetcher(fetcher)
-
-def usingCurl():
- """Whether the currently set HTTP fetcher is a Curl HTTP fetcher."""
- return isinstance(getDefaultFetcher(), CurlHTTPFetcher)
-
-class HTTPResponse(object):
- """XXX document attributes"""
- headers = None
- status = None
- body = None
- final_url = None
-
- def __init__(self, final_url=None, status=None, headers=None, body=None):
- self.final_url = final_url
- self.status = status
- self.headers = headers
- self.body = body
-
- def __repr__(self):
- return "<%s status %s for %s>" % (self.__class__.__name__,
- self.status,
- self.final_url)
-
-class HTTPFetcher(object):
- """
- This class is the interface for openid HTTP fetchers. This
- interface is only important if you need to write a new fetcher for
- some reason.
- """
-
- def fetch(self, url, body=None, headers=None):
- """
- This performs an HTTP POST or GET, following redirects along
- the way. If a body is specified, then the request will be a
- POST. Otherwise, it will be a GET.
-
-
- @param headers: HTTP headers to include with the request
- @type headers: {str:str}
-
- @return: An object representing the server's HTTP response. If
- there are network or protocol errors, an exception will be
- raised. HTTP error responses, like 404 or 500, do not
- cause exceptions.
-
- @rtype: L{HTTPResponse}
-
- @raise Exception: Different implementations will raise
- different errors based on the underlying HTTP library.
- """
- raise NotImplementedError
-
-def _allowedURL(url):
- return url.startswith('http://') or url.startswith('https://')
-
-class HTTPFetchingError(Exception):
- """Exception that is wrapped around all exceptions that are raised
- by the underlying fetcher when using the ExceptionWrappingFetcher
-
- @ivar why: The exception that caused this exception
- """
- def __init__(self, why=None):
- Exception.__init__(self, why)
- self.why = why
-
-class ExceptionWrappingFetcher(HTTPFetcher):
- """Fetcher that wraps another fetcher, causing all exceptions
-
- @cvar uncaught_exceptions: Exceptions that should be exposed to the
- user if they are raised by the fetch call
- """
-
- uncaught_exceptions = (SystemExit, KeyboardInterrupt, MemoryError)
-
- def __init__(self, fetcher):
- self.fetcher = fetcher
-
- def fetch(self, *args, **kwargs):
- try:
- return self.fetcher.fetch(*args, **kwargs)
- except self.uncaught_exceptions:
- raise
- except:
- exc_cls, exc_inst = sys.exc_info()[:2]
- if exc_inst is None:
- # string exceptions
- exc_inst = exc_cls
-
- raise HTTPFetchingError(why=exc_inst)
-
-class Urllib2Fetcher(HTTPFetcher):
- """An C{L{HTTPFetcher}} that uses urllib2.
- """
-
- # Parameterized for the benefit of testing frameworks, see
- # http://trac.openidenabled.com/trac/ticket/85
- urlopen = staticmethod(urllib2.urlopen)
-
- def fetch(self, url, body=None, headers=None):
- if not _allowedURL(url):
- raise ValueError('Bad URL scheme: %r' % (url,))
-
- if headers is None:
- headers = {}
-
- headers.setdefault(
- 'User-Agent',
- "%s Python-urllib/%s" % (USER_AGENT, urllib2.__version__,))
-
- req = urllib2.Request(url, data=body, headers=headers)
- try:
- f = self.urlopen(req)
- try:
- return self._makeResponse(f)
- finally:
- f.close()
- except urllib2.HTTPError, why:
- try:
- return self._makeResponse(why)
- finally:
- why.close()
-
- def _makeResponse(self, urllib2_response):
- resp = HTTPResponse()
- resp.body = urllib2_response.read(MAX_RESPONSE_KB * 1024)
- resp.final_url = urllib2_response.geturl()
- resp.headers = dict(urllib2_response.info().items())
-
- if hasattr(urllib2_response, 'code'):
- resp.status = urllib2_response.code
- else:
- resp.status = 200
-
- return resp
-
-class HTTPError(HTTPFetchingError):
- """
- This exception is raised by the C{L{CurlHTTPFetcher}} when it
- encounters an exceptional situation fetching a URL.
- """
- pass
-
-# XXX: define what we mean by paranoid, and make sure it is.
-class CurlHTTPFetcher(HTTPFetcher):
- """
- An C{L{HTTPFetcher}} that uses pycurl for fetching.
- See U{http://pycurl.sourceforge.net/}.
- """
- ALLOWED_TIME = 20 # seconds
-
- def __init__(self):
- HTTPFetcher.__init__(self)
- if pycurl is None:
- raise RuntimeError('Cannot find pycurl library')
-
- def _parseHeaders(self, header_file):
- header_file.seek(0)
-
- # Remove the status line from the beginning of the input
- unused_http_status_line = header_file.readline().lower ()
- if unused_http_status_line.startswith('http/1.1 100 '):
- unused_http_status_line = header_file.readline()
- unused_http_status_line = header_file.readline()
-
- lines = [line.strip() for line in header_file]
-
- # and the blank line from the end
- empty_line = lines.pop()
- if empty_line:
- raise HTTPError("No blank line at end of headers: %r" % (line,))
-
- headers = {}
- for line in lines:
- try:
- name, value = line.split(':', 1)
- except ValueError:
- raise HTTPError(
- "Malformed HTTP header line in response: %r" % (line,))
-
- value = value.strip()
-
- # HTTP headers are case-insensitive
- name = name.lower()
- headers[name] = value
-
- return headers
-
- def _checkURL(self, url):
- # XXX: document that this can be overridden to match desired policy
- # XXX: make sure url is well-formed and routeable
- return _allowedURL(url)
-
- def fetch(self, url, body=None, headers=None):
- stop = int(time.time()) + self.ALLOWED_TIME
- off = self.ALLOWED_TIME
-
- if headers is None:
- headers = {}
-
- headers.setdefault('User-Agent',
- "%s %s" % (USER_AGENT, pycurl.version,))
-
- header_list = []
- if headers is not None:
- for header_name, header_value in headers.iteritems():
- header_list.append('%s: %s' % (header_name, header_value))
-
- c = pycurl.Curl()
- try:
- c.setopt(pycurl.NOSIGNAL, 1)
-
- if header_list:
- c.setopt(pycurl.HTTPHEADER, header_list)
-
- # Presence of a body indicates that we should do a POST
- if body is not None:
- c.setopt(pycurl.POST, 1)
- c.setopt(pycurl.POSTFIELDS, body)
-
- while off > 0:
- if not self._checkURL(url):
- raise HTTPError("Fetching URL not allowed: %r" % (url,))
-
- data = cStringIO.StringIO()
- def write_data(chunk):
- if data.tell() > 1024*MAX_RESPONSE_KB:
- return 0
- else:
- return data.write(chunk)
-
- response_header_data = cStringIO.StringIO()
- c.setopt(pycurl.WRITEFUNCTION, write_data)
- c.setopt(pycurl.HEADERFUNCTION, response_header_data.write)
- c.setopt(pycurl.TIMEOUT, off)
- c.setopt(pycurl.URL, askbot.deps.openid.urinorm.urinorm(url))
-
- c.perform()
-
- response_headers = self._parseHeaders(response_header_data)
- code = c.getinfo(pycurl.RESPONSE_CODE)
- if code in [301, 302, 303, 307]:
- url = response_headers.get('location')
- if url is None:
- raise HTTPError(
- 'Redirect (%s) returned without a location' % code)
-
- # Redirects are always GETs
- c.setopt(pycurl.POST, 0)
-
- # There is no way to reset POSTFIELDS to empty and
- # reuse the connection, but we only use it once.
- else:
- resp = HTTPResponse()
- resp.headers = response_headers
- resp.status = code
- resp.final_url = url
- resp.body = data.getvalue()
- return resp
-
- off = stop - int(time.time())
-
- raise HTTPError("Timed out fetching: %r" % (url,))
- finally:
- c.close()
-
-class HTTPLib2Fetcher(HTTPFetcher):
- """A fetcher that uses C{httplib2} for performing HTTP
- requests. This implementation supports HTTP caching.
-
- @see: http://bitworking.org/projects/httplib2/
- """
-
- def __init__(self, cache=None):
- """@param cache: An object suitable for use as an C{httplib2}
- cache. If a string is passed, it is assumed to be a
- directory name.
- """
- if httplib2 is None:
- raise RuntimeError('Cannot find httplib2 library. '
- 'See http://bitworking.org/projects/httplib2/')
-
- super(HTTPLib2Fetcher, self).__init__()
-
- # An instance of the httplib2 object that performs HTTP requests
- self.httplib2 = httplib2.Http(cache)
-
- # We want httplib2 to raise exceptions for errors, just like
- # the other fetchers.
- self.httplib2.force_exception_to_status_code = False
-
- def fetch(self, url, body=None, headers=None):
- """Perform an HTTP request
-
- @raises Exception: Any exception that can be raised by httplib2
-
- @see: C{L{HTTPFetcher.fetch}}
- """
- if body:
- method = 'POST'
- else:
- method = 'GET'
-
- if headers is None:
- headers = {}
-
- # httplib2 doesn't check to make sure that the URL's scheme is
- # 'http' so we do it here.
- if not (url.startswith('http://') or url.startswith('https://')):
- raise ValueError('URL is not a HTTP URL: %r' % (url,))
-
- httplib2_response, content = self.httplib2.request(
- url, method, body=body, headers=headers)
-
- # Translate the httplib2 response to our HTTP response abstraction
-
- # When a 400 is returned, there is no "content-location"
- # header set. This seems like a bug to me. I can't think of a
- # case where we really care about the final URL when it is an
- # error response, but being careful about it can't hurt.
- try:
- final_url = httplib2_response['content-location']
- except KeyError:
- # We're assuming that no redirects occurred
- assert not httplib2_response.previous
-
- # And this should never happen for a successful response
- assert httplib2_response.status != 200
- final_url = url
-
- return HTTPResponse(
- body=content,
- final_url=final_url,
- headers=dict(httplib2_response.items()),
- status=httplib2_response.status,
- )
diff --git a/askbot/deps/openid/kvform.py b/askbot/deps/openid/kvform.py
deleted file mode 100644
index 81d429ea..00000000
--- a/askbot/deps/openid/kvform.py
+++ /dev/null
@@ -1,123 +0,0 @@
-__all__ = ['seqToKV', 'kvToSeq', 'dictToKV', 'kvToDict']
-
-from askbot.deps.openid import oidutil
-
-import types
-
-class KVFormError(ValueError):
- pass
-
-def seqToKV(seq, strict=False):
- """Represent a sequence of pairs of strings as newline-terminated
- key:value pairs. The pairs are generated in the order given.
-
- @param seq: The pairs
- @type seq: [(str, (unicode|str))]
-
- @return: A string representation of the sequence
- @rtype: str
- """
- def err(msg):
- formatted = 'seqToKV warning: %s: %r' % (msg, seq)
- if strict:
- raise KVFormError(formatted)
- else:
- oidutil.log(formatted)
-
- lines = []
- for k, v in seq:
- if isinstance(k, types.StringType):
- k = k.decode('UTF8')
- elif not isinstance(k, types.UnicodeType):
- err('Converting key to string: %r' % k)
- k = str(k)
-
- if '\n' in k:
- raise KVFormError(
- 'Invalid input for seqToKV: key contains newline: %r' % (k,))
-
- if ':' in k:
- raise KVFormError(
- 'Invalid input for seqToKV: key contains colon: %r' % (k,))
-
- if k.strip() != k:
- err('Key has whitespace at beginning or end: %r' % (k,))
-
- if isinstance(v, types.StringType):
- v = v.decode('UTF8')
- elif not isinstance(v, types.UnicodeType):
- err('Converting value to string: %r' % (v,))
- v = str(v)
-
- if '\n' in v:
- raise KVFormError(
- 'Invalid input for seqToKV: value contains newline: %r' % (v,))
-
- if v.strip() != v:
- err('Value has whitespace at beginning or end: %r' % (v,))
-
- lines.append(k + ':' + v + '\n')
-
- return ''.join(lines).encode('UTF8')
-
-def kvToSeq(data, strict=False):
- """
-
- After one parse, seqToKV and kvToSeq are inverses, with no warnings::
-
- seq = kvToSeq(s)
- seqToKV(kvToSeq(seq)) == seq
- """
- def err(msg):
- formatted = 'kvToSeq warning: %s: %r' % (msg, data)
- if strict:
- raise KVFormError(formatted)
- else:
- oidutil.log(formatted)
-
- lines = data.split('\n')
- if lines[-1]:
- err('Does not end in a newline')
- else:
- del lines[-1]
-
- pairs = []
- line_num = 0
- for line in lines:
- line_num += 1
-
- # Ignore blank lines
- if not line.strip():
- continue
-
- pair = line.split(':', 1)
- if len(pair) == 2:
- k, v = pair
- k_s = k.strip()
- if k_s != k:
- fmt = ('In line %d, ignoring leading or trailing '
- 'whitespace in key %r')
- err(fmt % (line_num, k))
-
- if not k_s:
- err('In line %d, got empty key' % (line_num,))
-
- v_s = v.strip()
- if v_s != v:
- fmt = ('In line %d, ignoring leading or trailing '
- 'whitespace in value %r')
- err(fmt % (line_num, v))
-
- pairs.append((k_s.decode('UTF8'), v_s.decode('UTF8')))
- else:
- err('Line %d does not contain a colon' % line_num)
-
- return pairs
-
-def dictToKV(d):
- seq = d.items()
- seq.sort()
- return seqToKV(seq)
-
-def kvToDict(s):
- return dict(kvToSeq(s))
diff --git a/askbot/deps/openid/message.py b/askbot/deps/openid/message.py
deleted file mode 100644
index 1ba72f06..00000000
--- a/askbot/deps/openid/message.py
+++ /dev/null
@@ -1,631 +0,0 @@
-"""Extension argument processing code
-"""
-__all__ = ['Message', 'NamespaceMap', 'no_default', 'registerNamespaceAlias',
- 'OPENID_NS', 'BARE_NS', 'OPENID1_NS', 'OPENID2_NS', 'SREG_URI',
- 'IDENTIFIER_SELECT']
-
-import copy
-import warnings
-import urllib
-
-from askbot.deps.openid import oidutil
-from askbot.deps.openid import kvform
-try:
- ElementTree = oidutil.importElementTree()
-except ImportError:
- # No elementtree found, so give up, but don't fail to import,
- # since we have fallbacks.
- ElementTree = None
-
-# This doesn't REALLY belong here, but where is better?
-IDENTIFIER_SELECT = 'http://specs.openid.net/auth/2.0/identifier_select'
-
-# URI for Simple Registration extension, the only commonly deployed
-# OpenID 1.x extension, and so a special case
-SREG_URI = 'http://openid.net/sreg/1.0'
-
-# The OpenID 1.X namespace URI
-OPENID1_NS = 'http://openid.net/signon/1.0'
-THE_OTHER_OPENID1_NS = 'http://openid.net/signon/1.1'
-
-OPENID1_NAMESPACES = OPENID1_NS, THE_OTHER_OPENID1_NS
-
-# The OpenID 2.0 namespace URI
-OPENID2_NS = 'http://specs.openid.net/auth/2.0'
-
-# The namespace consisting of pairs with keys that are prefixed with
-# "openid." but not in another namespace.
-NULL_NAMESPACE = oidutil.Symbol('Null namespace')
-
-# The null namespace, when it is an allowed OpenID namespace
-OPENID_NS = oidutil.Symbol('OpenID namespace')
-
-# The top-level namespace, excluding all pairs with keys that start
-# with "openid."
-BARE_NS = oidutil.Symbol('Bare namespace')
-
-# Limit, in bytes, of identity provider and return_to URLs, including
-# response payload. See OpenID 1.1 specification, Appendix D.
-OPENID1_URL_LIMIT = 2047
-
-# All OpenID protocol fields. Used to check namespace aliases.
-OPENID_PROTOCOL_FIELDS = [
- 'ns', 'mode', 'error', 'return_to', 'contact', 'reference',
- 'signed', 'assoc_type', 'session_type', 'dh_modulus', 'dh_gen',
- 'dh_consumer_public', 'claimed_id', 'identity', 'realm',
- 'invalidate_handle', 'op_endpoint', 'response_nonce', 'sig',
- 'assoc_handle', 'trust_root', 'openid',
- ]
-
-class UndefinedOpenIDNamespace(ValueError):
- """Raised if the generic OpenID namespace is accessed when there
- is no OpenID namespace set for this message."""
-
-class InvalidOpenIDNamespace(ValueError):
- """Raised if openid.ns is not a recognized value.
-
- For recognized values, see L{Message.allowed_openid_namespaces}
- """
- def __str__(self):
- s = "Invalid OpenID Namespace"
- if self.args:
- s += " %r" % (self.args[0],)
- return s
-
-
-# Sentinel used for Message implementation to indicate that getArg
-# should raise an exception instead of returning a default.
-no_default = object()
-
-# Global namespace / alias registration map. See
-# registerNamespaceAlias.
-registered_aliases = {}
-
-class NamespaceAliasRegistrationError(Exception):
- """
- Raised when an alias or namespace URI has already been registered.
- """
- pass
-
-def registerNamespaceAlias(namespace_uri, alias):
- """
- Registers a (namespace URI, alias) mapping in a global namespace
- alias map. Raises NamespaceAliasRegistrationError if either the
- namespace URI or alias has already been registered with a
- different value. This function is required if you want to use a
- namespace with an OpenID 1 message.
- """
- global registered_aliases
-
- if registered_aliases.get(alias) == namespace_uri:
- return
-
- if namespace_uri in registered_aliases.values():
- raise NamespaceAliasRegistrationError, \
- 'Namespace uri %r already registered' % (namespace_uri,)
-
- if alias in registered_aliases:
- raise NamespaceAliasRegistrationError, \
- 'Alias %r already registered' % (alias,)
-
- registered_aliases[alias] = namespace_uri
-
-class Message(object):
- """
- In the implementation of this object, None represents the global
- namespace as well as a namespace with no key.
-
- @cvar namespaces: A dictionary specifying specific
- namespace-URI to alias mappings that should be used when
- generating namespace aliases.
-
- @ivar ns_args: two-level dictionary of the values in this message,
- grouped by namespace URI. The first level is the namespace
- URI.
- """
-
- allowed_openid_namespaces = [OPENID1_NS, THE_OTHER_OPENID1_NS, OPENID2_NS]
-
- def __init__(self, openid_namespace=None):
- """Create an empty Message.
-
- @raises InvalidOpenIDNamespace: if openid_namespace is not in
- L{Message.allowed_openid_namespaces}
- """
- self.args = {}
- self.namespaces = NamespaceMap()
- if openid_namespace is None:
- self._openid_ns_uri = None
- else:
- implicit = openid_namespace in OPENID1_NAMESPACES
- self.setOpenIDNamespace(openid_namespace, implicit)
-
- def fromPostArgs(cls, args):
- """Construct a Message containing a set of POST arguments.
-
- """
- self = cls()
-
- # Partition into "openid." args and bare args
- openid_args = {}
- for key, value in args.items():
- if isinstance(value, list):
- raise TypeError("query dict must have one value for each key, "
- "not lists of values. Query is %r" % (args,))
-
-
- try:
- prefix, rest = key.split('.', 1)
- except ValueError:
- prefix = None
-
- if prefix != 'openid':
- self.args[(BARE_NS, key)] = value
- else:
- openid_args[rest] = value
-
- self._fromOpenIDArgs(openid_args)
-
- return self
-
- fromPostArgs = classmethod(fromPostArgs)
-
- def fromOpenIDArgs(cls, openid_args):
- """Construct a Message from a parsed KVForm message.
-
- @raises InvalidOpenIDNamespace: if openid.ns is not in
- L{Message.allowed_openid_namespaces}
- """
- self = cls()
- self._fromOpenIDArgs(openid_args)
- return self
-
- fromOpenIDArgs = classmethod(fromOpenIDArgs)
-
- def _fromOpenIDArgs(self, openid_args):
- ns_args = []
-
- # Resolve namespaces
- for rest, value in openid_args.iteritems():
- try:
- ns_alias, ns_key = rest.split('.', 1)
- except ValueError:
- ns_alias = NULL_NAMESPACE
- ns_key = rest
-
- if ns_alias == 'ns':
- self.namespaces.addAlias(value, ns_key)
- elif ns_alias == NULL_NAMESPACE and ns_key == 'ns':
- # null namespace
- self.setOpenIDNamespace(value, False)
- else:
- ns_args.append((ns_alias, ns_key, value))
-
- # Implicitly set an OpenID namespace definition (OpenID 1)
- if not self.getOpenIDNamespace():
- self.setOpenIDNamespace(OPENID1_NS, True)
-
- # Actually put the pairs into the appropriate namespaces
- for (ns_alias, ns_key, value) in ns_args:
- ns_uri = self.namespaces.getNamespaceURI(ns_alias)
- if ns_uri is None:
- # we found a namespaced arg without a namespace URI defined
- ns_uri = self._getDefaultNamespace(ns_alias)
- if ns_uri is None:
- ns_uri = self.getOpenIDNamespace()
- ns_key = '%s.%s' % (ns_alias, ns_key)
- else:
- self.namespaces.addAlias(ns_uri, ns_alias, implicit=True)
-
- self.setArg(ns_uri, ns_key, value)
-
- def _getDefaultNamespace(self, mystery_alias):
- """OpenID 1 compatibility: look for a default namespace URI to
- use for this alias."""
- global registered_aliases
- # Only try to map an alias to a default if it's an
- # OpenID 1.x message.
- if self.isOpenID1():
- return registered_aliases.get(mystery_alias)
- else:
- return None
-
- def setOpenIDNamespace(self, openid_ns_uri, implicit):
- """Set the OpenID namespace URI used in this message.
-
- @raises InvalidOpenIDNamespace: if the namespace is not in
- L{Message.allowed_openid_namespaces}
- """
- if openid_ns_uri not in self.allowed_openid_namespaces:
- raise InvalidOpenIDNamespace(openid_ns_uri)
-
- self.namespaces.addAlias(openid_ns_uri, NULL_NAMESPACE, implicit)
- self._openid_ns_uri = openid_ns_uri
-
- def getOpenIDNamespace(self):
- return self._openid_ns_uri
-
- def isOpenID1(self):
- return self.getOpenIDNamespace() in OPENID1_NAMESPACES
-
- def isOpenID2(self):
- return self.getOpenIDNamespace() == OPENID2_NS
-
- def fromKVForm(cls, kvform_string):
- """Create a Message from a KVForm string"""
- return cls.fromOpenIDArgs(kvform.kvToDict(kvform_string))
-
- fromKVForm = classmethod(fromKVForm)
-
- def copy(self):
- return copy.deepcopy(self)
-
- def toPostArgs(self):
- """Return all arguments with openid. in front of namespaced arguments.
- """
- args = {}
-
- # Add namespace definitions to the output
- for ns_uri, alias in self.namespaces.iteritems():
- if self.namespaces.isImplicit(ns_uri):
- continue
- if alias == NULL_NAMESPACE:
- ns_key = 'openid.ns'
- else:
- ns_key = 'openid.ns.' + alias
- args[ns_key] = ns_uri
-
- for (ns_uri, ns_key), value in self.args.iteritems():
- key = self.getKey(ns_uri, ns_key)
- args[key] = value.encode('UTF-8')
-
- return args
-
- def toArgs(self):
- """Return all namespaced arguments, failing if any
- non-namespaced arguments exist."""
- # FIXME - undocumented exception
- post_args = self.toPostArgs()
- kvargs = {}
- for k, v in post_args.iteritems():
- if not k.startswith('openid.'):
- raise ValueError(
- 'This message can only be encoded as a POST, because it '
- 'contains arguments that are not prefixed with "openid."')
- else:
- kvargs[k[7:]] = v
-
- return kvargs
-
- def toFormMarkup(self, action_url, form_tag_attrs=None,
- submit_text="Continue"):
- """Generate HTML form markup that contains the values in this
- message, to be HTTP POSTed as x-www-form-urlencoded UTF-8.
-
- @param action_url: The URL to which the form will be POSTed
- @type action_url: str
-
- @param form_tag_attrs: Dictionary of attributes to be added to
- the form tag. 'accept-charset' and 'enctype' have defaults
- that can be overridden. If a value is supplied for
- 'action' or 'method', it will be replaced.
- @type form_tag_attrs: {unicode: unicode}
-
- @param submit_text: The text that will appear on the submit
- button for this form.
- @type submit_text: unicode
-
- @returns: A string containing (X)HTML markup for a form that
- encodes the values in this Message object.
- @rtype: str or unicode
- """
- if ElementTree is None:
- raise RuntimeError('This function requires ElementTree.')
-
- assert action_url is not None
-
- form = ElementTree.Element('form')
-
- if form_tag_attrs:
- for name, attr in form_tag_attrs.iteritems():
- form.attrib[name] = attr
-
- form.attrib['action'] = action_url
- form.attrib['method'] = 'post'
- form.attrib['accept-charset'] = 'UTF-8'
- form.attrib['enctype'] = 'application/x-www-form-urlencoded'
-
- for name, value in self.toPostArgs().iteritems():
- attrs = {'type': 'hidden',
- 'name': name,
- 'value': value}
- form.append(ElementTree.Element('input', attrs))
-
- submit = ElementTree.Element(
- 'input', {'type':'submit', 'value':submit_text})
- form.append(submit)
-
- return ElementTree.tostring(form)
-
- def toURL(self, base_url):
- """Generate a GET URL with the parameters in this message
- attached as query parameters."""
- return oidutil.appendArgs(base_url, self.toPostArgs())
-
- def toKVForm(self):
- """Generate a KVForm string that contains the parameters in
- this message. This will fail if the message contains arguments
- outside of the 'openid.' prefix.
- """
- return kvform.dictToKV(self.toArgs())
-
- def toURLEncoded(self):
- """Generate an x-www-urlencoded string"""
- args = self.toPostArgs().items()
- args.sort()
- return urllib.urlencode(args)
-
- def _fixNS(self, namespace):
- """Convert an input value into the internally used values of
- this object
-
- @param namespace: The string or constant to convert
- @type namespace: str or unicode or BARE_NS or OPENID_NS
- """
- if namespace == OPENID_NS:
- if self._openid_ns_uri is None:
- raise UndefinedOpenIDNamespace('OpenID namespace not set')
- else:
- namespace = self._openid_ns_uri
-
- if namespace != BARE_NS and type(namespace) not in [str, unicode]:
- raise TypeError(
- "Namespace must be BARE_NS, OPENID_NS or a string. got %r"
- % (namespace,))
-
- if namespace != BARE_NS and ':' not in namespace:
- fmt = 'OpenID 2.0 namespace identifiers SHOULD be URIs. Got %r'
- warnings.warn(fmt % (namespace,), DeprecationWarning)
-
- if namespace == 'sreg':
- fmt = 'Using %r instead of "sreg" as namespace'
- warnings.warn(fmt % (SREG_URI,), DeprecationWarning,)
- return SREG_URI
-
- return namespace
-
- def hasKey(self, namespace, ns_key):
- namespace = self._fixNS(namespace)
- return (namespace, ns_key) in self.args
-
- def getKey(self, namespace, ns_key):
- """Get the key for a particular namespaced argument"""
- namespace = self._fixNS(namespace)
- if namespace == BARE_NS:
- return ns_key
-
- ns_alias = self.namespaces.getAlias(namespace)
-
- # No alias is defined, so no key can exist
- if ns_alias is None:
- return None
-
- if ns_alias == NULL_NAMESPACE:
- tail = ns_key
- else:
- tail = '%s.%s' % (ns_alias, ns_key)
-
- return 'openid.' + tail
-
- def getArg(self, namespace, key, default=None):
- """Get a value for a namespaced key.
-
- @param namespace: The namespace in the message for this key
- @type namespace: str
-
- @param key: The key to get within this namespace
- @type key: str
-
- @param default: The value to use if this key is absent from
- this message. Using the special value
- openid.message.no_default will result in this method
- raising a KeyError instead of returning the default.
-
- @rtype: str or the type of default
- @raises KeyError: if default is no_default
- @raises UndefinedOpenIDNamespace: if the message has not yet
- had an OpenID namespace set
- """
- namespace = self._fixNS(namespace)
- args_key = (namespace, key)
- try:
- return self.args[args_key]
- except KeyError:
- if default is no_default:
- raise KeyError((namespace, key))
- else:
- return default
-
- def getArgs(self, namespace):
- """Get the arguments that are defined for this namespace URI
-
- @returns: mapping from namespaced keys to values
- @returntype: dict
- """
- namespace = self._fixNS(namespace)
- return dict([
- (ns_key, value)
- for ((pair_ns, ns_key), value)
- in self.args.iteritems()
- if pair_ns == namespace
- ])
-
- def updateArgs(self, namespace, updates):
- """Set multiple key/value pairs in one call
-
- @param updates: The values to set
- @type updates: {unicode:unicode}
- """
- namespace = self._fixNS(namespace)
- for k, v in updates.iteritems():
- self.setArg(namespace, k, v)
-
- def setArg(self, namespace, key, value):
- """Set a single argument in this namespace"""
- assert key is not None
- assert value is not None
- namespace = self._fixNS(namespace)
- self.args[(namespace, key)] = value
- if not (namespace is BARE_NS):
- self.namespaces.add(namespace)
-
- def delArg(self, namespace, key):
- namespace = self._fixNS(namespace)
- del self.args[(namespace, key)]
-
- def __repr__(self):
- return "<%s.%s %r>" % (self.__class__.__module__,
- self.__class__.__name__,
- self.args)
-
- def __eq__(self, other):
- return self.args == other.args
-
-
- def __ne__(self, other):
- return not (self == other)
-
-
- def getAliasedArg(self, aliased_key, default=None):
- if aliased_key == 'ns':
- return self.getOpenIDNamespace()
-
- if aliased_key.startswith('ns.'):
- uri = self.namespaces.getNamespaceURI(aliased_key[3:])
- if uri is None:
- if default == no_default:
- raise KeyError
- else:
- return default
- else:
- return uri
-
- try:
- alias, key = aliased_key.split('.', 1)
- except ValueError:
- # need more than x values to unpack
- ns = None
- else:
- ns = self.namespaces.getNamespaceURI(alias)
-
- if ns is None:
- key = aliased_key
- ns = self.getOpenIDNamespace()
-
- return self.getArg(ns, key, default)
-
-class NamespaceMap(object):
- """Maintains a bijective map between namespace uris and aliases.
- """
- def __init__(self):
- self.alias_to_namespace = {}
- self.namespace_to_alias = {}
- self.implicit_namespaces = []
-
- def getAlias(self, namespace_uri):
- return self.namespace_to_alias.get(namespace_uri)
-
- def getNamespaceURI(self, alias):
- return self.alias_to_namespace.get(alias)
-
- def iterNamespaceURIs(self):
- """Return an iterator over the namespace URIs"""
- return iter(self.namespace_to_alias)
-
- def iterAliases(self):
- """Return an iterator over the aliases"""
- return iter(self.alias_to_namespace)
-
- def iteritems(self):
- """Iterate over the mapping
-
- @returns: iterator of (namespace_uri, alias)
- """
- return self.namespace_to_alias.iteritems()
-
- def addAlias(self, namespace_uri, desired_alias, implicit=False):
- """Add an alias from this namespace URI to the desired alias
- """
- # Check that desired_alias is not an openid protocol field as
- # per the spec.
- assert desired_alias not in OPENID_PROTOCOL_FIELDS, \
- "%r is not an allowed namespace alias" % (desired_alias,)
-
- # Check that desired_alias does not contain a period as per
- # the spec.
- if type(desired_alias) in [str, unicode]:
- assert '.' not in desired_alias, \
- "%r must not contain a dot" % (desired_alias,)
-
- # Check that there is not a namespace already defined for
- # the desired alias
- current_namespace_uri = self.alias_to_namespace.get(desired_alias)
- if (current_namespace_uri is not None
- and current_namespace_uri != namespace_uri):
-
- fmt = ('Cannot map %r to alias %r. '
- '%r is already mapped to alias %r')
-
- msg = fmt % (
- namespace_uri,
- desired_alias,
- current_namespace_uri,
- desired_alias)
- raise KeyError(msg)
-
- # Check that there is not already a (different) alias for
- # this namespace URI
- alias = self.namespace_to_alias.get(namespace_uri)
- if alias is not None and alias != desired_alias:
- fmt = ('Cannot map %r to alias %r. '
- 'It is already mapped to alias %r')
- raise KeyError(fmt % (namespace_uri, desired_alias, alias))
-
- assert (desired_alias == NULL_NAMESPACE or
- type(desired_alias) in [str, unicode]), repr(desired_alias)
- assert namespace_uri not in self.implicit_namespaces
- self.alias_to_namespace[desired_alias] = namespace_uri
- self.namespace_to_alias[namespace_uri] = desired_alias
- if implicit:
- self.implicit_namespaces.append(namespace_uri)
- return desired_alias
-
- def add(self, namespace_uri):
- """Add this namespace URI to the mapping, without caring what
- alias it ends up with"""
- # See if this namespace is already mapped to an alias
- alias = self.namespace_to_alias.get(namespace_uri)
- if alias is not None:
- return alias
-
- # Fall back to generating a numerical alias
- i = 0
- while True:
- alias = 'ext' + str(i)
- try:
- self.addAlias(namespace_uri, alias)
- except KeyError:
- i += 1
- else:
- return alias
-
- assert False, "Not reached"
-
- def isDefined(self, namespace_uri):
- return namespace_uri in self.namespace_to_alias
-
- def __contains__(self, namespace_uri):
- return self.isDefined(namespace_uri)
-
- def isImplicit(self, namespace_uri):
- return namespace_uri in self.implicit_namespaces
diff --git a/askbot/deps/openid/oidutil.py b/askbot/deps/openid/oidutil.py
deleted file mode 100644
index 593fdcf9..00000000
--- a/askbot/deps/openid/oidutil.py
+++ /dev/null
@@ -1,190 +0,0 @@
-"""This module contains general utility code that is used throughout
-the library.
-
-For users of this library, the C{L{log}} function is probably the most
-interesting.
-"""
-
-__all__ = ['log', 'appendArgs', 'toBase64', 'fromBase64', 'autoSubmitHTML']
-
-import binascii
-import sys
-import urlparse
-
-from urllib import urlencode
-
-elementtree_modules = [
- 'lxml.etree',
- 'xml.etree.cElementTree',
- 'xml.etree.ElementTree',
- 'cElementTree',
- 'elementtree.ElementTree',
- ]
-
-def autoSubmitHTML(form, title='OpenID transaction in progress'):
- return """
-<html>
-<head>
- <title>%s</title>
-</head>
-<body onload="document.forms[0].submit();">
-%s
-<script>
-var elements = document.forms[0].elements;
-for (var i = 0; i < elements.length; i++) {
- elements[i].style.display = "none";
-}
-</script>
-</body>
-</html>
-""" % (title, form)
-
-def importElementTree(module_names=None):
- """Find a working ElementTree implementation, trying the standard
- places that such a thing might show up.
-
- >>> ElementTree = importElementTree()
-
- @param module_names: The names of modules to try to use as
- ElementTree. Defaults to C{L{elementtree_modules}}
-
- @returns: An ElementTree module
- """
- if module_names is None:
- module_names = elementtree_modules
-
- for mod_name in module_names:
- try:
- ElementTree = __import__(mod_name, None, None, ['unused'])
- except ImportError:
- pass
- else:
- # Make sure it can actually parse XML
- try:
- ElementTree.XML('<unused/>')
- except (SystemExit, MemoryError, AssertionError):
- raise
- except:
- why = sys.exc_info()[1]
- log('Not using ElementTree library %r because it failed to '
- 'parse a trivial document: %s' % (mod_name, why))
- else:
- return ElementTree
- else:
- raise ImportError('No ElementTree library found. '
- 'You may need to install one. '
- 'Tried importing %r' % (module_names,)
- )
-
-def log(message, level=0):
- """Handle a log message from the OpenID library.
-
- This implementation writes the string it to C{sys.stderr},
- followed by a newline.
-
- Currently, the library does not use the second parameter to this
- function, but that may change in the future.
-
- To install your own logging hook::
-
- from askbot.deps.openid import oidutil
-
- def myLoggingFunction(message, level):
- ...
-
- oidutil.log = myLoggingFunction
-
- @param message: A string containing a debugging message from the
- OpenID library
- @type message: str
-
- @param level: The severity of the log message. This parameter is
- currently unused, but in the future, the library may indicate
- more important information with a higher level value.
- @type level: int or None
-
- @returns: Nothing.
- """
-
- sys.stderr.write(message)
- sys.stderr.write('\n')
-
-def appendArgs(url, args):
- """Append query arguments to a HTTP(s) URL. If the URL already has
- query arguemtns, these arguments will be added, and the existing
- arguments will be preserved. Duplicate arguments will not be
- detected or collapsed (both will appear in the output).
-
- @param url: The url to which the arguments will be appended
- @type url: str
-
- @param args: The query arguments to add to the URL. If a
- dictionary is passed, the items will be sorted before
- appending them to the URL. If a sequence of pairs is passed,
- the order of the sequence will be preserved.
- @type args: A dictionary from string to string, or a sequence of
- pairs of strings.
-
- @returns: The URL with the parameters added
- @rtype: str
- """
- if hasattr(args, 'items'):
- args = args.items()
- args.sort()
- else:
- args = list(args)
-
- if len(args) == 0:
- return url
-
- if '?' in url:
- sep = '&'
- else:
- sep = '?'
-
- # Map unicode to UTF-8 if present. Do not make any assumptions
- # about the encodings of plain bytes (str).
- i = 0
- for k, v in args:
- if type(k) is not str:
- k = k.encode('UTF-8')
-
- if type(v) is not str:
- v = v.encode('UTF-8')
-
- args[i] = (k, v)
- i += 1
-
- return '%s%s%s' % (url, sep, urlencode(args))
-
-def toBase64(s):
- """Represent string s as base64, omitting newlines"""
- return binascii.b2a_base64(s)[:-1]
-
-def fromBase64(s):
- try:
- return binascii.a2b_base64(s)
- except binascii.Error, why:
- # Convert to a common exception type
- raise ValueError(why[0])
-
-class Symbol(object):
- """This class implements an object that compares equal to others
- of the same type that have the same name. These are distict from
- str or unicode objects.
- """
-
- def __init__(self, name):
- self.name = name
-
- def __eq__(self, other):
- return type(self) is type(other) and self.name == other.name
-
- def __ne__(self, other):
- return not (self == other)
-
- def __hash__(self):
- return hash((self.__class__, self.name))
-
- def __repr__(self):
- return '<Symbol %s>' % (self.name,)
diff --git a/askbot/deps/openid/server/__init__.py b/askbot/deps/openid/server/__init__.py
deleted file mode 100644
index c8fde257..00000000
--- a/askbot/deps/openid/server/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-This package contains the portions of the library used only when
-implementing an OpenID server. See L{openid.server.server}.
-"""
-
-__all__ = ['server', 'trustroot']
diff --git a/askbot/deps/openid/server/server.py b/askbot/deps/openid/server/server.py
deleted file mode 100644
index 6d94249b..00000000
--- a/askbot/deps/openid/server/server.py
+++ /dev/null
@@ -1,1849 +0,0 @@
-# -*- test-case-name: openid.test.test_server -*-
-"""OpenID server protocol and logic.
-
-Overview
-========
-
- An OpenID server must perform three tasks:
-
- 1. Examine the incoming request to determine its nature and validity.
-
- 2. Make a decision about how to respond to this request.
-
- 3. Format the response according to the protocol.
-
- The first and last of these tasks may performed by
- the L{decodeRequest<Server.decodeRequest>} and
- L{encodeResponse<Server.encodeResponse>} methods of the
- L{Server} object. Who gets to do the intermediate task -- deciding
- how to respond to the request -- will depend on what type of request it
- is.
-
- If it's a request to authenticate a user (a X{C{checkid_setup}} or
- X{C{checkid_immediate}} request), you need to decide if you will assert
- that this user may claim the identity in question. Exactly how you do
- that is a matter of application policy, but it generally involves making
- sure the user has an account with your system and is logged in, checking
- to see if that identity is hers to claim, and verifying with the user that
- she does consent to releasing that information to the party making the
- request.
-
- Examine the properties of the L{CheckIDRequest} object, optionally
- check L{CheckIDRequest.returnToVerified}, and and when you've come
- to a decision, form a response by calling L{CheckIDRequest.answer}.
-
- Other types of requests relate to establishing associations between client
- and server and verifying the authenticity of previous communications.
- L{Server} contains all the logic and data necessary to respond to
- such requests; just pass the request to L{Server.handleRequest}.
-
-
-OpenID Extensions
-=================
-
- Do you want to provide other information for your users
- in addition to authentication? Version 2.0 of the OpenID
- protocol allows consumers to add extensions to their requests.
- For example, with sites using the U{Simple Registration
- Extension<http://openid.net/specs/openid-simple-registration-extension-1_0.html>},
- a user can agree to have their nickname and e-mail address sent to a
- site when they sign up.
-
- Since extensions do not change the way OpenID authentication works,
- code to handle extension requests may be completely separate from the
- L{OpenIDRequest} class here. But you'll likely want data sent back by
- your extension to be signed. L{OpenIDResponse} provides methods with
- which you can add data to it which can be signed with the other data in
- the OpenID signature.
-
- For example::
-
- # when request is a checkid_* request
- response = request.answer(True)
- # this will a signed 'openid.sreg.timezone' parameter to the response
- # as well as a namespace declaration for the openid.sreg namespace
- response.fields.setArg('http://openid.net/sreg/1.0', 'timezone', 'America/Los_Angeles')
-
- There are helper modules for a number of extensions, including
- L{Attribute Exchange<openid.extensions.ax>},
- L{PAPE<openid.extensions.pape>}, and
- L{Simple Registration<openid.extensions.sreg>} in the L{openid.extensions}
- package.
-
-Stores
-======
-
- The OpenID server needs to maintain state between requests in order
- to function. Its mechanism for doing this is called a store. The
- store interface is defined in C{L{openid.store.interface.OpenIDStore}}.
- Additionally, several concrete store implementations are provided, so that
- most sites won't need to implement a custom store. For a store backed
- by flat files on disk, see C{L{openid.store.filestore.FileOpenIDStore}}.
- For stores based on MySQL or SQLite, see the C{L{openid.store.sqlstore}}
- module.
-
-
-Upgrading
-=========
-
-From 1.0 to 1.1
----------------
-
- The keys by which a server looks up associations in its store have changed
- in version 1.2 of this library. If your store has entries created from
- version 1.0 code, you should empty it.
-
-From 1.1 to 2.0
----------------
-
- One of the additions to the OpenID protocol was a specified nonce
- format for one-way nonces. As a result, the nonce table in the store
- has changed. You'll need to run contrib/upgrade-store-1.1-to-2.0 to
- upgrade your store, or you'll encounter errors about the wrong number
- of columns in the oid_nonces table.
-
- If you've written your own custom store or code that interacts
- directly with it, you'll need to review the change notes in
- L{openid.store.interface}.
-
-@group Requests: OpenIDRequest, AssociateRequest, CheckIDRequest,
- CheckAuthRequest
-
-@group Responses: OpenIDResponse
-
-@group HTTP Codes: HTTP_OK, HTTP_REDIRECT, HTTP_ERROR
-
-@group Response Encodings: ENCODE_KVFORM, ENCODE_HTML_FORM, ENCODE_URL
-"""
-
-import time, warnings
-from copy import deepcopy
-
-from askbot.deps.openid import cryptutil
-from askbot.deps.openid import oidutil
-from askbot.deps.openid import kvform
-from askbot.deps.openid.dh import DiffieHellman
-from askbot.deps.openid.store.nonce import mkNonce
-from askbot.deps.openid.server.trustroot import TrustRoot, verifyReturnTo
-from askbot.deps.openid.association import Association, default_negotiator, getSecretSize
-from askbot.deps.openid.message import Message, InvalidOpenIDNamespace, \
- OPENID_NS, OPENID2_NS, IDENTIFIER_SELECT, OPENID1_URL_LIMIT
-from askbot.deps.openid.urinorm import urinorm
-
-HTTP_OK = 200
-HTTP_REDIRECT = 302
-HTTP_ERROR = 400
-
-BROWSER_REQUEST_MODES = ['checkid_setup', 'checkid_immediate']
-
-ENCODE_KVFORM = ('kvform',)
-ENCODE_URL = ('URL/redirect',)
-ENCODE_HTML_FORM = ('HTML form',)
-
-UNUSED = None
-
-class OpenIDRequest(object):
- """I represent an incoming OpenID request.
-
- @cvar mode: the C{X{openid.mode}} of this request.
- @type mode: str
- """
- mode = None
-
-
-class CheckAuthRequest(OpenIDRequest):
- """A request to verify the validity of a previous response.
-
- @cvar mode: "X{C{check_authentication}}"
- @type mode: str
-
- @ivar assoc_handle: The X{association handle} the response was signed with.
- @type assoc_handle: str
- @ivar signed: The message with the signature which wants checking.
- @type signed: L{Message}
-
- @ivar invalidate_handle: An X{association handle} the client is asking
- about the validity of. Optional, may be C{None}.
- @type invalidate_handle: str
-
- @see: U{OpenID Specs, Mode: check_authentication
- <http://openid.net/specs.bml#mode-check_authentication>}
- """
- mode = "check_authentication"
-
- required_fields = ["identity", "return_to", "response_nonce"]
-
- def __init__(self, assoc_handle, signed, invalidate_handle=None):
- """Construct me.
-
- These parameters are assigned directly as class attributes, see
- my L{class documentation<CheckAuthRequest>} for their descriptions.
-
- @type assoc_handle: str
- @type signed: L{Message}
- @type invalidate_handle: str
- """
- self.assoc_handle = assoc_handle
- self.signed = signed
- self.invalidate_handle = invalidate_handle
- self.namespace = OPENID2_NS
-
-
- def fromMessage(klass, message, op_endpoint=UNUSED):
- """Construct me from an OpenID Message.
-
- @param message: An OpenID check_authentication Message
- @type message: L{openid.message.Message}
-
- @returntype: L{CheckAuthRequest}
- """
- self = klass.__new__(klass)
- self.message = message
- self.namespace = message.getOpenIDNamespace()
- self.assoc_handle = message.getArg(OPENID_NS, 'assoc_handle')
- self.sig = message.getArg(OPENID_NS, 'sig')
-
- if (self.assoc_handle is None or
- self.sig is None):
- fmt = "%s request missing required parameter from message %s"
- raise ProtocolError(
- message, text=fmt % (self.mode, message))
-
- self.invalidate_handle = message.getArg(OPENID_NS, 'invalidate_handle')
-
- self.signed = message.copy()
- # openid.mode is currently check_authentication because
- # that's the mode of this request. But the signature
- # was made on something with a different openid.mode.
- # http://article.gmane.org/gmane.comp.web.openid.general/537
- if self.signed.hasKey(OPENID_NS, "mode"):
- self.signed.setArg(OPENID_NS, "mode", "id_res")
-
- return self
-
- fromMessage = classmethod(fromMessage)
-
- def answer(self, signatory):
- """Respond to this request.
-
- Given a L{Signatory}, I can check the validity of the signature and
- the X{C{invalidate_handle}}.
-
- @param signatory: The L{Signatory} to use to check the signature.
- @type signatory: L{Signatory}
-
- @returns: A response with an X{C{is_valid}} (and, if
- appropriate X{C{invalidate_handle}}) field.
- @returntype: L{OpenIDResponse}
- """
- is_valid = signatory.verify(self.assoc_handle, self.signed)
- # Now invalidate that assoc_handle so it this checkAuth message cannot
- # be replayed.
- signatory.invalidate(self.assoc_handle, dumb=True)
- response = OpenIDResponse(self)
- valid_str = (is_valid and "true") or "false"
- response.fields.setArg(OPENID_NS, 'is_valid', valid_str)
-
- if self.invalidate_handle:
- assoc = signatory.getAssociation(self.invalidate_handle, dumb=False)
- if not assoc:
- response.fields.setArg(
- OPENID_NS, 'invalidate_handle', self.invalidate_handle)
- return response
-
-
- def __str__(self):
- if self.invalidate_handle:
- ih = " invalidate? %r" % (self.invalidate_handle,)
- else:
- ih = ""
- s = "<%s handle: %r sig: %r: signed: %r%s>" % (
- self.__class__.__name__, self.assoc_handle,
- self.sig, self.signed, ih)
- return s
-
-
-class PlainTextServerSession(object):
- """An object that knows how to handle association requests with no
- session type.
-
- @cvar session_type: The session_type for this association
- session. There is no type defined for plain-text in the OpenID
- specification, so we use 'no-encryption'.
- @type session_type: str
-
- @see: U{OpenID Specs, Mode: associate
- <http://openid.net/specs.bml#mode-associate>}
- @see: AssociateRequest
- """
- session_type = 'no-encryption'
- allowed_assoc_types = ['HMAC-SHA1', 'HMAC-SHA256']
-
- def fromMessage(cls, unused_request):
- return cls()
-
- fromMessage = classmethod(fromMessage)
-
- def answer(self, secret):
- return {'mac_key': oidutil.toBase64(secret)}
-
-
-class DiffieHellmanSHA1ServerSession(object):
- """An object that knows how to handle association requests with the
- Diffie-Hellman session type.
-
- @cvar session_type: The session_type for this association
- session.
- @type session_type: str
-
- @ivar dh: The Diffie-Hellman algorithm values for this request
- @type dh: DiffieHellman
-
- @ivar consumer_pubkey: The public key sent by the consumer in the
- associate request
- @type consumer_pubkey: long
-
- @see: U{OpenID Specs, Mode: associate
- <http://openid.net/specs.bml#mode-associate>}
- @see: AssociateRequest
- """
- session_type = 'DH-SHA1'
- hash_func = staticmethod(cryptutil.sha1)
- allowed_assoc_types = ['HMAC-SHA1']
-
- def __init__(self, dh, consumer_pubkey):
- self.dh = dh
- self.consumer_pubkey = consumer_pubkey
-
- def fromMessage(cls, message):
- """
- @param message: The associate request message
- @type message: openid.message.Message
-
- @returntype: L{DiffieHellmanSHA1ServerSession}
-
- @raises ProtocolError: When parameters required to establish the
- session are missing.
- """
- dh_modulus = message.getArg(OPENID_NS, 'dh_modulus')
- dh_gen = message.getArg(OPENID_NS, 'dh_gen')
- if (dh_modulus is None and dh_gen is not None or
- dh_gen is None and dh_modulus is not None):
-
- if dh_modulus is None:
- missing = 'modulus'
- else:
- missing = 'generator'
-
- raise ProtocolError(message,
- 'If non-default modulus or generator is '
- 'supplied, both must be supplied. Missing %s'
- % (missing,))
-
- if dh_modulus or dh_gen:
- dh_modulus = cryptutil.base64ToLong(dh_modulus)
- dh_gen = cryptutil.base64ToLong(dh_gen)
- dh = DiffieHellman(dh_modulus, dh_gen)
- else:
- dh = DiffieHellman.fromDefaults()
-
- consumer_pubkey = message.getArg(OPENID_NS, 'dh_consumer_public')
- if consumer_pubkey is None:
- raise ProtocolError(message, "Public key for DH-SHA1 session "
- "not found in message %s" % (message,))
-
- consumer_pubkey = cryptutil.base64ToLong(consumer_pubkey)
-
- return cls(dh, consumer_pubkey)
-
- fromMessage = classmethod(fromMessage)
-
- def answer(self, secret):
- mac_key = self.dh.xorSecret(self.consumer_pubkey,
- secret,
- self.hash_func)
- return {
- 'dh_server_public': cryptutil.longToBase64(self.dh.public),
- 'enc_mac_key': oidutil.toBase64(mac_key),
- }
-
-class DiffieHellmanSHA256ServerSession(DiffieHellmanSHA1ServerSession):
- session_type = 'DH-SHA256'
- hash_func = staticmethod(cryptutil.sha256)
- allowed_assoc_types = ['HMAC-SHA256']
-
-class AssociateRequest(OpenIDRequest):
- """A request to establish an X{association}.
-
- @cvar mode: "X{C{check_authentication}}"
- @type mode: str
-
- @ivar assoc_type: The type of association. The protocol currently only
- defines one value for this, "X{C{HMAC-SHA1}}".
- @type assoc_type: str
-
- @ivar session: An object that knows how to handle association
- requests of a certain type.
-
- @see: U{OpenID Specs, Mode: associate
- <http://openid.net/specs.bml#mode-associate>}
- """
-
- mode = "associate"
-
- session_classes = {
- 'no-encryption': PlainTextServerSession,
- 'DH-SHA1': DiffieHellmanSHA1ServerSession,
- 'DH-SHA256': DiffieHellmanSHA256ServerSession,
- }
-
- def __init__(self, session, assoc_type):
- """Construct me.
-
- The session is assigned directly as a class attribute. See my
- L{class documentation<AssociateRequest>} for its description.
- """
- super(AssociateRequest, self).__init__()
- self.session = session
- self.assoc_type = assoc_type
- self.namespace = OPENID2_NS
-
-
- def fromMessage(klass, message, op_endpoint=UNUSED):
- """Construct me from an OpenID Message.
-
- @param message: The OpenID associate request
- @type message: openid.message.Message
-
- @returntype: L{AssociateRequest}
- """
- if message.isOpenID1():
- session_type = message.getArg(OPENID_NS, 'session_type')
- if session_type == 'no-encryption':
- oidutil.log('Received OpenID 1 request with a no-encryption '
- 'assocaition session type. Continuing anyway.')
- elif not session_type:
- session_type = 'no-encryption'
- else:
- session_type = message.getArg(OPENID2_NS, 'session_type')
- if session_type is None:
- raise ProtocolError(message,
- text="session_type missing from request")
-
- try:
- session_class = klass.session_classes[session_type]
- except KeyError:
- raise ProtocolError(message,
- "Unknown session type %r" % (session_type,))
-
- try:
- session = session_class.fromMessage(message)
- except ValueError, why:
- raise ProtocolError(message, 'Error parsing %s session: %s' %
- (session_class.session_type, why[0]))
-
- assoc_type = message.getArg(OPENID_NS, 'assoc_type', 'HMAC-SHA1')
- if assoc_type not in session.allowed_assoc_types:
- fmt = 'Session type %s does not support association type %s'
- raise ProtocolError(message, fmt % (session_type, assoc_type))
-
- self = klass(session, assoc_type)
- self.message = message
- self.namespace = message.getOpenIDNamespace()
- return self
-
- fromMessage = classmethod(fromMessage)
-
- def answer(self, assoc):
- """Respond to this request with an X{association}.
-
- @param assoc: The association to send back.
- @type assoc: L{openid.association.Association}
-
- @returns: A response with the association information, encrypted
- to the consumer's X{public key} if appropriate.
- @returntype: L{OpenIDResponse}
- """
- response = OpenIDResponse(self)
- response.fields.updateArgs(OPENID_NS, {
- 'expires_in': '%d' % (assoc.getExpiresIn(),),
- 'assoc_type': self.assoc_type,
- 'assoc_handle': assoc.handle,
- })
- response.fields.updateArgs(OPENID_NS,
- self.session.answer(assoc.secret))
-
- if not (self.session.session_type == 'no-encryption' and
- self.message.isOpenID1()):
- # The session type "no-encryption" did not have a name
- # in OpenID v1, it was just omitted.
- response.fields.setArg(
- OPENID_NS, 'session_type', self.session.session_type)
-
- return response
-
- def answerUnsupported(self, message, preferred_association_type=None,
- preferred_session_type=None):
- """Respond to this request indicating that the association
- type or association session type is not supported."""
- if self.message.isOpenID1():
- raise ProtocolError(self.message)
-
- response = OpenIDResponse(self)
- response.fields.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- response.fields.setArg(OPENID_NS, 'error', message)
-
- if preferred_association_type:
- response.fields.setArg(
- OPENID_NS, 'assoc_type', preferred_association_type)
-
- if preferred_session_type:
- response.fields.setArg(
- OPENID_NS, 'session_type', preferred_session_type)
-
- return response
-
-class CheckIDRequest(OpenIDRequest):
- """A request to confirm the identity of a user.
-
- This class handles requests for openid modes X{C{checkid_immediate}}
- and X{C{checkid_setup}}.
-
- @cvar mode: "X{C{checkid_immediate}}" or "X{C{checkid_setup}}"
- @type mode: str
-
- @ivar immediate: Is this an immediate-mode request?
- @type immediate: bool
-
- @ivar identity: The OP-local identifier being checked.
- @type identity: str
-
- @ivar claimed_id: The claimed identifier. Not present in OpenID 1.x
- messages.
- @type claimed_id: str
-
- @ivar trust_root: "Are you Frank?" asks the checkid request. "Who wants
- to know?" C{trust_root}, that's who. This URL identifies the party
- making the request, and the user will use that to make her decision
- about what answer she trusts them to have. Referred to as "realm" in
- OpenID 2.0.
- @type trust_root: str
-
- @ivar return_to: The URL to send the user agent back to to reply to this
- request.
- @type return_to: str
-
- @ivar assoc_handle: Provided in smart mode requests, a handle for a
- previously established association. C{None} for dumb mode requests.
- @type assoc_handle: str
- """
-
- def __init__(self, identity, return_to, trust_root=None, immediate=False,
- assoc_handle=None, op_endpoint=None, claimed_id=None):
- """Construct me.
-
- These parameters are assigned directly as class attributes, see
- my L{class documentation<CheckIDRequest>} for their descriptions.
-
- @raises MalformedReturnURL: When the C{return_to} URL is not a URL.
- """
- self.assoc_handle = assoc_handle
- self.identity = identity
- self.claimed_id = claimed_id or identity
- self.return_to = return_to
- self.trust_root = trust_root or return_to
- self.op_endpoint = op_endpoint
- assert self.op_endpoint is not None
- if immediate:
- self.immediate = True
- self.mode = "checkid_immediate"
- else:
- self.immediate = False
- self.mode = "checkid_setup"
-
- if self.return_to is not None and \
- not TrustRoot.parse(self.return_to):
- raise MalformedReturnURL(None, self.return_to)
- if not self.trustRootValid():
- raise UntrustedReturnURL(None, self.return_to, self.trust_root)
- self.message = None
-
- def _getNamespace(self):
- warnings.warn('The "namespace" attribute of CheckIDRequest objects '
- 'is deprecated. Use "message.getOpenIDNamespace()" '
- 'instead', DeprecationWarning, stacklevel=2)
- return self.message.getOpenIDNamespace()
-
- namespace = property(_getNamespace)
-
- def fromMessage(klass, message, op_endpoint):
- """Construct me from an OpenID message.
-
- @raises ProtocolError: When not all required parameters are present
- in the message.
-
- @raises MalformedReturnURL: When the C{return_to} URL is not a URL.
-
- @raises UntrustedReturnURL: When the C{return_to} URL is outside
- the C{trust_root}.
-
- @param message: An OpenID checkid_* request Message
- @type message: openid.message.Message
-
- @param op_endpoint: The endpoint URL of the server that this
- message was sent to.
- @type op_endpoint: str
-
- @returntype: L{CheckIDRequest}
- """
- self = klass.__new__(klass)
- self.message = message
- self.op_endpoint = op_endpoint
- mode = message.getArg(OPENID_NS, 'mode')
- if mode == "checkid_immediate":
- self.immediate = True
- self.mode = "checkid_immediate"
- else:
- self.immediate = False
- self.mode = "checkid_setup"
-
- self.return_to = message.getArg(OPENID_NS, 'return_to')
- if message.isOpenID1() and not self.return_to:
- fmt = "Missing required field 'return_to' from %r"
- raise ProtocolError(message, text=fmt % (message,))
-
- self.identity = message.getArg(OPENID_NS, 'identity')
- self.claimed_id = message.getArg(OPENID_NS, 'claimed_id')
- if message.isOpenID1():
- if self.identity is None:
- s = "OpenID 1 message did not contain openid.identity"
- raise ProtocolError(message, text=s)
- else:
- if self.identity and not self.claimed_id:
- s = ("OpenID 2.0 message contained openid.identity but not "
- "claimed_id")
- raise ProtocolError(message, text=s)
- elif self.claimed_id and not self.identity:
- s = ("OpenID 2.0 message contained openid.claimed_id but not "
- "identity")
- raise ProtocolError(message, text=s)
-
- # There's a case for making self.trust_root be a TrustRoot
- # here. But if TrustRoot isn't currently part of the "public" API,
- # I'm not sure it's worth doing.
-
- if message.isOpenID1():
- trust_root_param = 'trust_root'
- else:
- trust_root_param = 'realm'
-
- # Using 'or' here is slightly different than sending a default
- # argument to getArg, as it will treat no value and an empty
- # string as equivalent.
- self.trust_root = (message.getArg(OPENID_NS, trust_root_param)
- or self.return_to)
-
- if not message.isOpenID1():
- if self.return_to is self.trust_root is None:
- raise ProtocolError(message, "openid.realm required when " +
- "openid.return_to absent")
-
- self.assoc_handle = message.getArg(OPENID_NS, 'assoc_handle')
-
- # Using TrustRoot.parse here is a bit misleading, as we're not
- # parsing return_to as a trust root at all. However, valid URLs
- # are valid trust roots, so we can use this to get an idea if it
- # is a valid URL. Not all trust roots are valid return_to URLs,
- # however (particularly ones with wildcards), so this is still a
- # little sketchy.
- if self.return_to is not None and \
- not TrustRoot.parse(self.return_to):
- raise MalformedReturnURL(message, self.return_to)
-
- # I first thought that checking to see if the return_to is within
- # the trust_root is premature here, a logic-not-decoding thing. But
- # it was argued that this is really part of data validation. A
- # request with an invalid trust_root/return_to is broken regardless of
- # application, right?
- if not self.trustRootValid():
- raise UntrustedReturnURL(message, self.return_to, self.trust_root)
-
- return self
-
- fromMessage = classmethod(fromMessage)
-
- def idSelect(self):
- """Is the identifier to be selected by the IDP?
-
- @returntype: bool
- """
- # So IDPs don't have to import the constant
- return self.identity == IDENTIFIER_SELECT
-
- def trustRootValid(self):
- """Is my return_to under my trust_root?
-
- @returntype: bool
- """
- if not self.trust_root:
- return True
- tr = TrustRoot.parse(self.trust_root)
- if tr is None:
- raise MalformedTrustRoot(self.message, self.trust_root)
-
- if self.return_to is not None:
- return tr.validateURL(self.return_to)
- else:
- return True
-
- def returnToVerified(self):
- """Does the relying party publish the return_to URL for this
- response under the realm? It is up to the provider to set a
- policy for what kinds of realms should be allowed. This
- return_to URL verification reduces vulnerability to data-theft
- attacks based on open proxies, cross-site-scripting, or open
- redirectors.
-
- This check should only be performed after making sure that the
- return_to URL matches the realm.
-
- @see: L{trustRootValid}
-
- @raises openid.yadis.discover.DiscoveryFailure: if the realm
- URL does not support Yadis discovery (and so does not
- support the verification process).
-
- @raises openid.fetchers.HTTPFetchingError: if the realm URL
- is not reachable. When this is the case, the RP may be hosted
- on the user's intranet.
-
- @returntype: bool
-
- @returns: True if the realm publishes a document with the
- return_to URL listed
-
- @since: 2.1.0
- """
- return verifyReturnTo(self.trust_root, self.return_to)
-
- def answer(self, allow, server_url=None, identity=None, claimed_id=None):
- """Respond to this request.
-
- @param allow: Allow this user to claim this identity, and allow the
- consumer to have this information?
- @type allow: bool
-
- @param server_url: DEPRECATED. Passing C{op_endpoint} to the
- L{Server} constructor makes this optional.
-
- When an OpenID 1.x immediate mode request does not succeed,
- it gets back a URL where the request may be carried out
- in a not-so-immediate fashion. Pass my URL in here (the
- fully qualified address of this server's endpoint, i.e.
- C{http://example.com/server}), and I will use it as a base for the
- URL for a new request.
-
- Optional for requests where C{CheckIDRequest.immediate} is C{False}
- or C{allow} is C{True}.
-
- @type server_url: str
-
- @param identity: The OP-local identifier to answer with. Only for use
- when the relying party requested identifier selection.
- @type identity: str or None
-
- @param claimed_id: The claimed identifier to answer with, for use
- with identifier selection in the case where the claimed identifier
- and the OP-local identifier differ, i.e. when the claimed_id uses
- delegation.
-
- If C{identity} is provided but this is not, C{claimed_id} will
- default to the value of C{identity}. When answering requests
- that did not ask for identifier selection, the response
- C{claimed_id} will default to that of the request.
-
- This parameter is new in OpenID 2.0.
- @type claimed_id: str or None
-
- @returntype: L{OpenIDResponse}
-
- @change: Version 2.0 deprecates C{server_url} and adds C{claimed_id}.
-
- @raises NoReturnError: when I do not have a return_to.
- """
- assert self.message is not None
-
- if not self.return_to:
- raise NoReturnToError
-
- if not server_url:
- if not self.message.isOpenID1() and not self.op_endpoint:
- # In other words, that warning I raised in Server.__init__?
- # You should pay attention to it now.
- raise RuntimeError("%s should be constructed with op_endpoint "
- "to respond to OpenID 2.0 messages." %
- (self,))
- server_url = self.op_endpoint
-
- if allow:
- mode = 'id_res'
- elif self.message.isOpenID1():
- if self.immediate:
- mode = 'id_res'
- else:
- mode = 'cancel'
- else:
- if self.immediate:
- mode = 'setup_needed'
- else:
- mode = 'cancel'
-
- response = OpenIDResponse(self)
-
- if claimed_id and self.message.isOpenID1():
- namespace = self.message.getOpenIDNamespace()
- raise VersionError("claimed_id is new in OpenID 2.0 and not "
- "available for %s" % (namespace,))
-
- if allow:
- if self.identity == IDENTIFIER_SELECT:
- if not identity:
- raise ValueError(
- "This request uses IdP-driven identifier selection."
- "You must supply an identifier in the response.")
- response_identity = identity
- response_claimed_id = claimed_id or identity
-
- elif self.identity:
- if identity and (self.identity != identity):
- normalized_request_identity = urinorm(self.identity)
- normalized_answer_identity = urinorm(identity)
-
- if (normalized_request_identity !=
- normalized_answer_identity):
- raise ValueError(
- "Request was for identity %r, cannot reply "
- "with identity %r" % (self.identity, identity))
-
- # The "identity" value in the response shall always be
- # the same as that in the request, otherwise the RP is
- # likely to not validate the response.
- response_identity = self.identity
- response_claimed_id = self.claimed_id
- else:
- if identity:
- raise ValueError(
- "This request specified no identity and you "
- "supplied %r" % (identity,))
- response_identity = None
-
- if self.message.isOpenID1() and response_identity is None:
- raise ValueError(
- "Request was an OpenID 1 request, so response must "
- "include an identifier."
- )
-
- response.fields.updateArgs(OPENID_NS, {
- 'mode': mode,
- 'return_to': self.return_to,
- 'response_nonce': mkNonce(),
- })
-
- if server_url:
- response.fields.setArg(OPENID_NS, 'op_endpoint', server_url)
-
- if response_identity is not None:
- response.fields.setArg(
- OPENID_NS, 'identity', response_identity)
- if self.message.isOpenID2():
- response.fields.setArg(
- OPENID_NS, 'claimed_id', response_claimed_id)
- else:
- response.fields.setArg(OPENID_NS, 'mode', mode)
- if self.immediate:
- if self.message.isOpenID1() and not server_url:
- raise ValueError("setup_url is required for allow=False "
- "in OpenID 1.x immediate mode.")
- # Make a new request just like me, but with immediate=False.
- setup_request = self.__class__(
- self.identity, self.return_to, self.trust_root,
- immediate=False, assoc_handle=self.assoc_handle,
- op_endpoint=self.op_endpoint, claimed_id=self.claimed_id)
-
- # XXX: This API is weird.
- setup_request.message = self.message
-
- setup_url = setup_request.encodeToURL(server_url)
- response.fields.setArg(OPENID_NS, 'user_setup_url', setup_url)
-
- return response
-
-
- def encodeToURL(self, server_url):
- """Encode this request as a URL to GET.
-
- @param server_url: The URL of the OpenID server to make this request of.
- @type server_url: str
-
- @returntype: str
-
- @raises NoReturnError: when I do not have a return_to.
- """
- if not self.return_to:
- raise NoReturnToError
-
- # Imported from the alternate reality where these classes are used
- # in both the client and server code, so Requests are Encodable too.
- # That's right, code imported from alternate realities all for the
- # love of you, id_res/user_setup_url.
- q = {'mode': self.mode,
- 'identity': self.identity,
- 'claimed_id': self.claimed_id,
- 'return_to': self.return_to}
- if self.trust_root:
- if self.message.isOpenID1():
- q['trust_root'] = self.trust_root
- else:
- q['realm'] = self.trust_root
- if self.assoc_handle:
- q['assoc_handle'] = self.assoc_handle
-
- response = Message(self.message.getOpenIDNamespace())
- response.updateArgs(OPENID_NS, q)
- return response.toURL(server_url)
-
-
- def getCancelURL(self):
- """Get the URL to cancel this request.
-
- Useful for creating a "Cancel" button on a web form so that operation
- can be carried out directly without another trip through the server.
-
- (Except you probably want to make another trip through the server so
- that it knows that the user did make a decision. Or you could simulate
- this method by doing C{.answer(False).encodeToURL()})
-
- @returntype: str
- @returns: The return_to URL with openid.mode = cancel.
-
- @raises NoReturnError: when I do not have a return_to.
- """
- if not self.return_to:
- raise NoReturnToError
-
- if self.immediate:
- raise ValueError("Cancel is not an appropriate response to "
- "immediate mode requests.")
-
- response = Message(self.message.getOpenIDNamespace())
- response.setArg(OPENID_NS, 'mode', 'cancel')
- return response.toURL(self.return_to)
-
-
- def __repr__(self):
- return '<%s id:%r im:%s tr:%r ah:%r>' % (self.__class__.__name__,
- self.identity,
- self.immediate,
- self.trust_root,
- self.assoc_handle)
-
-
-
-class OpenIDResponse(object):
- """I am a response to an OpenID request.
-
- @ivar request: The request I respond to.
- @type request: L{OpenIDRequest}
-
- @ivar fields: My parameters as a dictionary with each key mapping to
- one value. Keys are parameter names with no leading "C{openid.}".
- e.g. "C{identity}" and "C{mac_key}", never "C{openid.identity}".
- @type fields: L{openid.message.Message}
-
- @ivar signed: The names of the fields which should be signed.
- @type signed: list of str
- """
-
- # Implementer's note: In a more symmetric client/server
- # implementation, there would be more types of OpenIDResponse
- # object and they would have validated attributes according to the
- # type of response. But as it is, Response objects in a server are
- # basically write-only, their only job is to go out over the wire,
- # so this is just a loose wrapper around OpenIDResponse.fields.
-
- def __init__(self, request):
- """Make a response to an L{OpenIDRequest}.
-
- @type request: L{OpenIDRequest}
- """
- self.request = request
- self.fields = Message(request.namespace)
-
- def __str__(self):
- return "%s for %s: %s" % (
- self.__class__.__name__,
- self.request.__class__.__name__,
- self.fields)
-
-
- def toFormMarkup(self, form_tag_attrs=None):
- """Returns the form markup for this response.
-
- @param form_tag_attrs: Dictionary of attributes to be added to
- the form tag. 'accept-charset' and 'enctype' have defaults
- that can be overridden. If a value is supplied for
- 'action' or 'method', it will be replaced.
-
- @returntype: str
-
- @since: 2.1.0
- """
- return self.fields.toFormMarkup(self.request.return_to,
- form_tag_attrs=form_tag_attrs)
-
- def toHTML(self, form_tag_attrs=None):
- """Returns an HTML document that auto-submits the form markup
- for this response.
-
- @returntype: str
-
- @see: toFormMarkup
-
- @since: 2.1.?
- """
- return oidutil.autoSubmitHTML(self.toFormMarkup(form_tag_attrs))
-
- def renderAsForm(self):
- """Returns True if this response's encoding is
- ENCODE_HTML_FORM. Convenience method for server authors.
-
- @returntype: bool
-
- @since: 2.1.0
- """
- return self.whichEncoding() == ENCODE_HTML_FORM
-
-
- def needsSigning(self):
- """Does this response require signing?
-
- @returntype: bool
- """
- return self.fields.getArg(OPENID_NS, 'mode') == 'id_res'
-
-
- # implements IEncodable
-
- def whichEncoding(self):
- """How should I be encoded?
-
- @returns: one of ENCODE_URL, ENCODE_HTML_FORM, or ENCODE_KVFORM.
-
- @change: 2.1.0 added the ENCODE_HTML_FORM response.
- """
- if self.request.mode in BROWSER_REQUEST_MODES:
- if self.fields.getOpenIDNamespace() == OPENID2_NS and \
- len(self.encodeToURL()) > OPENID1_URL_LIMIT:
- return ENCODE_HTML_FORM
- else:
- return ENCODE_URL
- else:
- return ENCODE_KVFORM
-
-
- def encodeToURL(self):
- """Encode a response as a URL for the user agent to GET.
-
- You will generally use this URL with a HTTP redirect.
-
- @returns: A URL to direct the user agent back to.
- @returntype: str
- """
- return self.fields.toURL(self.request.return_to)
-
-
- def addExtension(self, extension_response):
- """
- Add an extension response to this response message.
-
- @param extension_response: An object that implements the
- extension interface for adding arguments to an OpenID
- message.
- @type extension_response: L{openid.extension}
-
- @returntype: None
- """
- extension_response.toMessage(self.fields)
-
-
- def encodeToKVForm(self):
- """Encode a response in key-value colon/newline format.
-
- This is a machine-readable format used to respond to messages which
- came directly from the consumer and not through the user agent.
-
- @see: OpenID Specs,
- U{Key-Value Colon/Newline format<http://openid.net/specs.bml#keyvalue>}
-
- @returntype: str
- """
- return self.fields.toKVForm()
-
-
-
-class WebResponse(object):
- """I am a response to an OpenID request in terms a web server understands.
-
- I generally come from an L{Encoder}, either directly or from
- L{Server.encodeResponse}.
-
- @ivar code: The HTTP code of this response.
- @type code: int
-
- @ivar headers: Headers to include in this response.
- @type headers: dict
-
- @ivar body: The body of this response.
- @type body: str
- """
-
- def __init__(self, code=HTTP_OK, headers=None, body=""):
- """Construct me.
-
- These parameters are assigned directly as class attributes, see
- my L{class documentation<WebResponse>} for their descriptions.
- """
- self.code = code
- if headers is not None:
- self.headers = headers
- else:
- self.headers = {}
- self.body = body
-
-
-
-class Signatory(object):
- """I sign things.
-
- I also check signatures.
-
- All my state is encapsulated in an
- L{OpenIDStore<openid.store.interface.OpenIDStore>}, which means
- I'm not generally pickleable but I am easy to reconstruct.
-
- @cvar SECRET_LIFETIME: The number of seconds a secret remains valid.
- @type SECRET_LIFETIME: int
- """
-
- SECRET_LIFETIME = 14 * 24 * 60 * 60 # 14 days, in seconds
-
- # keys have a bogus server URL in them because the filestore
- # really does expect that key to be a URL. This seems a little
- # silly for the server store, since I expect there to be only one
- # server URL.
- _normal_key = 'http://localhost/|normal'
- _dumb_key = 'http://localhost/|dumb'
-
-
- def __init__(self, store):
- """Create a new Signatory.
-
- @param store: The back-end where my associations are stored.
- @type store: L{openid.store.interface.OpenIDStore}
- """
- assert store is not None
- self.store = store
-
-
- def verify(self, assoc_handle, message):
- """Verify that the signature for some data is valid.
-
- @param assoc_handle: The handle of the association used to sign the
- data.
- @type assoc_handle: str
-
- @param message: The signed message to verify
- @type message: openid.message.Message
-
- @returns: C{True} if the signature is valid, C{False} if not.
- @returntype: bool
- """
- assoc = self.getAssociation(assoc_handle, dumb=True)
- if not assoc:
- oidutil.log("failed to get assoc with handle %r to verify "
- "message %r"
- % (assoc_handle, message))
- return False
-
- try:
- valid = assoc.checkMessageSignature(message)
- except ValueError, ex:
- oidutil.log("Error in verifying %s with %s: %s" % (message,
- assoc,
- ex))
- return False
- return valid
-
-
- def sign(self, response):
- """Sign a response.
-
- I take a L{OpenIDResponse}, create a signature for everything
- in its L{signed<OpenIDResponse.signed>} list, and return a new
- copy of the response object with that signature included.
-
- @param response: A response to sign.
- @type response: L{OpenIDResponse}
-
- @returns: A signed copy of the response.
- @returntype: L{OpenIDResponse}
- """
- signed_response = deepcopy(response)
- assoc_handle = response.request.assoc_handle
- if assoc_handle:
- # normal mode
- # disabling expiration check because even if the association
- # is expired, we still need to know some properties of the
- # association so that we may preserve those properties when
- # creating the fallback association.
- assoc = self.getAssociation(assoc_handle, dumb=False,
- checkExpiration=False)
-
- if not assoc or assoc.expiresIn <= 0:
- # fall back to dumb mode
- signed_response.fields.setArg(
- OPENID_NS, 'invalidate_handle', assoc_handle)
- assoc_type = assoc and assoc.assoc_type or 'HMAC-SHA1'
- if assoc and assoc.expiresIn <= 0:
- # now do the clean-up that the disabled checkExpiration
- # code didn't get to do.
- self.invalidate(assoc_handle, dumb=False)
- assoc = self.createAssociation(dumb=True, assoc_type=assoc_type)
- else:
- # dumb mode.
- assoc = self.createAssociation(dumb=True)
-
- try:
- signed_response.fields = assoc.signMessage(signed_response.fields)
- except kvform.KVFormError, err:
- raise EncodingError(response, explanation=str(err))
- return signed_response
-
-
- def createAssociation(self, dumb=True, assoc_type='HMAC-SHA1'):
- """Make a new association.
-
- @param dumb: Is this association for a dumb-mode transaction?
- @type dumb: bool
-
- @param assoc_type: The type of association to create. Currently
- there is only one type defined, C{HMAC-SHA1}.
- @type assoc_type: str
-
- @returns: the new association.
- @returntype: L{openid.association.Association}
- """
- secret = cryptutil.getBytes(getSecretSize(assoc_type))
- uniq = oidutil.toBase64(cryptutil.getBytes(4))
- handle = '{%s}{%x}{%s}' % (assoc_type, int(time.time()), uniq)
-
- assoc = Association.fromExpiresIn(
- self.SECRET_LIFETIME, handle, secret, assoc_type)
-
- if dumb:
- key = self._dumb_key
- else:
- key = self._normal_key
- self.store.storeAssociation(key, assoc)
- return assoc
-
-
- def getAssociation(self, assoc_handle, dumb, checkExpiration=True):
- """Get the association with the specified handle.
-
- @type assoc_handle: str
-
- @param dumb: Is this association used with dumb mode?
- @type dumb: bool
-
- @returns: the association, or None if no valid association with that
- handle was found.
- @returntype: L{openid.association.Association}
- """
- # Hmm. We've created an interface that deals almost entirely with
- # assoc_handles. The only place outside the Signatory that uses this
- # (and thus the only place that ever sees Association objects) is
- # when creating a response to an association request, as it must have
- # the association's secret.
-
- if assoc_handle is None:
- raise ValueError("assoc_handle must not be None")
-
- if dumb:
- key = self._dumb_key
- else:
- key = self._normal_key
- assoc = self.store.getAssociation(key, assoc_handle)
- if assoc is not None and assoc.expiresIn <= 0:
- oidutil.log("requested %sdumb key %r is expired (by %s seconds)" %
- ((not dumb) and 'not-' or '',
- assoc_handle, assoc.expiresIn))
- if checkExpiration:
- self.store.removeAssociation(key, assoc_handle)
- assoc = None
- return assoc
-
-
- def invalidate(self, assoc_handle, dumb):
- """Invalidates the association with the given handle.
-
- @type assoc_handle: str
-
- @param dumb: Is this association used with dumb mode?
- @type dumb: bool
- """
- if dumb:
- key = self._dumb_key
- else:
- key = self._normal_key
- self.store.removeAssociation(key, assoc_handle)
-
-
-
-class Encoder(object):
- """I encode responses in to L{WebResponses<WebResponse>}.
-
- If you don't like L{WebResponses<WebResponse>}, you can do
- your own handling of L{OpenIDResponses<OpenIDResponse>} with
- L{OpenIDResponse.whichEncoding}, L{OpenIDResponse.encodeToURL}, and
- L{OpenIDResponse.encodeToKVForm}.
- """
-
- responseFactory = WebResponse
-
-
- def encode(self, response):
- """Encode a response to a L{WebResponse}.
-
- @raises EncodingError: When I can't figure out how to encode this
- message.
- """
- encode_as = response.whichEncoding()
- if encode_as == ENCODE_KVFORM:
- wr = self.responseFactory(body=response.encodeToKVForm())
- if isinstance(response, Exception):
- wr.code = HTTP_ERROR
- elif encode_as == ENCODE_URL:
- location = response.encodeToURL()
- wr = self.responseFactory(code=HTTP_REDIRECT,
- headers={'location': location})
- elif encode_as == ENCODE_HTML_FORM:
- wr = self.responseFactory(code=HTTP_OK,
- body=response.toFormMarkup())
- else:
- # Can't encode this to a protocol message. You should probably
- # render it to HTML and show it to the user.
- raise EncodingError(response)
- return wr
-
-
-
-class SigningEncoder(Encoder):
- """I encode responses in to L{WebResponses<WebResponse>}, signing them when required.
- """
-
- def __init__(self, signatory):
- """Create a L{SigningEncoder}.
-
- @param signatory: The L{Signatory} I will make signatures with.
- @type signatory: L{Signatory}
- """
- self.signatory = signatory
-
-
- def encode(self, response):
- """Encode a response to a L{WebResponse}, signing it first if appropriate.
-
- @raises EncodingError: When I can't figure out how to encode this
- message.
-
- @raises AlreadySigned: When this response is already signed.
-
- @returntype: L{WebResponse}
- """
- # the isinstance is a bit of a kludge... it means there isn't really
- # an adapter to make the interfaces quite match.
- if (not isinstance(response, Exception)) and response.needsSigning():
- if not self.signatory:
- raise ValueError(
- "Must have a store to sign this request: %s" %
- (response,), response)
- if response.fields.hasKey(OPENID_NS, 'sig'):
- raise AlreadySigned(response)
- response = self.signatory.sign(response)
- return super(SigningEncoder, self).encode(response)
-
-
-
-class Decoder(object):
- """I decode an incoming web request in to a L{OpenIDRequest}.
- """
-
- _handlers = {
- 'checkid_setup': CheckIDRequest.fromMessage,
- 'checkid_immediate': CheckIDRequest.fromMessage,
- 'check_authentication': CheckAuthRequest.fromMessage,
- 'associate': AssociateRequest.fromMessage,
- }
-
- def __init__(self, server):
- """Construct a Decoder.
-
- @param server: The server which I am decoding requests for.
- (Necessary because some replies reference their server.)
- @type server: L{Server}
- """
- self.server = server
-
- def decode(self, query):
- """I transform query parameters into an L{OpenIDRequest}.
-
- If the query does not seem to be an OpenID request at all, I return
- C{None}.
-
- @param query: The query parameters as a dictionary with each
- key mapping to one value.
- @type query: dict
-
- @raises ProtocolError: When the query does not seem to be a valid
- OpenID request.
-
- @returntype: L{OpenIDRequest}
- """
- if not query:
- return None
-
- try:
- message = Message.fromPostArgs(query)
- except InvalidOpenIDNamespace, err:
- # It's useful to have a Message attached to a ProtocolError, so we
- # override the bad ns value to build a Message out of it. Kinda
- # kludgy, since it's made of lies, but the parts that aren't lies
- # are more useful than a 'None'.
- query = query.copy()
- query['openid.ns'] = OPENID2_NS
- message = Message.fromPostArgs(query)
- raise ProtocolError(message, str(err))
-
- mode = message.getArg(OPENID_NS, 'mode')
- if not mode:
- fmt = "No mode value in message %s"
- raise ProtocolError(message, text=fmt % (message,))
-
- handler = self._handlers.get(mode, self.defaultDecoder)
- return handler(message, self.server.op_endpoint)
-
-
- def defaultDecoder(self, message, server):
- """Called to decode queries when no handler for that mode is found.
-
- @raises ProtocolError: This implementation always raises
- L{ProtocolError}.
- """
- mode = message.getArg(OPENID_NS, 'mode')
- fmt = "Unrecognized OpenID mode %r"
- raise ProtocolError(message, text=fmt % (mode,))
-
-
-
-class Server(object):
- """I handle requests for an OpenID server.
-
- Some types of requests (those which are not C{checkid} requests) may be
- handed to my L{handleRequest} method, and I will take care of it and
- return a response.
-
- For your convenience, I also provide an interface to L{Decoder.decode}
- and L{SigningEncoder.encode} through my methods L{decodeRequest} and
- L{encodeResponse}.
-
- All my state is encapsulated in an
- L{OpenIDStore<openid.store.interface.OpenIDStore>}, which means
- I'm not generally pickleable but I am easy to reconstruct.
-
- Example::
-
- oserver = Server(FileOpenIDStore(data_path), "http://example.com/op")
- request = oserver.decodeRequest(query)
- if request.mode in ['checkid_immediate', 'checkid_setup']:
- if self.isAuthorized(request.identity, request.trust_root):
- response = request.answer(True)
- elif request.immediate:
- response = request.answer(False)
- else:
- self.showDecidePage(request)
- return
- else:
- response = oserver.handleRequest(request)
-
- webresponse = oserver.encode(response)
-
- @ivar signatory: I'm using this for associate requests and to sign things.
- @type signatory: L{Signatory}
-
- @ivar decoder: I'm using this to decode things.
- @type decoder: L{Decoder}
-
- @ivar encoder: I'm using this to encode things.
- @type encoder: L{Encoder}
-
- @ivar op_endpoint: My URL.
- @type op_endpoint: str
-
- @ivar negotiator: I use this to determine which kinds of
- associations I can make and how.
- @type negotiator: L{openid.association.SessionNegotiator}
- """
-
- signatoryClass = Signatory
- encoderClass = SigningEncoder
- decoderClass = Decoder
-
- def __init__(self, store, op_endpoint=None):
- """A new L{Server}.
-
- @param store: The back-end where my associations are stored.
- @type store: L{openid.store.interface.OpenIDStore}
-
- @param op_endpoint: My URL, the fully qualified address of this
- server's endpoint, i.e. C{http://example.com/server}
- @type op_endpoint: str
-
- @change: C{op_endpoint} is new in library version 2.0. It
- currently defaults to C{None} for compatibility with
- earlier versions of the library, but you must provide it
- if you want to respond to any version 2 OpenID requests.
- """
- self.store = store
- self.signatory = self.signatoryClass(self.store)
- self.encoder = self.encoderClass(self.signatory)
- self.decoder = self.decoderClass(self)
- self.negotiator = default_negotiator.copy()
-
- if not op_endpoint:
- warnings.warn("%s.%s constructor requires op_endpoint parameter "
- "for OpenID 2.0 servers" %
- (self.__class__.__module__, self.__class__.__name__),
- stacklevel=2)
- self.op_endpoint = op_endpoint
-
-
- def handleRequest(self, request):
- """Handle a request.
-
- Give me a request, I will give you a response. Unless it's a type
- of request I cannot handle myself, in which case I will raise
- C{NotImplementedError}. In that case, you can handle it yourself,
- or add a method to me for handling that request type.
-
- @raises NotImplementedError: When I do not have a handler defined
- for that type of request.
-
- @returntype: L{OpenIDResponse}
- """
- handler = getattr(self, 'openid_' + request.mode, None)
- if handler is not None:
- return handler(request)
- else:
- raise NotImplementedError(
- "%s has no handler for a request of mode %r." %
- (self, request.mode))
-
-
- def openid_check_authentication(self, request):
- """Handle and respond to C{check_authentication} requests.
-
- @returntype: L{OpenIDResponse}
- """
- return request.answer(self.signatory)
-
-
- def openid_associate(self, request):
- """Handle and respond to C{associate} requests.
-
- @returntype: L{OpenIDResponse}
- """
- # XXX: TESTME
- assoc_type = request.assoc_type
- session_type = request.session.session_type
- if self.negotiator.isAllowed(assoc_type, session_type):
- assoc = self.signatory.createAssociation(dumb=False,
- assoc_type=assoc_type)
- return request.answer(assoc)
- else:
- message = ('Association type %r is not supported with '
- 'session type %r' % (assoc_type, session_type))
- (preferred_assoc_type, preferred_session_type) = \
- self.negotiator.getAllowedType()
- return request.answerUnsupported(
- message,
- preferred_assoc_type,
- preferred_session_type)
-
-
- def decodeRequest(self, query):
- """Transform query parameters into an L{OpenIDRequest}.
-
- If the query does not seem to be an OpenID request at all, I return
- C{None}.
-
- @param query: The query parameters as a dictionary with each
- key mapping to one value.
- @type query: dict
-
- @raises ProtocolError: When the query does not seem to be a valid
- OpenID request.
-
- @returntype: L{OpenIDRequest}
-
- @see: L{Decoder.decode}
- """
- return self.decoder.decode(query)
-
-
- def encodeResponse(self, response):
- """Encode a response to a L{WebResponse}, signing it first if appropriate.
-
- @raises EncodingError: When I can't figure out how to encode this
- message.
-
- @raises AlreadySigned: When this response is already signed.
-
- @returntype: L{WebResponse}
-
- @see: L{SigningEncoder.encode}
- """
- return self.encoder.encode(response)
-
-
-
-class ProtocolError(Exception):
- """A message did not conform to the OpenID protocol.
-
- @ivar message: The query that is failing to be a valid OpenID request.
- @type message: openid.message.Message
- """
-
- def __init__(self, message, text=None, reference=None, contact=None):
- """When an error occurs.
-
- @param message: The message that is failing to be a valid
- OpenID request.
- @type message: openid.message.Message
-
- @param text: A message about the encountered error. Set as C{args[0]}.
- @type text: str
- """
- self.openid_message = message
- self.reference = reference
- self.contact = contact
- assert type(message) not in [str, unicode]
- Exception.__init__(self, text)
-
-
- def getReturnTo(self):
- """Get the return_to argument from the request, if any.
-
- @returntype: str
- """
- if self.openid_message is None:
- return None
- else:
- return self.openid_message.getArg(OPENID_NS, 'return_to')
-
- def hasReturnTo(self):
- """Did this request have a return_to parameter?
-
- @returntype: bool
- """
- return self.getReturnTo() is not None
-
- def toMessage(self):
- """Generate a Message object for sending to the relying party,
- after encoding.
- """
- namespace = self.openid_message.getOpenIDNamespace()
- reply = Message(namespace)
- reply.setArg(OPENID_NS, 'mode', 'error')
- reply.setArg(OPENID_NS, 'error', str(self))
-
- if self.contact is not None:
- reply.setArg(OPENID_NS, 'contact', str(self.contact))
-
- if self.reference is not None:
- reply.setArg(OPENID_NS, 'reference', str(self.reference))
-
- return reply
-
- # implements IEncodable
-
- def encodeToURL(self):
- return self.toMessage().toURL(self.getReturnTo())
-
- def encodeToKVForm(self):
- return self.toMessage().toKVForm()
-
- def toFormMarkup(self):
- """Encode to HTML form markup for POST.
-
- @since: 2.1.0
- """
- return self.toMessage().toFormMarkup(self.getReturnTo())
-
- def toHTML(self):
- """Encode to a full HTML page, wrapping the form markup in a page
- that will autosubmit the form.
-
- @since: 2.1.?
- """
- return oidutil.autoSubmitHTML(self.toFormMarkup())
-
- def whichEncoding(self):
- """How should I be encoded?
-
- @returns: one of ENCODE_URL, ENCODE_KVFORM, or None. If None,
- I cannot be encoded as a protocol message and should be
- displayed to the user.
- """
- if self.hasReturnTo():
- if self.openid_message.getOpenIDNamespace() == OPENID2_NS and \
- len(self.encodeToURL()) > OPENID1_URL_LIMIT:
- return ENCODE_HTML_FORM
- else:
- return ENCODE_URL
-
- if self.openid_message is None:
- return None
-
- mode = self.openid_message.getArg(OPENID_NS, 'mode')
- if mode:
- if mode not in BROWSER_REQUEST_MODES:
- return ENCODE_KVFORM
-
- # According to the OpenID spec as of this writing, we are probably
- # supposed to switch on request type here (GET versus POST) to figure
- # out if we're supposed to print machine-readable or human-readable
- # content at this point. GET/POST seems like a pretty lousy way of
- # making the distinction though, as it's just as possible that the
- # user agent could have mistakenly been directed to post to the
- # server URL.
-
- # Basically, if your request was so broken that you didn't manage to
- # include an openid.mode, I'm not going to worry too much about
- # returning you something you can't parse.
- return None
-
-
-
-class VersionError(Exception):
- """Raised when an operation was attempted that is not compatible with
- the protocol version being used."""
-
-
-
-class NoReturnToError(Exception):
- """Raised when a response to a request cannot be generated because
- the request contains no return_to URL.
- """
- pass
-
-
-
-class EncodingError(Exception):
- """Could not encode this as a protocol message.
-
- You should probably render it and show it to the user.
-
- @ivar response: The response that failed to encode.
- @type response: L{OpenIDResponse}
- """
-
- def __init__(self, response, explanation=None):
- Exception.__init__(self, response)
- self.response = response
- self.explanation = explanation
-
- def __str__(self):
- if self.explanation:
- s = '%s: %s' % (self.__class__.__name__,
- self.explanation)
- else:
- s = '%s for Response %s' % (
- self.__class__.__name__, self.response)
- return s
-
-
-class AlreadySigned(EncodingError):
- """This response is already signed."""
-
-
-
-class UntrustedReturnURL(ProtocolError):
- """A return_to is outside the trust_root."""
-
- def __init__(self, message, return_to, trust_root):
- ProtocolError.__init__(self, message)
- self.return_to = return_to
- self.trust_root = trust_root
-
- def __str__(self):
- return "return_to %r not under trust_root %r" % (self.return_to,
- self.trust_root)
-
-
-class MalformedReturnURL(ProtocolError):
- """The return_to URL doesn't look like a valid URL."""
- def __init__(self, openid_message, return_to):
- self.return_to = return_to
- ProtocolError.__init__(self, openid_message)
-
-
-
-class MalformedTrustRoot(ProtocolError):
- """The trust root is not well-formed.
-
- @see: OpenID Specs, U{openid.trust_root<http://openid.net/specs.bml#mode-checkid_immediate>}
- """
- pass
-
-
-#class IEncodable: # Interface
-# def encodeToURL(return_to):
-# """Encode a response as a URL for redirection.
-#
-# @returns: A URL to direct the user agent back to.
-# @returntype: str
-# """
-# pass
-#
-# def encodeToKvform():
-# """Encode a response in key-value colon/newline format.
-#
-# This is a machine-readable format used to respond to messages which
-# came directly from the consumer and not through the user agent.
-#
-# @see: OpenID Specs,
-# U{Key-Value Colon/Newline format<http://openid.net/specs.bml#keyvalue>}
-#
-# @returntype: str
-# """
-# pass
-#
-# def whichEncoding():
-# """How should I be encoded?
-#
-# @returns: one of ENCODE_URL, ENCODE_KVFORM, or None. If None,
-# I cannot be encoded as a protocol message and should be
-# displayed to the user.
-# """
-# pass
diff --git a/askbot/deps/openid/server/trustroot.py b/askbot/deps/openid/server/trustroot.py
deleted file mode 100644
index f78d2992..00000000
--- a/askbot/deps/openid/server/trustroot.py
+++ /dev/null
@@ -1,454 +0,0 @@
-# -*- test-case-name: openid.test.test_rpverify -*-
-"""
-This module contains the C{L{TrustRoot}} class, which helps handle
-trust root checking. This module is used by the
-C{L{openid.server.server}} module, but it is also available to server
-implementers who wish to use it for additional trust root checking.
-
-It also implements relying party return_to URL verification, based on
-the realm.
-"""
-
-__all__ = [
- 'TrustRoot',
- 'RP_RETURN_TO_URL_TYPE',
- 'extractReturnToURLs',
- 'returnToMatches',
- 'verifyReturnTo',
- ]
-
-from askbot.deps.openid import oidutil
-from askbot.deps.openid import urinorm
-from askbot.deps.openid.yadis import services
-
-from urlparse import urlparse, urlunparse
-import re
-
-############################################
-_protocols = ['http', 'https']
-_top_level_domains = [
- 'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an',
- 'ao', 'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw',
- 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi',
- 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw',
- 'by', 'bz', 'ca', 'cat', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci',
- 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', 'cv',
- 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec',
- 'edu', 'ee', 'eg', 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk',
- 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh',
- 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt',
- 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id',
- 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is',
- 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki',
- 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc',
- 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', 'ma', 'mc',
- 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo',
- 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv',
- 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf',
- 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org',
- 'pa', 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr',
- 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru',
- 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj',
- 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy',
- 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', 'tk', 'tl',
- 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw',
- 'tz', 'ua', 'ug', 'uk', 'us', 'uy', 'uz', 'va', 'vc', 've',
- 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'xn--0zwm56d',
- 'xn--11b5bs3a9aj6g', 'xn--80akhbyknj4f', 'xn--9t4b11yi5a',
- 'xn--deba0ad', 'xn--g6w251d', 'xn--hgbk6aj7f53bba',
- 'xn--hlcj6aya9esc7a', 'xn--jxalpdlp', 'xn--kgbechtv',
- 'xn--zckzah', 'ye', 'yt', 'yu', 'za', 'zm', 'zw']
-
-# Build from RFC3986, section 3.2.2. Used to reject hosts with invalid
-# characters.
-host_segment_re = re.compile(
- r"(?:[-a-zA-Z0-9!$&'\(\)\*+,;=._~]|%[a-zA-Z0-9]{2})+$")
-
-class RealmVerificationRedirected(Exception):
- """Attempting to verify this realm resulted in a redirect.
-
- @since: 2.1.0
- """
- def __init__(self, relying_party_url, rp_url_after_redirects):
- self.relying_party_url = relying_party_url
- self.rp_url_after_redirects = rp_url_after_redirects
-
- def __str__(self):
- return ("Attempting to verify %r resulted in "
- "redirect to %r" %
- (self.relying_party_url,
- self.rp_url_after_redirects))
-
-
-def _parseURL(url):
- try:
- url = urinorm.urinorm(url)
- except ValueError:
- return None
- proto, netloc, path, params, query, frag = urlparse(url)
- if not path:
- # Python <2.4 does not parse URLs with no path properly
- if not query and '?' in netloc:
- netloc, query = netloc.split('?', 1)
-
- path = '/'
-
- path = urlunparse(('', '', path, params, query, frag))
-
- if ':' in netloc:
- try:
- host, port = netloc.split(':')
- except ValueError:
- return None
-
- if not re.match(r'\d+$', port):
- return None
- else:
- host = netloc
- port = ''
-
- host = host.lower()
- if not host_segment_re.match(host):
- return None
-
- return proto, host, port, path
-
-class TrustRoot(object):
- """
- This class represents an OpenID trust root. The C{L{parse}}
- classmethod accepts a trust root string, producing a
- C{L{TrustRoot}} object. The method OpenID server implementers
- would be most likely to use is the C{L{isSane}} method, which
- checks the trust root for given patterns that indicate that the
- trust root is too broad or points to a local network resource.
-
- @sort: parse, isSane
- """
-
- def __init__(self, unparsed, proto, wildcard, host, port, path):
- self.unparsed = unparsed
- self.proto = proto
- self.wildcard = wildcard
- self.host = host
- self.port = port
- self.path = path
-
- def isSane(self):
- """
- This method checks the to see if a trust root represents a
- reasonable (sane) set of URLs. 'http://*.com/', for example
- is not a reasonable pattern, as it cannot meaningfully specify
- the site claiming it. This function attempts to find many
- related examples, but it can only work via heuristics.
- Negative responses from this method should be treated as
- advisory, used only to alert the user to examine the trust
- root carefully.
-
-
- @return: Whether the trust root is sane
-
- @rtype: C{bool}
- """
-
- if self.host == 'localhost':
- return True
-
- host_parts = self.host.split('.')
- if self.wildcard:
- assert host_parts[0] == '', host_parts
- del host_parts[0]
-
- # If it's an absolute domain name, remove the empty string
- # from the end.
- if host_parts and not host_parts[-1]:
- del host_parts[-1]
-
- if not host_parts:
- return False
-
- # Do not allow adjacent dots
- if '' in host_parts:
- return False
-
- tld = host_parts[-1]
- if tld not in _top_level_domains:
- return False
-
- if len(host_parts) == 1:
- return False
-
- if self.wildcard:
- if len(tld) == 2 and len(host_parts[-2]) <= 3:
- # It's a 2-letter tld with a short second to last segment
- # so there needs to be more than two segments specified
- # (e.g. *.co.uk is insane)
- return len(host_parts) > 2
-
- # Passed all tests for insanity.
- return True
-
- def validateURL(self, url):
- """
- Validates a URL against this trust root.
-
-
- @param url: The URL to check
-
- @type url: C{str}
-
-
- @return: Whether the given URL is within this trust root.
-
- @rtype: C{bool}
- """
-
- url_parts = _parseURL(url)
- if url_parts is None:
- return False
-
- proto, host, port, path = url_parts
-
- if proto != self.proto:
- return False
-
- if port != self.port:
- return False
-
- if '*' in host:
- return False
-
- if not self.wildcard:
- if host != self.host:
- return False
- elif ((not host.endswith(self.host)) and
- ('.' + host) != self.host):
- return False
-
- if path != self.path:
- path_len = len(self.path)
- trust_prefix = self.path[:path_len]
- url_prefix = path[:path_len]
-
- # must be equal up to the length of the path, at least
- if trust_prefix != url_prefix:
- return False
-
- # These characters must be on the boundary between the end
- # of the trust root's path and the start of the URL's
- # path.
- if '?' in self.path:
- allowed = '&'
- else:
- allowed = '?/'
-
- return (self.path[-1] in allowed or
- path[path_len] in allowed)
-
- return True
-
- def parse(cls, trust_root):
- """
- This method creates a C{L{TrustRoot}} instance from the given
- input, if possible.
-
-
- @param trust_root: This is the trust root to parse into a
- C{L{TrustRoot}} object.
-
- @type trust_root: C{str}
-
-
- @return: A C{L{TrustRoot}} instance if trust_root parses as a
- trust root, C{None} otherwise.
-
- @rtype: C{NoneType} or C{L{TrustRoot}}
- """
- url_parts = _parseURL(trust_root)
- if url_parts is None:
- return None
-
- proto, host, port, path = url_parts
-
- # check for valid prototype
- if proto not in _protocols:
- return None
-
- # check for URI fragment
- if path.find('#') != -1:
- return None
-
- # extract wildcard if it is there
- if host.find('*', 1) != -1:
- # wildcard must be at start of domain: *.foo.com, not foo.*.com
- return None
-
- if host.startswith('*'):
- # Starts with star, so must have a dot after it (if a
- # domain is specified)
- if len(host) > 1 and host[1] != '.':
- return None
-
- host = host[1:]
- wilcard = True
- else:
- wilcard = False
-
- # we have a valid trust root
- tr = cls(trust_root, proto, wilcard, host, port, path)
-
- return tr
-
- parse = classmethod(parse)
-
- def checkSanity(cls, trust_root_string):
- """str -> bool
-
- is this a sane trust root?
- """
- trust_root = cls.parse(trust_root_string)
- if trust_root is None:
- return False
- else:
- return trust_root.isSane()
-
- checkSanity = classmethod(checkSanity)
-
- def checkURL(cls, trust_root, url):
- """quick func for validating a url against a trust root. See the
- TrustRoot class if you need more control."""
- tr = cls.parse(trust_root)
- return tr is not None and tr.validateURL(url)
-
- checkURL = classmethod(checkURL)
-
- def buildDiscoveryURL(self):
- """Return a discovery URL for this realm.
-
- This function does not check to make sure that the realm is
- valid. Its behaviour on invalid inputs is undefined.
-
- @rtype: str
-
- @returns: The URL upon which relying party discovery should be run
- in order to verify the return_to URL
-
- @since: 2.1.0
- """
- if self.wildcard:
- # Use "www." in place of the star
- assert self.host.startswith('.'), self.host
- www_domain = 'www' + self.host
- return '%s://%s%s' % (self.proto, www_domain, self.path)
- else:
- return self.unparsed
-
- def __repr__(self):
- return "TrustRoot(%r, %r, %r, %r, %r, %r)" % (
- self.unparsed, self.proto, self.wildcard, self.host, self.port,
- self.path)
-
- def __str__(self):
- return repr(self)
-
-# The URI for relying party discovery, used in realm verification.
-#
-# XXX: This should probably live somewhere else (like in
-# openid.consumer or openid.yadis somewhere)
-RP_RETURN_TO_URL_TYPE = 'http://specs.openid.net/auth/2.0/return_to'
-
-def _extractReturnURL(endpoint):
- """If the endpoint is a relying party OpenID return_to endpoint,
- return the endpoint URL. Otherwise, return None.
-
- This function is intended to be used as a filter for the Yadis
- filtering interface.
-
- @see: C{L{openid.yadis.services}}
- @see: C{L{openid.yadis.filters}}
-
- @param endpoint: An XRDS BasicServiceEndpoint, as returned by
- performing Yadis dicovery.
-
- @returns: The endpoint URL or None if the endpoint is not a
- relying party endpoint.
- @rtype: str or NoneType
- """
- if endpoint.matchTypes([RP_RETURN_TO_URL_TYPE]):
- return endpoint.uri
- else:
- return None
-
-def returnToMatches(allowed_return_to_urls, return_to):
- """Is the return_to URL under one of the supplied allowed
- return_to URLs?
-
- @since: 2.1.0
- """
-
- for allowed_return_to in allowed_return_to_urls:
- # A return_to pattern works the same as a realm, except that
- # it's not allowed to use a wildcard. We'll model this by
- # parsing it as a realm, and not trying to match it if it has
- # a wildcard.
-
- return_realm = TrustRoot.parse(allowed_return_to)
- if (# Parses as a trust root
- return_realm is not None and
-
- # Does not have a wildcard
- not return_realm.wildcard and
-
- # Matches the return_to that we passed in with it
- return_realm.validateURL(return_to)
- ):
- return True
-
- # No URL in the list matched
- return False
-
-def getAllowedReturnURLs(relying_party_url):
- """Given a relying party discovery URL return a list of return_to URLs.
-
- @since: 2.1.0
- """
- (rp_url_after_redirects, return_to_urls) = services.getServiceEndpoints(
- relying_party_url, _extractReturnURL)
-
- if rp_url_after_redirects != relying_party_url:
- # Verification caused a redirect
- raise RealmVerificationRedirected(
- relying_party_url, rp_url_after_redirects)
-
- return return_to_urls
-
-# _vrfy parameter is there to make testing easier
-def verifyReturnTo(realm_str, return_to, _vrfy=getAllowedReturnURLs):
- """Verify that a return_to URL is valid for the given realm.
-
- This function builds a discovery URL, performs Yadis discovery on
- it, makes sure that the URL does not redirect, parses out the
- return_to URLs, and finally checks to see if the current return_to
- URL matches the return_to.
-
- @raises DiscoveryFailure: When Yadis discovery fails
- @returns: True if the return_to URL is valid for the realm
-
- @since: 2.1.0
- """
- realm = TrustRoot.parse(realm_str)
- if realm is None:
- # The realm does not parse as a URL pattern
- return False
-
- try:
- allowable_urls = _vrfy(realm.buildDiscoveryURL())
- except RealmVerificationRedirected, err:
- oidutil.log(str(err))
- return False
-
- if returnToMatches(allowable_urls, return_to):
- return True
- else:
- oidutil.log("Failed to validate return_to %r for realm %r, was not "
- "in %s" % (return_to, realm_str, allowable_urls))
- return False
diff --git a/askbot/deps/openid/sreg.py b/askbot/deps/openid/sreg.py
deleted file mode 100644
index a002b128..00000000
--- a/askbot/deps/openid/sreg.py
+++ /dev/null
@@ -1,7 +0,0 @@
-"""moved to L{openid.extensions.sreg}"""
-
-import warnings
-warnings.warn("openid.sreg has moved to openid.extensions.sreg",
- DeprecationWarning)
-
-from askbot.deps.openid.extensions.sreg import *
diff --git a/askbot/deps/openid/store/__init__.py b/askbot/deps/openid/store/__init__.py
deleted file mode 100644
index 76509b51..00000000
--- a/askbot/deps/openid/store/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-"""
-This package contains the modules related to this library's use of
-persistent storage.
-
-@sort: interface, filestore, sqlstore, memstore
-"""
-
-__all__ = ['interface', 'filestore', 'sqlstore', 'memstore', 'nonce']
diff --git a/askbot/deps/openid/store/filestore.py b/askbot/deps/openid/store/filestore.py
deleted file mode 100644
index 47de4964..00000000
--- a/askbot/deps/openid/store/filestore.py
+++ /dev/null
@@ -1,426 +0,0 @@
-"""
-This module contains an C{L{OpenIDStore}} implementation backed by
-flat files.
-"""
-
-import string
-import os
-import os.path
-import time
-
-from errno import EEXIST, ENOENT
-
-try:
- from tempfile import mkstemp
-except ImportError:
- # Python < 2.3
- import warnings
- warnings.filterwarnings("ignore",
- "tempnam is a potential security risk",
- RuntimeWarning,
- "openid.store.filestore")
-
- def mkstemp(dir):
- for _ in range(5):
- name = os.tempnam(dir)
- try:
- fd = os.open(name, os.O_CREAT | os.O_EXCL | os.O_RDWR, 0600)
- except OSError, why:
- if why.errno != EEXIST:
- raise
- else:
- return fd, name
-
- raise RuntimeError('Failed to get temp file after 5 attempts')
-
-from askbot.deps.openid.association import Association
-from askbot.deps.openid.store.interface import OpenIDStore
-from askbot.deps.openid.store import nonce
-from askbot.deps.openid import cryptutil, oidutil
-
-_filename_allowed = string.ascii_letters + string.digits + '.'
-try:
- # 2.4
- set
-except NameError:
- try:
- # 2.3
- import sets
- except ImportError:
- # Python < 2.2
- d = {}
- for c in _filename_allowed:
- d[c] = None
- _isFilenameSafe = d.has_key
- del d
- else:
- _isFilenameSafe = sets.Set(_filename_allowed).__contains__
-else:
- _isFilenameSafe = set(_filename_allowed).__contains__
-
-def _safe64(s):
- h64 = oidutil.toBase64(cryptutil.sha1(s))
- h64 = h64.replace('+', '_')
- h64 = h64.replace('/', '.')
- h64 = h64.replace('=', '')
- return h64
-
-def _filenameEscape(s):
- filename_chunks = []
- for c in s:
- if _isFilenameSafe(c):
- filename_chunks.append(c)
- else:
- filename_chunks.append('_%02X' % ord(c))
- return ''.join(filename_chunks)
-
-def _removeIfPresent(filename):
- """Attempt to remove a file, returning whether the file existed at
- the time of the call.
-
- str -> bool
- """
- try:
- os.unlink(filename)
- except OSError, why:
- if why.errno == ENOENT:
- # Someone beat us to it, but it's gone, so that's OK
- return 0
- else:
- raise
- else:
- # File was present
- return 1
-
-def _ensureDir(dir_name):
- """Create dir_name as a directory if it does not exist. If it
- exists, make sure that it is, in fact, a directory.
-
- Can raise OSError
-
- str -> NoneType
- """
- try:
- os.makedirs(dir_name)
- except OSError, why:
- if why.errno != EEXIST or not os.path.isdir(dir_name):
- raise
-
-class FileOpenIDStore(OpenIDStore):
- """
- This is a filesystem-based store for OpenID associations and
- nonces. This store should be safe for use in concurrent systems
- on both windows and unix (excluding NFS filesystems). There are a
- couple race conditions in the system, but those failure cases have
- been set up in such a way that the worst-case behavior is someone
- having to try to log in a second time.
-
- Most of the methods of this class are implementation details.
- People wishing to just use this store need only pay attention to
- the C{L{__init__}} method.
-
- Methods of this object can raise OSError if unexpected filesystem
- conditions, such as bad permissions or missing directories, occur.
- """
-
- def __init__(self, directory):
- """
- Initializes a new FileOpenIDStore. This initializes the
- nonce and association directories, which are subdirectories of
- the directory passed in.
-
- @param directory: This is the directory to put the store
- directories in.
-
- @type directory: C{str}
- """
- # Make absolute
- directory = os.path.normpath(os.path.abspath(directory))
-
- self.nonce_dir = os.path.join(directory, 'nonces')
-
- self.association_dir = os.path.join(directory, 'associations')
-
- # Temp dir must be on the same filesystem as the assciations
- # directory
- self.temp_dir = os.path.join(directory, 'temp')
-
- self.max_nonce_age = 6 * 60 * 60 # Six hours, in seconds
-
- self._setup()
-
- def _setup(self):
- """Make sure that the directories in which we store our data
- exist.
-
- () -> NoneType
- """
- _ensureDir(self.nonce_dir)
- _ensureDir(self.association_dir)
- _ensureDir(self.temp_dir)
-
- def _mktemp(self):
- """Create a temporary file on the same filesystem as
- self.association_dir.
-
- The temporary directory should not be cleaned if there are any
- processes using the store. If there is no active process using
- the store, it is safe to remove all of the files in the
- temporary directory.
-
- () -> (file, str)
- """
- fd, name = mkstemp(dir=self.temp_dir)
- try:
- file_obj = os.fdopen(fd, 'wb')
- return file_obj, name
- except:
- _removeIfPresent(name)
- raise
-
- def getAssociationFilename(self, server_url, handle):
- """Create a unique filename for a given server url and
- handle. This implementation does not assume anything about the
- format of the handle. The filename that is returned will
- contain the domain name from the server URL for ease of human
- inspection of the data directory.
-
- (str, str) -> str
- """
- if server_url.find('://') == -1:
- raise ValueError('Bad server URL: %r' % server_url)
-
- proto, rest = server_url.split('://', 1)
- domain = _filenameEscape(rest.split('/', 1)[0])
- url_hash = _safe64(server_url)
- if handle:
- handle_hash = _safe64(handle)
- else:
- handle_hash = ''
-
- filename = '%s-%s-%s-%s' % (proto, domain, url_hash, handle_hash)
-
- return os.path.join(self.association_dir, filename)
-
- def storeAssociation(self, server_url, association):
- """Store an association in the association directory.
-
- (str, Association) -> NoneType
- """
- association_s = association.serialize()
- filename = self.getAssociationFilename(server_url, association.handle)
- tmp_file, tmp = self._mktemp()
-
- try:
- try:
- tmp_file.write(association_s)
- os.fsync(tmp_file.fileno())
- finally:
- tmp_file.close()
-
- try:
- os.rename(tmp, filename)
- except OSError, why:
- if why.errno != EEXIST:
- raise
-
- # We only expect EEXIST to happen only on Windows. It's
- # possible that we will succeed in unlinking the existing
- # file, but not in putting the temporary file in place.
- try:
- os.unlink(filename)
- except OSError, why:
- if why.errno == ENOENT:
- pass
- else:
- raise
-
- # Now the target should not exist. Try renaming again,
- # giving up if it fails.
- os.rename(tmp, filename)
- except:
- # If there was an error, don't leave the temporary file
- # around.
- _removeIfPresent(tmp)
- raise
-
- def getAssociation(self, server_url, handle=None):
- """Retrieve an association. If no handle is specified, return
- the association with the latest expiration.
-
- (str, str or NoneType) -> Association or NoneType
- """
- if handle is None:
- handle = ''
-
- # The filename with the empty handle is a prefix of all other
- # associations for the given server URL.
- filename = self.getAssociationFilename(server_url, handle)
-
- if handle:
- return self._getAssociation(filename)
- else:
- association_files = os.listdir(self.association_dir)
- matching_files = []
- # strip off the path to do the comparison
- name = os.path.basename(filename)
- for association_file in association_files:
- if association_file.startswith(name):
- matching_files.append(association_file)
-
- matching_associations = []
- # read the matching files and sort by time issued
- for name in matching_files:
- full_name = os.path.join(self.association_dir, name)
- association = self._getAssociation(full_name)
- if association is not None:
- matching_associations.append(
- (association.issued, association))
-
- matching_associations.sort()
-
- # return the most recently issued one.
- if matching_associations:
- (_, assoc) = matching_associations[-1]
- return assoc
- else:
- return None
-
- def _getAssociation(self, filename):
- try:
- assoc_file = file(filename, 'rb')
- except IOError, why:
- if why.errno == ENOENT:
- # No association exists for that URL and handle
- return None
- else:
- raise
- else:
- try:
- assoc_s = assoc_file.read()
- finally:
- assoc_file.close()
-
- try:
- association = Association.deserialize(assoc_s)
- except ValueError:
- _removeIfPresent(filename)
- return None
-
- # Clean up expired associations
- if association.getExpiresIn() == 0:
- _removeIfPresent(filename)
- return None
- else:
- return association
-
- def removeAssociation(self, server_url, handle):
- """Remove an association if it exists. Do nothing if it does not.
-
- (str, str) -> bool
- """
- assoc = self.getAssociation(server_url, handle)
- if assoc is None:
- return 0
- else:
- filename = self.getAssociationFilename(server_url, handle)
- return _removeIfPresent(filename)
-
- def useNonce(self, server_url, timestamp, salt):
- """Return whether this nonce is valid.
-
- str -> bool
- """
- if abs(timestamp - time.time()) > nonce.SKEW:
- return False
-
- if server_url:
- proto, rest = server_url.split('://', 1)
- else:
- # Create empty proto / rest values for empty server_url,
- # which is part of a consumer-generated nonce.
- proto, rest = '', ''
-
- domain = _filenameEscape(rest.split('/', 1)[0])
- url_hash = _safe64(server_url)
- salt_hash = _safe64(salt)
-
- filename = '%08x-%s-%s-%s-%s' % (timestamp, proto, domain,
- url_hash, salt_hash)
-
- filename = os.path.join(self.nonce_dir, filename)
- try:
- fd = os.open(filename, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0200)
- except OSError, why:
- if why.errno == EEXIST:
- return False
- else:
- raise
- else:
- os.close(fd)
- return True
-
- def _allAssocs(self):
- all_associations = []
-
- association_filenames = map(
- lambda filename: os.path.join(self.association_dir, filename),
- os.listdir(self.association_dir))
- for association_filename in association_filenames:
- try:
- association_file = file(association_filename, 'rb')
- except IOError, why:
- if why.errno == ENOENT:
- oidutil.log("%s disappeared during %s._allAssocs" % (
- association_filename, self.__class__.__name__))
- else:
- raise
- else:
- try:
- assoc_s = association_file.read()
- finally:
- association_file.close()
-
- # Remove expired or corrupted associations
- try:
- association = Association.deserialize(assoc_s)
- except ValueError:
- _removeIfPresent(association_filename)
- else:
- all_associations.append(
- (association_filename, association))
-
- return all_associations
-
- def cleanup(self):
- """Remove expired entries from the database. This is
- potentially expensive, so only run when it is acceptable to
- take time.
-
- () -> NoneType
- """
- self.cleanupAssociations()
- self.cleanupNonces()
-
- def cleanupAssociations(self):
- removed = 0
- for assoc_filename, assoc in self._allAssocs():
- if assoc.getExpiresIn() == 0:
- _removeIfPresent(assoc_filename)
- removed += 1
- return removed
-
- def cleanupNonces(self):
- nonces = os.listdir(self.nonce_dir)
- now = time.time()
-
- removed = 0
- # Check all nonces for expiry
- for nonce_fname in nonces:
- timestamp = nonce_fname.split('-', 1)[0]
- timestamp = int(timestamp, 16)
- if abs(timestamp - now) > nonce.SKEW:
- filename = os.path.join(self.nonce_dir, nonce_fname)
- _removeIfPresent(filename)
- removed += 1
- return removed
diff --git a/askbot/deps/openid/store/interface.py b/askbot/deps/openid/store/interface.py
deleted file mode 100644
index bb90972f..00000000
--- a/askbot/deps/openid/store/interface.py
+++ /dev/null
@@ -1,197 +0,0 @@
-"""
-This module contains the definition of the C{L{OpenIDStore}}
-interface.
-"""
-
-class OpenIDStore(object):
- """
- This is the interface for the store objects the OpenID library
- uses. It is a single class that provides all of the persistence
- mechanisms that the OpenID library needs, for both servers and
- consumers.
-
- @change: Version 2.0 removed the C{storeNonce}, C{getAuthKey}, and C{isDumb}
- methods, and changed the behavior of the C{L{useNonce}} method
- to support one-way nonces. It added C{L{cleanupNonces}},
- C{L{cleanupAssociations}}, and C{L{cleanup}}.
-
- @sort: storeAssociation, getAssociation, removeAssociation,
- useNonce
- """
-
- def storeAssociation(self, server_url, association):
- """
- This method puts a C{L{Association
- <openid.association.Association>}} object into storage,
- retrievable by server URL and handle.
-
-
- @param server_url: The URL of the identity server that this
- association is with. Because of the way the server
- portion of the library uses this interface, don't assume
- there are any limitations on the character set of the
- input string. In particular, expect to see unescaped
- non-url-safe characters in the server_url field.
-
- @type server_url: C{str}
-
-
- @param association: The C{L{Association
- <openid.association.Association>}} to store.
-
- @type association: C{L{Association
- <openid.association.Association>}}
-
-
- @return: C{None}
-
- @rtype: C{NoneType}
- """
- raise NotImplementedError
-
- def getAssociation(self, server_url, handle=None):
- """
- This method returns an C{L{Association
- <openid.association.Association>}} object from storage that
- matches the server URL and, if specified, handle. It returns
- C{None} if no such association is found or if the matching
- association is expired.
-
- If no handle is specified, the store may return any
- association which matches the server URL. If multiple
- associations are valid, the recommended return value for this
- method is the one most recently issued.
-
- This method is allowed (and encouraged) to garbage collect
- expired associations when found. This method must not return
- expired associations.
-
-
- @param server_url: The URL of the identity server to get the
- association for. Because of the way the server portion of
- the library uses this interface, don't assume there are
- any limitations on the character set of the input string.
- In particular, expect to see unescaped non-url-safe
- characters in the server_url field.
-
- @type server_url: C{str}
-
-
- @param handle: This optional parameter is the handle of the
- specific association to get. If no specific handle is
- provided, any valid association matching the server URL is
- returned.
-
- @type handle: C{str} or C{NoneType}
-
-
- @return: The C{L{Association
- <openid.association.Association>}} for the given identity
- server.
-
- @rtype: C{L{Association <openid.association.Association>}} or
- C{NoneType}
- """
- raise NotImplementedError
-
- def removeAssociation(self, server_url, handle):
- """
- This method removes the matching association if it's found,
- and returns whether the association was removed or not.
-
-
- @param server_url: The URL of the identity server the
- association to remove belongs to. Because of the way the
- server portion of the library uses this interface, don't
- assume there are any limitations on the character set of
- the input string. In particular, expect to see unescaped
- non-url-safe characters in the server_url field.
-
- @type server_url: C{str}
-
-
- @param handle: This is the handle of the association to
- remove. If there isn't an association found that matches
- both the given URL and handle, then there was no matching
- handle found.
-
- @type handle: C{str}
-
-
- @return: Returns whether or not the given association existed.
-
- @rtype: C{bool} or C{int}
- """
- raise NotImplementedError
-
- def useNonce(self, server_url, timestamp, salt):
- """Called when using a nonce.
-
- This method should return C{True} if the nonce has not been
- used before, and store it for a while to make sure nobody
- tries to use the same value again. If the nonce has already
- been used or the timestamp is not current, return C{False}.
-
- You may use L{openid.store.nonce.SKEW} for your timestamp window.
-
- @change: In earlier versions, round-trip nonces were used and
- a nonce was only valid if it had been previously stored
- with C{storeNonce}. Version 2.0 uses one-way nonces,
- requiring a different implementation here that does not
- depend on a C{storeNonce} call. (C{storeNonce} is no
- longer part of the interface.)
-
- @param server_url: The URL of the server from which the nonce
- originated.
-
- @type server_url: C{str}
-
- @param timestamp: The time that the nonce was created (to the
- nearest second), in seconds since January 1 1970 UTC.
- @type timestamp: C{int}
-
- @param salt: A random string that makes two nonces from the
- same server issued during the same second unique.
- @type salt: str
-
- @return: Whether or not the nonce was valid.
-
- @rtype: C{bool}
- """
- raise NotImplementedError
-
- def cleanupNonces(self):
- """Remove expired nonces from the store.
-
- Discards any nonce from storage that is old enough that its
- timestamp would not pass L{useNonce}.
-
- This method is not called in the normal operation of the
- library. It provides a way for store admins to keep
- their storage from filling up with expired data.
-
- @return: the number of nonces expired.
- @returntype: int
- """
- raise NotImplementedError
-
- def cleanupAssociations(self):
- """Remove expired associations from the store.
-
- This method is not called in the normal operation of the
- library. It provides a way for store admins to keep
- their storage from filling up with expired data.
-
- @return: the number of associations expired.
- @returntype: int
- """
- raise NotImplementedError
-
- def cleanup(self):
- """Shortcut for C{L{cleanupNonces}()}, C{L{cleanupAssociations}()}.
-
- This method is not called in the normal operation of the
- library. It provides a way for store admins to keep
- their storage from filling up with expired data.
- """
- return self.cleanupNonces(), self.cleanupAssociations()
diff --git a/askbot/deps/openid/store/memstore.py b/askbot/deps/openid/store/memstore.py
deleted file mode 100644
index a088c0d0..00000000
--- a/askbot/deps/openid/store/memstore.py
+++ /dev/null
@@ -1,125 +0,0 @@
-"""A simple store using only in-process memory."""
-
-from askbot.deps.openid.store import nonce
-
-import copy
-import time
-
-class ServerAssocs(object):
- def __init__(self):
- self.assocs = {}
-
- def set(self, assoc):
- self.assocs[assoc.handle] = assoc
-
- def get(self, handle):
- return self.assocs.get(handle)
-
- def remove(self, handle):
- try:
- del self.assocs[handle]
- except KeyError:
- return False
- else:
- return True
-
- def best(self):
- """Returns association with the oldest issued date.
-
- or None if there are no associations.
- """
- best = None
- for assoc in self.assocs.values():
- if best is None or best.issued < assoc.issued:
- best = assoc
- return best
-
- def cleanup(self):
- """Remove expired associations.
-
- @return: tuple of (removed associations, remaining associations)
- """
- remove = []
- for handle, assoc in self.assocs.iteritems():
- if assoc.getExpiresIn() == 0:
- remove.append(handle)
- for handle in remove:
- del self.assocs[handle]
- return len(remove), len(self.assocs)
-
-
-
-class MemoryStore(object):
- """In-process memory store.
-
- Use for single long-running processes. No persistence supplied.
- """
- def __init__(self):
- self.server_assocs = {}
- self.nonces = {}
-
- def _getServerAssocs(self, server_url):
- try:
- return self.server_assocs[server_url]
- except KeyError:
- assocs = self.server_assocs[server_url] = ServerAssocs()
- return assocs
-
- def storeAssociation(self, server_url, assoc):
- assocs = self._getServerAssocs(server_url)
- assocs.set(copy.deepcopy(assoc))
-
- def getAssociation(self, server_url, handle=None):
- assocs = self._getServerAssocs(server_url)
- if handle is None:
- return assocs.best()
- else:
- return assocs.get(handle)
-
- def removeAssociation(self, server_url, handle):
- assocs = self._getServerAssocs(server_url)
- return assocs.remove(handle)
-
- def useNonce(self, server_url, timestamp, salt):
- if abs(timestamp - time.time()) > nonce.SKEW:
- return False
-
- anonce = (str(server_url), int(timestamp), str(salt))
- if anonce in self.nonces:
- return False
- else:
- self.nonces[anonce] = None
- return True
-
- def cleanupNonces(self):
- now = time.time()
- expired = []
- for anonce in self.nonces.iterkeys():
- if abs(anonce[1] - now) > nonce.SKEW:
- # removing items while iterating over the set could be bad.
- expired.append(anonce)
-
- for anonce in expired:
- del self.nonces[anonce]
- return len(expired)
-
- def cleanupAssociations(self):
- remove_urls = []
- removed_assocs = 0
- for server_url, assocs in self.server_assocs.iteritems():
- removed, remaining = assocs.cleanup()
- removed_assocs += removed
- if not remaining:
- remove_urls.append(server_url)
-
- # Remove entries from server_assocs that had none remaining.
- for server_url in remove_urls:
- del self.server_assocs[server_url]
- return removed_assocs
-
- def __eq__(self, other):
- return ((self.server_assocs == other.server_assocs) and
- (self.nonces == other.nonces))
-
- def __ne__(self, other):
- return not (self == other)
diff --git a/askbot/deps/openid/store/nonce.py b/askbot/deps/openid/store/nonce.py
deleted file mode 100644
index 7847f9fa..00000000
--- a/askbot/deps/openid/store/nonce.py
+++ /dev/null
@@ -1,98 +0,0 @@
-__all__ = [
- 'split',
- 'mkNonce',
- 'checkTimestamp',
- ]
-
-from askbot.deps.openid import cryptutil
-from time import strptime, strftime, gmtime, time
-from calendar import timegm
-import string
-
-NONCE_CHARS = string.ascii_letters + string.digits
-
-# Keep nonces for five hours (allow five hours for the combination of
-# request time and clock skew). This is probably way more than is
-# necessary, but there is not much overhead in storing nonces.
-SKEW = 60 * 60 * 5
-
-time_fmt = '%Y-%m-%dT%H:%M:%SZ'
-time_str_len = len('0000-00-00T00:00:00Z')
-
-def split(nonce_string):
- """Extract a timestamp from the given nonce string
-
- @param nonce_string: the nonce from which to extract the timestamp
- @type nonce_string: str
-
- @returns: A pair of a Unix timestamp and the salt characters
- @returntype: (int, str)
-
- @raises ValueError: if the nonce does not start with a correctly
- formatted time string
- """
- timestamp_str = nonce_string[:time_str_len]
- try:
- timestamp = timegm(strptime(timestamp_str, time_fmt))
- except AssertionError: # Python 2.2
- timestamp = -1
- if timestamp < 0:
- raise ValueError('time out of range')
- return timestamp, nonce_string[time_str_len:]
-
-def checkTimestamp(nonce_string, allowed_skew=SKEW, now=None):
- """Is the timestamp that is part of the specified nonce string
- within the allowed clock-skew of the current time?
-
- @param nonce_string: The nonce that is being checked
- @type nonce_string: str
-
- @param allowed_skew: How many seconds should be allowed for
- completing the request, allowing for clock skew.
- @type allowed_skew: int
-
- @param now: The current time, as a Unix timestamp
- @type now: int
-
- @returntype: bool
- @returns: Whether the timestamp is correctly formatted and within
- the allowed skew of the current time.
- """
- try:
- stamp, _ = split(nonce_string)
- except ValueError:
- return False
- else:
- if now is None:
- now = time()
-
- # Time after which we should not use the nonce
- past = now - allowed_skew
-
- # Time that is too far in the future for us to allow
- future = now + allowed_skew
-
- # the stamp is not too far in the future and is not too far in
- # the past
- return past <= stamp <= future
-
-def mkNonce(when=None):
- """Generate a nonce with the current timestamp
-
- @param when: Unix timestamp representing the issue time of the
- nonce. Defaults to the current time.
- @type when: int
-
- @returntype: str
- @returns: A string that should be usable as a one-way nonce
-
- @see: time
- """
- salt = cryptutil.randomString(6, NONCE_CHARS)
- if when is None:
- t = gmtime()
- else:
- t = gmtime(when)
-
- time_str = strftime(time_fmt, t)
- return time_str + salt
diff --git a/askbot/deps/openid/store/sqlstore.py b/askbot/deps/openid/store/sqlstore.py
deleted file mode 100644
index cceebd58..00000000
--- a/askbot/deps/openid/store/sqlstore.py
+++ /dev/null
@@ -1,516 +0,0 @@
-"""
-This module contains C{L{OpenIDStore}} implementations that use
-various SQL databases to back them.
-
-Example of how to initialize a store database::
-
- python -c 'from askbot.deps.openid.store import sqlstore; import pysqlite2.dbapi2; sqlstore.SQLiteStore(pysqlite2.dbapi2.connect("cstore.db")).createTables()'
-"""
-import re
-import time
-
-from askbot.deps.openid.association import Association
-from askbot.deps.openid.store.interface import OpenIDStore
-from askbot.deps.openid.store import nonce
-
-def _inTxn(func):
- def wrapped(self, *args, **kwargs):
- return self._callInTransaction(func, self, *args, **kwargs)
-
- if hasattr(func, '__name__'):
- try:
- wrapped.__name__ = func.__name__[4:]
- except TypeError:
- pass
-
- if hasattr(func, '__doc__'):
- wrapped.__doc__ = func.__doc__
-
- return wrapped
-
-class SQLStore(OpenIDStore):
- """
- This is the parent class for the SQL stores, which contains the
- logic common to all of the SQL stores.
-
- The table names used are determined by the class variables
- C{L{associations_table}} and
- C{L{nonces_table}}. To change the name of the tables used, pass
- new table names into the constructor.
-
- To create the tables with the proper schema, see the
- C{L{createTables}} method.
-
- This class shouldn't be used directly. Use one of its subclasses
- instead, as those contain the code necessary to use a specific
- database.
-
- All methods other than C{L{__init__}} and C{L{createTables}}
- should be considered implementation details.
-
-
- @cvar associations_table: This is the default name of the table to
- keep associations in
-
- @cvar nonces_table: This is the default name of the table to keep
- nonces in.
-
-
- @sort: __init__, createTables
- """
-
- associations_table = 'oid_associations'
- nonces_table = 'oid_nonces'
-
- def __init__(self, conn, associations_table=None, nonces_table=None):
- """
- This creates a new SQLStore instance. It requires an
- established database connection be given to it, and it allows
- overriding the default table names.
-
-
- @param conn: This must be an established connection to a
- database of the correct type for the SQLStore subclass
- you're using.
-
- @type conn: A python database API compatible connection
- object.
-
-
- @param associations_table: This is an optional parameter to
- specify the name of the table used for storing
- associations. The default value is specified in
- C{L{SQLStore.associations_table}}.
-
- @type associations_table: C{str}
-
-
- @param nonces_table: This is an optional parameter to specify
- the name of the table used for storing nonces. The
- default value is specified in C{L{SQLStore.nonces_table}}.
-
- @type nonces_table: C{str}
- """
- self.conn = conn
- self.cur = None
- self._statement_cache = {}
- self._table_names = {
- 'associations': associations_table or self.associations_table,
- 'nonces': nonces_table or self.nonces_table,
- }
- self.max_nonce_age = 6 * 60 * 60 # Six hours, in seconds
-
- # DB API extension: search for "Connection Attributes .Error,
- # .ProgrammingError, etc." in
- # http://www.python.org/dev/peps/pep-0249/
- if (hasattr(self.conn, 'IntegrityError') and
- hasattr(self.conn, 'OperationalError')):
- self.exceptions = self.conn
-
- if not (hasattr(self.exceptions, 'IntegrityError') and
- hasattr(self.exceptions, 'OperationalError')):
- raise RuntimeError("Error using database connection module "
- "(Maybe it can't be imported?)")
-
- def blobDecode(self, blob):
- """Convert a blob as returned by the SQL engine into a str object.
-
- str -> str"""
- return blob
-
- def blobEncode(self, s):
- """Convert a str object into the necessary object for storing
- in the database as a blob."""
- return s
-
- def _getSQL(self, sql_name):
- try:
- return self._statement_cache[sql_name]
- except KeyError:
- sql = getattr(self, sql_name)
- sql %= self._table_names
- self._statement_cache[sql_name] = sql
- return sql
-
- def _execSQL(self, sql_name, *args):
- sql = self._getSQL(sql_name)
- # Kludge because we have reports of postgresql not quoting
- # arguments if they are passed in as unicode instead of str.
- # Currently the strings in our tables just have ascii in them,
- # so this ought to be safe.
- def unicode_to_str(arg):
- if isinstance(arg, unicode):
- return str(arg)
- else:
- return arg
- str_args = map(unicode_to_str, args)
- self.cur.execute(sql, str_args)
-
- def __getattr__(self, attr):
- # if the attribute starts with db_, use a default
- # implementation that looks up the appropriate SQL statement
- # as an attribute of this object and executes it.
- if attr[:3] == 'db_':
- sql_name = attr[3:] + '_sql'
- def func(*args):
- return self._execSQL(sql_name, *args)
- setattr(self, attr, func)
- return func
- else:
- raise AttributeError('Attribute %r not found' % (attr,))
-
- def _callInTransaction(self, func, *args, **kwargs):
- """Execute the given function inside of a transaction, with an
- open cursor. If no exception is raised, the transaction is
- comitted, otherwise it is rolled back."""
- # No nesting of transactions
- self.conn.rollback()
-
- try:
- self.cur = self.conn.cursor()
- try:
- ret = func(*args, **kwargs)
- finally:
- self.cur.close()
- self.cur = None
- except:
- self.conn.rollback()
- raise
- else:
- self.conn.commit()
-
- return ret
-
- def txn_createTables(self):
- """
- This method creates the database tables necessary for this
- store to work. It should not be called if the tables already
- exist.
- """
- self.db_create_nonce()
- self.db_create_assoc()
-
- createTables = _inTxn(txn_createTables)
-
- def txn_storeAssociation(self, server_url, association):
- """Set the association for the server URL.
-
- Association -> NoneType
- """
- a = association
- self.db_set_assoc(
- server_url,
- a.handle,
- self.blobEncode(a.secret),
- a.issued,
- a.lifetime,
- a.assoc_type)
-
- storeAssociation = _inTxn(txn_storeAssociation)
-
- def txn_getAssociation(self, server_url, handle=None):
- """Get the most recent association that has been set for this
- server URL and handle.
-
- str -> NoneType or Association
- """
- if handle is not None:
- self.db_get_assoc(server_url, handle)
- else:
- self.db_get_assocs(server_url)
-
- rows = self.cur.fetchall()
- if len(rows) == 0:
- return None
- else:
- associations = []
- for values in rows:
- assoc = Association(*values)
- assoc.secret = self.blobDecode(assoc.secret)
- if assoc.getExpiresIn() == 0:
- self.txn_removeAssociation(server_url, assoc.handle)
- else:
- associations.append((assoc.issued, assoc))
-
- if associations:
- associations.sort()
- return associations[-1][1]
- else:
- return None
-
- getAssociation = _inTxn(txn_getAssociation)
-
- def txn_removeAssociation(self, server_url, handle):
- """Remove the association for the given server URL and handle,
- returning whether the association existed at all.
-
- (str, str) -> bool
- """
- self.db_remove_assoc(server_url, handle)
- return self.cur.rowcount > 0 # -1 is undefined
-
- removeAssociation = _inTxn(txn_removeAssociation)
-
- def txn_useNonce(self, server_url, timestamp, salt):
- """Return whether this nonce is present, and if it is, then
- remove it from the set.
-
- str -> bool"""
- if abs(timestamp - time.time()) > nonce.SKEW:
- return False
-
- try:
- self.db_add_nonce(server_url, timestamp, salt)
- except self.exceptions.IntegrityError:
- # The key uniqueness check failed
- return False
- else:
- # The nonce was successfully added
- return True
-
- useNonce = _inTxn(txn_useNonce)
-
- def txn_cleanupNonces(self):
- self.db_clean_nonce(int(time.time()) - nonce.SKEW)
- return self.cur.rowcount
-
- cleanupNonces = _inTxn(txn_cleanupNonces)
-
- def txn_cleanupAssociations(self):
- self.db_clean_assoc(int(time.time()))
- return self.cur.rowcount
-
- cleanupAssociations = _inTxn(txn_cleanupAssociations)
-
-
-class SQLiteStore(SQLStore):
- """
- This is an SQLite-based specialization of C{L{SQLStore}}.
-
- To create an instance, see C{L{SQLStore.__init__}}. To create the
- tables it will use, see C{L{SQLStore.createTables}}.
-
- All other methods are implementation details.
- """
-
- create_nonce_sql = """
- CREATE TABLE %(nonces)s (
- server_url VARCHAR,
- timestamp INTEGER,
- salt CHAR(40),
- UNIQUE(server_url, timestamp, salt)
- );
- """
-
- create_assoc_sql = """
- CREATE TABLE %(associations)s
- (
- server_url VARCHAR(2047),
- handle VARCHAR(255),
- secret BLOB(128),
- issued INTEGER,
- lifetime INTEGER,
- assoc_type VARCHAR(64),
- PRIMARY KEY (server_url, handle)
- );
- """
-
- set_assoc_sql = ('INSERT OR REPLACE INTO %(associations)s '
- '(server_url, handle, secret, issued, '
- 'lifetime, assoc_type) '
- 'VALUES (?, ?, ?, ?, ?, ?);')
- get_assocs_sql = ('SELECT handle, secret, issued, lifetime, assoc_type '
- 'FROM %(associations)s WHERE server_url = ?;')
- get_assoc_sql = (
- 'SELECT handle, secret, issued, lifetime, assoc_type '
- 'FROM %(associations)s WHERE server_url = ? AND handle = ?;')
-
- get_expired_sql = ('SELECT server_url '
- 'FROM %(associations)s WHERE issued + lifetime < ?;')
-
- remove_assoc_sql = ('DELETE FROM %(associations)s '
- 'WHERE server_url = ? AND handle = ?;')
-
- clean_assoc_sql = 'DELETE FROM %(associations)s WHERE issued + lifetime < ?;'
-
- add_nonce_sql = 'INSERT INTO %(nonces)s VALUES (?, ?, ?);'
-
- clean_nonce_sql = 'DELETE FROM %(nonces)s WHERE timestamp < ?;'
-
- def blobDecode(self, buf):
- return str(buf)
-
- def blobEncode(self, s):
- return buffer(s)
-
- def useNonce(self, *args, **kwargs):
- # Older versions of the sqlite wrapper do not raise
- # IntegrityError as they should, so we have to detect the
- # message from the OperationalError.
- try:
- return super(SQLiteStore, self).useNonce(*args, **kwargs)
- except self.exceptions.OperationalError, why:
- if re.match('^columns .* are not unique$', why[0]):
- return False
- else:
- raise
-
-class MySQLStore(SQLStore):
- """
- This is a MySQL-based specialization of C{L{SQLStore}}.
-
- Uses InnoDB tables for transaction support.
-
- To create an instance, see C{L{SQLStore.__init__}}. To create the
- tables it will use, see C{L{SQLStore.createTables}}.
-
- All other methods are implementation details.
- """
-
- try:
- import MySQLdb as exceptions
- except ImportError:
- exceptions = None
-
- create_nonce_sql = """
- CREATE TABLE %(nonces)s (
- server_url BLOB NOT NULL,
- timestamp INTEGER NOT NULL,
- salt CHAR(40) NOT NULL,
- PRIMARY KEY (server_url(255), timestamp, salt)
- )
- ENGINE=InnoDB;
- """
-
- create_assoc_sql = """
- CREATE TABLE %(associations)s
- (
- server_url BLOB NOT NULL,
- handle VARCHAR(255) NOT NULL,
- secret BLOB NOT NULL,
- issued INTEGER NOT NULL,
- lifetime INTEGER NOT NULL,
- assoc_type VARCHAR(64) NOT NULL,
- PRIMARY KEY (server_url(255), handle)
- )
- ENGINE=InnoDB;
- """
-
- set_assoc_sql = ('REPLACE INTO %(associations)s '
- 'VALUES (%%s, %%s, %%s, %%s, %%s, %%s);')
- get_assocs_sql = ('SELECT handle, secret, issued, lifetime, assoc_type'
- ' FROM %(associations)s WHERE server_url = %%s;')
- get_expired_sql = ('SELECT server_url '
- 'FROM %(associations)s WHERE issued + lifetime < %%s;')
-
- get_assoc_sql = (
- 'SELECT handle, secret, issued, lifetime, assoc_type'
- ' FROM %(associations)s WHERE server_url = %%s AND handle = %%s;')
- remove_assoc_sql = ('DELETE FROM %(associations)s '
- 'WHERE server_url = %%s AND handle = %%s;')
-
- clean_assoc_sql = 'DELETE FROM %(associations)s WHERE issued + lifetime < %%s;'
-
- add_nonce_sql = 'INSERT INTO %(nonces)s VALUES (%%s, %%s, %%s);'
-
- clean_nonce_sql = 'DELETE FROM %(nonces)s WHERE timestamp < %%s;'
-
- def blobDecode(self, blob):
- if type(blob) is str:
- # Versions of MySQLdb >= 1.2.2
- return blob
- else:
- # Versions of MySQLdb prior to 1.2.2 (as far as we can tell)
- return blob.tostring()
-
-class PostgreSQLStore(SQLStore):
- """
- This is a PostgreSQL-based specialization of C{L{SQLStore}}.
-
- To create an instance, see C{L{SQLStore.__init__}}. To create the
- tables it will use, see C{L{SQLStore.createTables}}.
-
- All other methods are implementation details.
- """
-
- try:
- import psycopg as exceptions
- except ImportError:
- # psycopg2 has the dbapi extension where the exception classes
- # are available on the connection object. A psycopg2
- # connection will use the correct exception classes because of
- # this, and a psycopg connection will fall through to use the
- # psycopg imported above.
- exceptions = None
-
- create_nonce_sql = """
- CREATE TABLE %(nonces)s (
- server_url VARCHAR(2047) NOT NULL,
- timestamp INTEGER NOT NULL,
- salt CHAR(40) NOT NULL,
- PRIMARY KEY (server_url, timestamp, salt)
- );
- """
-
- create_assoc_sql = """
- CREATE TABLE %(associations)s
- (
- server_url VARCHAR(2047) NOT NULL,
- handle VARCHAR(255) NOT NULL,
- secret BYTEA NOT NULL,
- issued INTEGER NOT NULL,
- lifetime INTEGER NOT NULL,
- assoc_type VARCHAR(64) NOT NULL,
- PRIMARY KEY (server_url, handle),
- CONSTRAINT secret_length_constraint CHECK (LENGTH(secret) <= 128)
- );
- """
-
- def db_set_assoc(self, server_url, handle, secret, issued, lifetime, assoc_type):
- """
- Set an association. This is implemented as a method because
- REPLACE INTO is not supported by PostgreSQL (and is not
- standard SQL).
- """
- result = self.db_get_assoc(server_url, handle)
- rows = self.cur.fetchall()
- if len(rows):
- # Update the table since this associations already exists.
- return self.db_update_assoc(secret, issued, lifetime, assoc_type,
- server_url, handle)
- else:
- # Insert a new record because this association wasn't
- # found.
- return self.db_new_assoc(server_url, handle, secret, issued,
- lifetime, assoc_type)
-
- new_assoc_sql = ('INSERT INTO %(associations)s '
- 'VALUES (%%s, %%s, %%s, %%s, %%s, %%s);')
- update_assoc_sql = ('UPDATE %(associations)s SET '
- 'secret = %%s, issued = %%s, '
- 'lifetime = %%s, assoc_type = %%s '
- 'WHERE server_url = %%s AND handle = %%s;')
- get_assocs_sql = ('SELECT handle, secret, issued, lifetime, assoc_type'
- ' FROM %(associations)s WHERE server_url = %%s;')
- get_expired_sql = ('SELECT server_url '
- 'FROM %(associations)s WHERE issued + lifetime < %%s;')
-
- get_assoc_sql = (
- 'SELECT handle, secret, issued, lifetime, assoc_type'
- ' FROM %(associations)s WHERE server_url = %%s AND handle = %%s;')
- remove_assoc_sql = ('DELETE FROM %(associations)s '
- 'WHERE server_url = %%s AND handle = %%s;')
-
- clean_assoc_sql = 'DELETE FROM %(associations)s WHERE issued + lifetime < %%s;'
-
- add_nonce_sql = 'INSERT INTO %(nonces)s VALUES (%%s, %%s, %%s);'
-
- clean_nonce_sql = 'DELETE FROM %(nonces)s WHERE timestamp < %%s;'
-
- def blobEncode(self, blob):
- try:
- from psycopg2 import Binary
- except ImportError:
- from psycopg import Binary
-
- return Binary(blob)
diff --git a/askbot/deps/openid/test/__init__.py b/askbot/deps/openid/test/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/askbot/deps/openid/test/__init__.py
+++ /dev/null
diff --git a/askbot/deps/openid/test/cryptutil.py b/askbot/deps/openid/test/cryptutil.py
deleted file mode 100644
index 62d59ce2..00000000
--- a/askbot/deps/openid/test/cryptutil.py
+++ /dev/null
@@ -1,108 +0,0 @@
-import sys
-import random
-import os.path
-
-from askbot.deps.openid import cryptutil
-
-# Most of the purpose of this test is to make sure that cryptutil can
-# find a good source of randomness on this machine.
-
-def test_cryptrand():
- # It's possible, but HIGHLY unlikely that a correct implementation
- # will fail by returning the same number twice
-
- s = cryptutil.getBytes(32)
- t = cryptutil.getBytes(32)
- assert len(s) == 32
- assert len(t) == 32
- assert s != t
-
- a = cryptutil.randrange(2L ** 128)
- b = cryptutil.randrange(2L ** 128)
- assert type(a) is long
- assert type(b) is long
- assert b != a
-
- # Make sure that we can generate random numbers that are larger
- # than platform int size
- cryptutil.randrange(long(sys.maxint) + 1L)
-
-def test_reversed():
- if hasattr(cryptutil, 'reversed'):
- cases = [
- ('', ''),
- ('a', 'a'),
- ('ab', 'ba'),
- ('abc', 'cba'),
- ('abcdefg', 'gfedcba'),
- ([], []),
- ([1], [1]),
- ([1,2], [2,1]),
- ([1,2,3], [3,2,1]),
- (range(1000), range(999, -1, -1)),
- ]
-
- for case, expected in cases:
- expected = list(expected)
- actual = list(cryptutil.reversed(case))
- assert actual == expected, (case, expected, actual)
- twice = list(cryptutil.reversed(actual))
- assert twice == list(case), (actual, case, twice)
-
-def test_binaryLongConvert():
- MAX = sys.maxint
- for iteration in xrange(500):
- n = 0L
- for i in range(10):
- n += long(random.randrange(MAX))
-
- s = cryptutil.longToBinary(n)
- assert type(s) is str
- n_prime = cryptutil.binaryToLong(s)
- assert n == n_prime, (n, n_prime)
-
- cases = [
- ('\x00', 0L),
- ('\x01', 1L),
- ('\x7F', 127L),
- ('\x00\xFF', 255L),
- ('\x00\x80', 128L),
- ('\x00\x81', 129L),
- ('\x00\x80\x00', 32768L),
- ('OpenID is cool', 1611215304203901150134421257416556L)
- ]
-
- for s, n in cases:
- n_prime = cryptutil.binaryToLong(s)
- s_prime = cryptutil.longToBinary(n)
- assert n == n_prime, (s, n, n_prime)
- assert s == s_prime, (n, s, s_prime)
-
-def test_longToBase64():
- f = file(os.path.join(os.path.dirname(__file__), 'n2b64'))
- try:
- for line in f:
- parts = line.strip().split(' ')
- assert parts[0] == cryptutil.longToBase64(long(parts[1]))
- finally:
- f.close()
-
-def test_base64ToLong():
- f = file(os.path.join(os.path.dirname(__file__), 'n2b64'))
- try:
- for line in f:
- parts = line.strip().split(' ')
- assert long(parts[1]) == cryptutil.base64ToLong(parts[0])
- finally:
- f.close()
-
-
-def test():
- test_reversed()
- test_binaryLongConvert()
- test_cryptrand()
- test_longToBase64()
- test_base64ToLong()
-
-if __name__ == '__main__':
- test()
diff --git a/askbot/deps/openid/test/data/accept.txt b/askbot/deps/openid/test/data/accept.txt
deleted file mode 100644
index 0853321a..00000000
--- a/askbot/deps/openid/test/data/accept.txt
+++ /dev/null
@@ -1,118 +0,0 @@
-# Accept: [Accept: header value from RFC2616,
-# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html]
-# Available: [whitespace-separated content types]
-# Expected: [Accept-header like list, containing the available content
-# types with their q-values]
-
-Accept: */*
-Available: text/plain
-Expected: text/plain; q=1.0
-
-Accept: */*
-Available: text/plain, text/html
-Expected: text/plain; q=1.0, text/html; q=1.0
-
-# The order matters
-Accept: */*
-Available: text/html, text/plain
-Expected: text/html; q=1.0, text/plain; q=1.0
-
-Accept: text/*, */*; q=0.9
-Available: text/plain, image/jpeg
-Expected: text/plain; q=1.0, image/jpeg; q=0.9
-
-Accept: text/*, */*; q=0.9
-Available: image/jpeg, text/plain
-Expected: text/plain; q=1.0, image/jpeg; q=0.9
-
-# wildcard subtypes still reject differing main types
-Accept: text/*
-Available: image/jpeg, text/plain
-Expected: text/plain; q=1.0
-
-Accept: text/html
-Available: text/html
-Expected: text/html; q=1.0
-
-Accept: text/html, text/*
-Available: text/html
-Expected: text/html; q=1.0
-
-Accept: text/html, text/*
-Available: text/plain, text/html
-Expected: text/plain; q=1.0, text/html; q=1.0
-
-Accept: text/html, text/*; q=0.9
-Available: text/plain, text/html
-Expected: text/html; q=1.0, text/plain; q=0.9
-
-# If a more specific type has a higher q-value, then the higher value wins
-Accept: text/*; q=0.9, text/html
-Available: text/plain, text/html
-Expected: text/html; q=1.0, text/plain; q=0.9
-
-Accept: */*, text/*; q=0.9, text/html; q=0.1
-Available: text/plain, text/html, image/monkeys
-Expected: image/monkeys; q=1.0, text/plain; q=0.9, text/html; q=0.1
-
-Accept: text/*, text/html; q=0
-Available: text/html
-Expected:
-
-Accept: text/*, text/html; q=0
-Available: text/html, text/plain
-Expected: text/plain; q=1.0
-
-Accept: text/html
-Available: text/plain
-Expected:
-
-Accept: application/xrds+xml, text/html; q=0.9
-Available: application/xrds+xml, text/html
-Expected: application/xrds+xml; q=1.0, text/html; q=0.9
-
-Accept: application/xrds+xml, */*; q=0.9
-Available: application/xrds+xml, text/html
-Expected: application/xrds+xml; q=1.0, text/html; q=0.9
-
-Accept: application/xrds+xml, application/xhtml+xml; q=0.9, text/html; q=0.8, text/xml; q=0.7
-Available: application/xrds+xml, text/html
-Expected: application/xrds+xml; q=1.0, text/html; q=0.8
-
-# See http://www.rfc-editor.org/rfc/rfc3023.txt, section A.13
-Accept: application/xrds
-Available: application/xrds+xml
-Expected:
-
-Accept: application/xrds+xml
-Available: application/xrds
-Expected:
-
-Accept: application/xml
-Available: application/xrds+xml
-Expected:
-
-Available: application/xrds+xml
-Accept: application/xml
-Expected:
-
-
-
-#################################################
-# The tests below this line are documentation of how this library
-# works. If the implementation changes, it's acceptable to change the
-# test to reflect that. These are specified so that we can make sure
-# that the current implementation actually works the way that we
-# expect it to given these inputs.
-
-Accept: text/html;level=1
-Available: text/html
-Expected: text/html; q=1.0
-
-Accept: text/html; level=1, text/html; level=9; q=0.1
-Available: text/html
-Expected: text/html; q=1.0
-
-Accept: text/html; level=9; q=0.1, text/html; level=1
-Available: text/html
-Expected: text/html; q=1.0
diff --git a/askbot/deps/openid/test/data/example-xrds.xml b/askbot/deps/openid/test/data/example-xrds.xml
deleted file mode 100644
index 101ba3bd..00000000
--- a/askbot/deps/openid/test/data/example-xrds.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Sample XRDS file at: NAME -->
-<xrds:XRDS
- xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)">
- <XRD>
-
- <Service priority="0">
- <Type>http://example.com/</Type>
- <URI>http://www.openidenabled.com/</URI>
- </Service>
-
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/openid-1.2-consumer-sqlitestore.db b/askbot/deps/openid/test/data/openid-1.2-consumer-sqlitestore.db
deleted file mode 100644
index 11444b26..00000000
--- a/askbot/deps/openid/test/data/openid-1.2-consumer-sqlitestore.db
+++ /dev/null
Binary files differ
diff --git a/askbot/deps/openid/test/data/test1-discover.txt b/askbot/deps/openid/test/data/test1-discover.txt
deleted file mode 100644
index 7ec9b878..00000000
--- a/askbot/deps/openid/test/data/test1-discover.txt
+++ /dev/null
@@ -1,137 +0,0 @@
-equiv
-Status: 200 OK
-Content-Type: text/html
-
-<html>
-<head>
-<meta http-equiv="YADIS_HEADER" content="URL_BASE/xrds">
-<title>Joe Schmoe's Homepage</title>
-</head>
-<body>
-<h1>Joe Schmoe's Homepage</h1>
-<p>Blah blah blah blah blah blah blah</p>
-</body>
-</html>
-
-header
-Status: 200 OK
-Content-Type: text/html
-YADIS_HEADER: URL_BASE/xrds
-
-<html>
-<head>
-<title>Joe Schmoe's Homepage</title>
-</head>
-<body>
-<h1>Joe Schmoe's Homepage</h1>
-<p>Blah blah blah blah blah blah blah</p>
-</body>
-
-xrds
-Status: 200 OK
-Content-Type: application/xrds+xml
-
-<XRDS Content>
-
-xrds_ctparam
-Status: 200 OK
-Content-Type: application/xrds+xml; charset=UTF8
-
-<XRDS Content>
-
-xrds_ctcase
-Status: 200 OK
-Content-Type: appliCATION/XRDS+xml
-
-<XRDS Content>
-
-xrds_html
-Status: 200 OK
-Content-Type: text/html
-
-<XRDS Content>
-
-redir_equiv
-Status: 302 Found
-Content-Type: text/plain
-Location: URL_BASE/equiv
-
-You are presently being redirected.
-
-redir_header
-Status: 302 Found
-Content-Type: text/plain
-Location: URL_BASE/header
-
-You are presently being redirected.
-
-redir_xrds
-Status: 302 Found
-Content-Type: application/xrds+xml
-Location: URL_BASE/xrds
-
-<XRDS Content>
-
-redir_xrds_html
-Status: 302 Found
-Content-Type: text/plain
-Location: URL_BASE/xrds_html
-
-You are presently being redirected.
-
-redir_redir_equiv
-Status: 302 Found
-Content-Type: text/plain
-Location: URL_BASE/redir_equiv
-
-You are presently being redirected.
-
-lowercase_header
-Status: 200 OK
-Content-Type: text/html
-x-xrds-location: URL_BASE/xrds
-
-<html>
-<head>
-<title>Joe Schmoe's Homepage</title>
-</head>
-<body>
-<h1>Joe Schmoe's Homepage</h1>
-<p>Blah blah blah blah blah blah blah</p>
-</body>
-
-404_server_response
-Status: 404 Not Found
-
-EEk!
-
-500_server_response
-Status: 500 Server error
-
-EEk!
-
-201_server_response
-Status: 201 Created
-
-EEk!
-
-404_with_header
-Status: 404 Not Found
-YADIS_HEADER: URL_BASE/xrds
-
-EEk!
-
-404_with_meta
-Status: 404 Not Found
-Content-Type: text/html
-
-<html>
-<head>
-<meta http-equiv="YADIS_HEADER" content="URL_BASE/xrds">
-<title>Joe Schmoe's Homepage</title>
-</head>
-<body>
-<h1>Joe Schmoe's Homepage</h1>
-<p>Blah blah blah blah blah blah blah</p>
-</body>
-</html>
diff --git a/askbot/deps/openid/test/data/test1-parsehtml.txt b/askbot/deps/openid/test/data/test1-parsehtml.txt
deleted file mode 100644
index feee692e..00000000
--- a/askbot/deps/openid/test/data/test1-parsehtml.txt
+++ /dev/null
@@ -1,152 +0,0 @@
-found
-<!-- minimal well-formed success case -->
-<html><head><meta http-equiv="X-XRDS-Location" content="found"></head></html>
-
-found
-<!-- minimal well-formed success case, xhtml closing, whitespace -->
-<html><head><meta http-equiv="X-XRDS-Location" content="found" /></head></html>
-
-found
-<!-- minimal well-formed success case, xhtml closing, no whitespace -->
-<html><head><meta http-equiv="X-XRDS-Location" content="found"/></head></html>
-
-found
-<!-- minimal success case -->
-<html><head><meta http-equiv="X-XRDS-Location" content="found">
-
-found
-<!-- ignore bogus top-level tags -->
-</porky><html><head><meta http-equiv="X-XRDS-Location" content="found">
-
-found
-<!-- Case folding for header name -->
-<html><head><meta http-equiv="x-xrds-location" content="found">
-
-found
-<!-- missing <html> tag -->
-<head><meta http-equiv="X-XRDS-Location" content="found">
-
-found
-<!-- javascript in head -->
-<html><head><script type="text/javascript">document.write("<body>");</script><META http-equiv="X-XRDS-Location" content="found">
-
-EOF
-<!-- no closing script tag -->
-<html><head><script type="text/javascript">document.write("<body>");<META http-equiv="X-XRDS-Location" content="found">
-
-found
-<!-- case folding for tag names -->
-<html><head><META http-equiv="X-XRDS-Location" content="found">
-
-found
-<!-- Stop after first one found -->
-<html><head>
-<meta http-equiv="x-xrds-location" content="found">
-<meta http-equiv="x-xrds-location" content="not-found">
-
-&
-<!-- standard entity -->
-<head><meta http-equiv="X-XRDS-Location" content="&amp;">
-
-found
-<!-- hex entity -->
-<html>
- <head>
- <meta http-equiv="X-XRDS-Location" content="&#x66;ound">
- </head>
-</html>
-
-found
-<!-- decimal entity -->
-<html>
- <head>
- <meta http-equiv="X-XRDS-Location" content="&#102;ound">
- </head>
-</html>
-
-/
-<!-- hex entity -->
-<html>
- <head>
- <meta http-equiv="X-XRDS-Location" content="&#x2f;">
- </head>
-</html>
-
-
-<!-- empty string -->
-<html><head><meta http-equiv="X-XRDS-Location" content="">
-
-EOF
-<!-- No markup, except this comment -->
-
-None
-<!-- No meta, just standard HTML -->
-<html>
- <head>
- <title>A boring document</title>
- </head>
- <body>
- <h1>A boring document</h1>
- <p>There's really nothing interesting about this</p>
- </body>
-</html>
-
-EOF
-<!-- No <html> or <head> -->
-<meta http-equiv="X-XRDS-Location" content="found">
-
-EOF
-<!-- No <head> tag -->
-<html><meta http-equiv="X-XRDS-Location" content="found">
-
-None
-<!-- No <html> or <head> and a <body> -->
-<body><meta http-equiv="X-XRDS-Location" content="found">
-
-None
-<!-- <head> and <html> reversed -->
-<head><html><meta http-equiv="X-XRDS-Location" content="found">
-
-None
-<!-- <meta> is inside of <body> -->
-<html><head><body><meta http-equiv="X-XRDS-Location" content="found">
-
-None
-<!-- <meta> is inside comment -->
-<html>
- <head>
- <!--<meta http-equiv="X-XRDS-Location" content="found">-->
- </head>
-</html>
-
-None
-<!-- <meta> is inside of <body> -->
-<html>
- <head>
- <title>Someone's blog</title>
- </head>
- <body>
- <h1>My blog</h1>
- <p>This is my blog</p>
- <h2>Comments</h2>
- <p><meta http-equiv="X-XRDS-Location" content="found"></p>
- </body>
-</html>
-
-None
-<!-- short head tag -->
-<html><head/>
-<meta http-equiv="X-XRDS-Location" content="found">
-
-None
-<!-- <body> comes first -->
-<body><html><head>
-<meta http-equiv="X-XRDS-Location" content="found">
-
-None
-<!-- </body> comes first -->
-</body><html><head>
-<meta http-equiv="X-XRDS-Location" content="found">
-
-None
-<!bad processing instruction!>
diff --git a/askbot/deps/openid/test/data/test_discover/openid.html b/askbot/deps/openid/test/data/test_discover/openid.html
deleted file mode 100644
index 1a57d44f..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
- <head>
- <title>Identity Page for Smoker</title>
- <link rel="openid.server" href="http://www.myopenid.com/server" />
- <link rel="openid.delegate" href="http://smoker.myopenid.com/" />
- </head>
- <body>
- <p>foo</p>
- </body>
-</html>
diff --git a/askbot/deps/openid/test/data/test_discover/openid2.html b/askbot/deps/openid/test/data/test_discover/openid2.html
deleted file mode 100644
index a74c042e..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid2.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
- <head>
- <title>Identity Page for Smoker</title>
- <link rel="openid2.provider" href="http://www.myopenid.com/server" />
- <link rel="openid2.local_id" href="http://smoker.myopenid.com/" />
- </head>
- <body>
- <p>foo</p>
- </body>
-</html>
diff --git a/askbot/deps/openid/test/data/test_discover/openid2_xrds.xml b/askbot/deps/openid/test/data/test_discover/openid2_xrds.xml
deleted file mode 100644
index 8091ab94..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid2_xrds.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- >
- <XRD>
- <Service priority="10">
- <Type>http://specs.openid.net/auth/2.0/signon</Type>
- <URI>http://www.myopenid.com/server</URI>
- <LocalID>http://smoker.myopenid.com/</LocalID>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/openid2_xrds_no_local_id.xml b/askbot/deps/openid/test/data/test_discover/openid2_xrds_no_local_id.xml
deleted file mode 100644
index e6a0eb97..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid2_xrds_no_local_id.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- >
- <XRD>
- <Service priority="10">
- <Type>http://specs.openid.net/auth/2.0/signon</Type>
- <URI>http://www.myopenid.com/server</URI>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/openid_1_and_2.html b/askbot/deps/openid/test/data/test_discover/openid_1_and_2.html
deleted file mode 100644
index 5e581287..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid_1_and_2.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
- <head>
- <title>Identity Page for Smoker</title>
- <link rel="openid2.provider openid.server" href="http://www.myopenid.com/server" />
- <link rel="openid2.local_id openid.delegate" href="http://smoker.myopenid.com/" />
- </head>
- <body>
- <p>foo</p>
- </body>
-</html>
diff --git a/askbot/deps/openid/test/data/test_discover/openid_1_and_2_xrds.xml b/askbot/deps/openid/test/data/test_discover/openid_1_and_2_xrds.xml
deleted file mode 100644
index 6d85d57e..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid_1_and_2_xrds.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
-
- <Service priority="10">
- <Type>http://specs.openid.net/auth/2.0/signon</Type>
- <Type>http://openid.net/signon/1.1</Type>
- <URI>http://www.myopenid.com/server</URI>
- <LocalID>http://smoker.myopenid.com/</LocalID>
- <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml b/askbot/deps/openid/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml
deleted file mode 100644
index db7282e2..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
-
- <Service priority="10">
- <Type>http://specs.openid.net/auth/2.0/signon</Type>
- <Type>http://openid.net/signon/1.0</Type>
- <Type>http://openid.net/signon/1.1</Type>
- <URI>http://www.myopenid.com/server</URI>
- <LocalID>http://smoker.myopenid.com/</LocalID>
- <openid:Delegate>http://localid.mismatch.invalid/</openid:Delegate>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/openid_and_yadis.html b/askbot/deps/openid/test/data/test_discover/openid_and_yadis.html
deleted file mode 100644
index 3befa6fc..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid_and_yadis.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
- <head>
- <title>Identity Page for Smoker</title>
- <meta http-equiv="X-XRDS-Location" content="http://someuser.unittest/xrds" />
- <link rel="openid.server" href="http://www.myopenid.com/server" />
- <link rel="openid.delegate" href="http://smoker.myopenid.com/" />
- </head>
- <body>
- <p>foo</p>
- </body>
-</html>
diff --git a/askbot/deps/openid/test/data/test_discover/openid_no_delegate.html b/askbot/deps/openid/test/data/test_discover/openid_no_delegate.html
deleted file mode 100644
index f5180b3d..00000000
--- a/askbot/deps/openid/test/data/test_discover/openid_no_delegate.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
- <head>
- <title>Identity Page for Smoker</title>
- <link rel="openid.server" href="http://www.myopenid.com/server" />
- </head>
- <body>
- <p>foo</p>
- </body>
-</html>
diff --git a/askbot/deps/openid/test/data/test_discover/yadis_0entries.xml b/askbot/deps/openid/test/data/test_discover/yadis_0entries.xml
deleted file mode 100644
index f161a0b3..00000000
--- a/askbot/deps/openid/test/data/test_discover/yadis_0entries.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
- <Service >
- <Type>http://is-not-openid.unittest/</Type>
- <URI>http://noffing.unittest./</URI>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/yadis_2_bad_local_id.xml b/askbot/deps/openid/test/data/test_discover/yadis_2_bad_local_id.xml
deleted file mode 100644
index 68c2ce1f..00000000
--- a/askbot/deps/openid/test/data/test_discover/yadis_2_bad_local_id.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
-
- <Service priority="10">
- <Type>http://specs.openid.net/auth/2.0/signon</Type>
- <URI>http://www.myopenid.com/server</URI>
- <LocalID>http://smoker.myopenid.com/</LocalID>
- <LocalID>http://localid.mismatch.invalid/</LocalID>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/yadis_2entries_delegate.xml b/askbot/deps/openid/test/data/test_discover/yadis_2entries_delegate.xml
deleted file mode 100644
index 372955b0..00000000
--- a/askbot/deps/openid/test/data/test_discover/yadis_2entries_delegate.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
- <CanonicalID>=!1000</CanonicalID>
-
- <Service priority="10">
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://www.myopenid.com/server</URI>
- <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
- </Service>
-
- <Service priority="20">
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://www.livejournal.com/openid/server.bml</URI>
- <openid:Delegate>http://frank.livejournal.com/</openid:Delegate>
- </Service>
-
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/yadis_2entries_idp.xml b/askbot/deps/openid/test/data/test_discover/yadis_2entries_idp.xml
deleted file mode 100644
index 9a07b3d4..00000000
--- a/askbot/deps/openid/test/data/test_discover/yadis_2entries_idp.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
- <CanonicalID>=!1000</CanonicalID>
-
- <Service priority="10">
- <Type>http://specs.openid.net/auth/2.0/signon</Type>
- <URI>http://www.myopenid.com/server</URI>
- <openid:LocalID>http://smoker.myopenid.com/</openid:LocalID>
- </Service>
-
- <Service priority="20">
- <Type>http://specs.openid.net/auth/2.0/server</Type>
- <URI>http://www.livejournal.com/openid/server.bml</URI>
- </Service>
-
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/yadis_another_delegate.xml b/askbot/deps/openid/test/data/test_discover/yadis_another_delegate.xml
deleted file mode 100644
index 2f3b9af3..00000000
--- a/askbot/deps/openid/test/data/test_discover/yadis_another_delegate.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
-
- <Service priority="10">
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://vroom.unittest/server</URI>
- <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/yadis_idp.xml b/askbot/deps/openid/test/data/test_discover/yadis_idp.xml
deleted file mode 100644
index f570d043..00000000
--- a/askbot/deps/openid/test/data/test_discover/yadis_idp.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
- <Service priority="10">
- <Type>http://specs.openid.net/auth/2.0/server</Type>
- <URI>http://www.myopenid.com/server</URI>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/yadis_idp_delegate.xml b/askbot/deps/openid/test/data/test_discover/yadis_idp_delegate.xml
deleted file mode 100644
index 54106005..00000000
--- a/askbot/deps/openid/test/data/test_discover/yadis_idp_delegate.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0"
- >
- <XRD>
- <Service>
- <Type>http://specs.openid.net/auth/2.0/server</Type>
- <URI>http://www.myopenid.com/server</URI>
- <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_discover/yadis_no_delegate.xml b/askbot/deps/openid/test/data/test_discover/yadis_no_delegate.xml
deleted file mode 100644
index fbd67349..00000000
--- a/askbot/deps/openid/test/data/test_discover/yadis_no_delegate.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- >
- <XRD>
- <Service priority="10">
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://www.myopenid.com/server</URI>
- </Service>
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/README b/askbot/deps/openid/test/data/test_etxrd/README
deleted file mode 100644
index 3739cf1c..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/README
+++ /dev/null
@@ -1,12 +0,0 @@
-delegated-20060809.xrds - results from proxy.xri.net, determined by
- Drummond and Kevin to be incorrect.
-delegated-20060809-r1.xrds - Drummond's 1st correction
-delegated-20060809-r2.xrds - Drummond's 2nd correction
-
-spoofs: keturn's (=!E4)'s attempts to log in with Drummond's i-number (=!D2)
-spoof1.xrds
-spoof2.xrds
-spoof3.xrds - attempt to steal @!C0!D2 by having "at least one" CanonicalID
- match the $res service ProviderID.
-
-ref.xrds - resolving @ootao*test.ref, which refers to a neustar XRI.
diff --git a/askbot/deps/openid/test/data/test_etxrd/delegated-20060809-r1.xrds b/askbot/deps/openid/test/data/test_etxrd/delegated-20060809-r1.xrds
deleted file mode 100644
index f994b140..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/delegated-20060809-r1.xrds
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://@ootao*test1" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*ootao</Query>
- <Status code="100"/>
- <Expires>2006-08-09T22:07:13.000Z</Expires>
- <ProviderID>xri://@</ProviderID>
- <LocalID priority="10">!5BAD.2AA.3C72.AF46</LocalID>
- <CanonicalID priority="10">@!5BAD.2AA.3C72.AF46</CanonicalID>
- <Service priority="10">
- <Type>xri://$res*auth*($v*2.0)</Type>
- <ProviderID>xri://!!1003</ProviderID>
- <MediaType>application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://resolve.ezibroker.net/resolve/@ootao/</URI>
- </Service>
- <Service priority="10">
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*test1</Query>
- <Status code="100">SUCCESS</Status>
- <ProviderID>xri://!!1003</ProviderID>
- <LocalID>!0000.0000.3B9A.CA01</LocalID>
- <CanonicalID>@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01</CanonicalID>
- <Service>
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/delegated-20060809-r2.xrds b/askbot/deps/openid/test/data/test_etxrd/delegated-20060809-r2.xrds
deleted file mode 100644
index 68c08dc4..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/delegated-20060809-r2.xrds
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://@ootao*test1" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*ootao</Query>
- <Status code="100"/>
- <Expires>2006-08-09T22:07:13.000Z</Expires>
- <ProviderID>xri://@</ProviderID>
- <LocalID priority="10">!5BAD.2AA.3C72.AF46</LocalID>
- <CanonicalID priority="10">@!5BAD.2AA.3C72.AF46</CanonicalID>
- <Service priority="10">
- <Type>xri://$res*auth*($v*2.0)</Type>
- <ProviderID>xri://@!5BAD.2AA.3C72.AF46</ProviderID>
- <MediaType>application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://resolve.ezibroker.net/resolve/@ootao/</URI>
- </Service>
- <Service priority="10">
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*test1</Query>
- <Status code="100">SUCCESS</Status>
- <ProviderID>xri://@!5BAD.2AA.3C72.AF46</ProviderID>
- <LocalID>!0000.0000.3B9A.CA01</LocalID>
- <CanonicalID>@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01</CanonicalID>
- <Service>
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/delegated-20060809.xrds b/askbot/deps/openid/test/data/test_etxrd/delegated-20060809.xrds
deleted file mode 100644
index 073ee688..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/delegated-20060809.xrds
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://@ootao*test1" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*ootao</Query>
- <Status code="100"/>
- <Expires>2006-08-09T22:07:13.000Z</Expires>
- <ProviderID>xri://@</ProviderID>
- <LocalID priority="10">!5BAD.2AA.3C72.AF46</LocalID>
- <CanonicalID priority="10">@!5BAD.2AA.3C72.AF46</CanonicalID>
- <Service priority="10">
- <Type>xri://$res*auth*($v*2.0)</Type>
- <ProviderID/>
- <MediaType>application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://resolve.ezibroker.net/resolve/@ootao/</URI>
- </Service>
- <Service priority="10">
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*test1</Query>
- <Status code="100">SUCCESS</Status>
- <ProviderID>xri://!!1003</ProviderID>
- <LocalID>!0000.0000.3B9A.CA01</LocalID>
- <CanonicalID>@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01</CanonicalID>
- <Service>
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/no-xrd.xml b/askbot/deps/openid/test/data/test_etxrd/no-xrd.xml
deleted file mode 100644
index ca66f735..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/no-xrd.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS
- xmlns:xrds="xri://$xrds"
- xmlns:openid="http://openid.net/xmlns/1.0"
- xmlns:typekey="http://typekey.com/xmlns/1.0"
- xmlns="xri://$xrd*($v*2.0)">
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/not-xrds.xml b/askbot/deps/openid/test/data/test_etxrd/not-xrds.xml
deleted file mode 100644
index 7f5bfd51..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/not-xrds.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<x></x>
diff --git a/askbot/deps/openid/test/data/test_etxrd/prefixsometimes.xrds b/askbot/deps/openid/test/data/test_etxrd/prefixsometimes.xrds
deleted file mode 100644
index 5522a6e5..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/prefixsometimes.xrds
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://@ootao*test1" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*ootao</Query>
- <Status code="100"/>
- <Expires>2006-08-09T22:07:13.000Z</Expires>
- <ProviderID>xri://@</ProviderID>
- <LocalID priority="10">!5BAD.2AA.3C72.AF46</LocalID>
- <CanonicalID priority="10">@!5BAD.2AA.3C72.AF46</CanonicalID>
- <Service priority="10">
- <Type>xri://$res*auth*($v*2.0)</Type>
- <ProviderID>xri://@!5BAD.2AA.3C72.AF46</ProviderID>
- <MediaType>application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://resolve.ezibroker.net/resolve/@ootao/</URI>
- </Service>
- <Service priority="10">
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*test1</Query>
- <Status code="100">SUCCESS</Status>
- <ProviderID>xri://@!5BAD.2AA.3C72.AF46</ProviderID>
- <LocalID>!0000.0000.3B9A.CA01</LocalID>
- <CanonicalID>xri://@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01</CanonicalID>
- <Service>
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/ref.xrds b/askbot/deps/openid/test/data/test_etxrd/ref.xrds
deleted file mode 100644
index 69cf683d..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/ref.xrds
+++ /dev/null
@@ -1,109 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://@ootao*test.ref" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*ootao</Query>
- <Status code="100"/>
- <Expires>2006-08-15T18:56:09.000Z</Expires>
- <ProviderID>xri://@</ProviderID>
- <LocalID priority="10">!5BAD.2AA.3C72.AF46</LocalID>
- <CanonicalID priority="10">@!5BAD.2AA.3C72.AF46</CanonicalID>
- <Service priority="10">
- <Type>xri://$res*auth*($v*2.0)</Type>
- <ProviderID/>
- <MediaType>application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://resolve.ezibroker.net/resolve/@ootao/</URI>
- </Service>
- <Service priority="10">
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*test.ref</Query>
- <Status code="100">SUCCESS</Status>
- <ProviderID>xri://!!1003</ProviderID>
- <LocalID>!0000.0000.3B9A.CA03</LocalID>
- <CanonicalID>@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA03</CanonicalID>
- <Ref>@!BAE.A650.823B.2475</Ref>
- <Service>
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
- <XRDS ref="xri://@!BAE.A650.823B.2475" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>!BAE.A650.823B.2475</Query>
- <Status code="100"/>
- <Expires>2006-08-15T18:56:10.000Z</Expires>
- <ProviderID>xri://@</ProviderID>
- <LocalID priority="10">!BAE.A650.823B.2475</LocalID>
- <CanonicalID priority="10">@!BAE.A650.823B.2475</CanonicalID>
- <Service priority="10">
- <Type select="true">(+wdnc)</Type>
- <ProviderID/>
- <Path select="true">(+wdnc)</Path>
- <URI append="none" priority="10">http://www.tcpacompliance.us</URI>
- </Service>
- <Service priority="10">
- <Type match="content" select="true">xri://$res*auth*($v*2.0)</Type>
- <ProviderID/>
- <MediaType match="content" select="false">application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://dev.dready.org/cgi-bin/xri</URI>
- </Service>
- <Service priority="10">
- <Type match="content" select="true">(+i-name)</Type>
- <ProviderID/>
- <Path match="content" select="true">(+i-name)</Path>
- <URI append="none" priority="10">http://www.inames.net</URI>
- </Service>
- <Service priority="10">
- <Type select="true">xri://+i-service*(+contact)*($v*1.0)</Type>
- <Type match="default" select="false"/>
- <ProviderID>xri://!!1001</ProviderID>
- <Path select="true">(+contact)</Path>
- <Path match="null" select="false"/>
- <MediaType select="false">text/html</MediaType>
- <MediaType match="default" select="false"/>
- <URI append="none" priority="10">http://www.neustar.biz</URI>
- </Service>
- </XRD>
- </XRDS>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>!BAE.A650.823B.2475</Query>
- <Status code="100"/>
- <Expires>2006-08-15T18:56:10.000Z</Expires>
- <ProviderID>xri://@</ProviderID>
- <LocalID priority="10">!BAE.A650.823B.2475</LocalID>
- <CanonicalID priority="10">@!BAE.A650.823B.2475</CanonicalID>
- <Service priority="10">
- <Type select="true">(+wdnc)</Type>
- <ProviderID/>
- <Path select="true">(+wdnc)</Path>
- <URI append="none" priority="10">http://www.tcpacompliance.us</URI>
- </Service>
- <Service priority="10">
- <Type match="content" select="true">xri://$res*auth*($v*2.0)</Type>
- <ProviderID/>
- <MediaType match="content" select="false">application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://dev.dready.org/cgi-bin/xri</URI>
- </Service>
- <Service priority="10">
- <Type match="content" select="true">(+i-name)</Type>
- <ProviderID/>
- <Path match="content" select="true">(+i-name)</Path>
- <URI append="none" priority="10">http://www.inames.net</URI>
- </Service>
- <Service priority="10">
- <Type select="true">xri://+i-service*(+contact)*($v*1.0)</Type>
- <Type match="default" select="false"/>
- <ProviderID>xri://!!1001</ProviderID>
- <Path select="true">(+contact)</Path>
- <Path match="null" select="false"/>
- <MediaType select="false">text/html</MediaType>
- <MediaType match="default" select="false"/>
- <URI append="none" priority="10">http://www.neustar.biz</URI>
- </Service>
- </XRD>
-</XRDS> \ No newline at end of file
diff --git a/askbot/deps/openid/test/data/test_etxrd/sometimesprefix.xrds b/askbot/deps/openid/test/data/test_etxrd/sometimesprefix.xrds
deleted file mode 100644
index eff75554..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/sometimesprefix.xrds
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://@ootao*test1" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*ootao</Query>
- <Status code="100"/>
- <Expires>2006-08-09T22:07:13.000Z</Expires>
- <ProviderID>xri://@</ProviderID>
- <LocalID priority="10">!5BAD.2AA.3C72.AF46</LocalID>
- <CanonicalID priority="10">xri://@!5BAD.2AA.3C72.AF46</CanonicalID>
- <Service priority="10">
- <Type>xri://$res*auth*($v*2.0)</Type>
- <ProviderID>xri://@!5BAD.2AA.3C72.AF46</ProviderID>
- <MediaType>application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://resolve.ezibroker.net/resolve/@ootao/</URI>
- </Service>
- <Service priority="10">
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*test1</Query>
- <Status code="100">SUCCESS</Status>
- <ProviderID>xri://@!5BAD.2AA.3C72.AF46</ProviderID>
- <LocalID>!0000.0000.3B9A.CA01</LocalID>
- <CanonicalID>@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01</CanonicalID>
- <Service>
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID/>
- <URI append="qxri" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/spoof1.xrds b/askbot/deps/openid/test/data/test_etxrd/spoof1.xrds
deleted file mode 100644
index 8e870c81..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/spoof1.xrds
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://=keturn*isDrummond" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*keturn</Query>
- <ProviderID>xri://=</ProviderID>
- <LocalID>!E4</LocalID>
- <CanonicalID>=!E4</CanonicalID>
-
- <Service>
- <Type>xri://$res*auth*($v*2.0)</Type>
- <URI>http://keturn.example.com/resolve/</URI>
- <ProviderID>=!E4</ProviderID>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*isDrummond</Query>
- <ProviderID>=!E4</ProviderID>
- <LocalID>!D2</LocalID>
- <CanonicalID>=!D2</CanonicalID>
- <Service>
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://keturn.example.com/openid</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/spoof2.xrds b/askbot/deps/openid/test/data/test_etxrd/spoof2.xrds
deleted file mode 100644
index 7547561e..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/spoof2.xrds
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://=keturn*isDrummond" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*keturn</Query>
- <ProviderID>xri://=</ProviderID>
- <LocalID>!E4</LocalID>
- <CanonicalID>=!E4</CanonicalID>
-
- <Service>
- <Type>xri://$res*auth*($v*2.0)</Type>
- <URI>http://keturn.example.com/resolve/</URI>
- <ProviderID>xri://=</ProviderID>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*isDrummond</Query>
- <ProviderID>xri://=</ProviderID>
- <LocalID>!D2</LocalID>
- <CanonicalID>=!D2</CanonicalID>
- <Service>
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://keturn.example.com/openid</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/spoof3.xrds b/askbot/deps/openid/test/data/test_etxrd/spoof3.xrds
deleted file mode 100644
index f4c43c9b..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/spoof3.xrds
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://=keturn*isDrummond" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*keturn</Query>
- <ProviderID>xri://@</ProviderID>
- <LocalID>@E4</LocalID>
- <CanonicalID>@!E4</CanonicalID>
-
- <Service>
- <Type>xri://$res*auth*($v*2.0)</Type>
- <URI>http://keturn.example.com/resolve/</URI>
- <ProviderID>@!E4</ProviderID>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*is</Query>
- <ProviderID>@!E4</ProviderID>
- <LocalID>!D2</LocalID>
- <CanonicalID>=!C0</CanonicalID>
- <CanonicalID>=!E4!01</CanonicalID>
- <Service>
- <Type>xri://$res*auth*($v*2.0)</Type>
- <URI>http://keturn.example.com/resolve/</URI>
- <ProviderID>@!C0</ProviderID>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*drummond</Query>
- <ProviderID>@!C0</ProviderID>
- <LocalID>!D2</LocalID>
- <CanonicalID>@!C0!D2</CanonicalID>
- <Service>
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://keturn.example.com/openid</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/status222.xrds b/askbot/deps/openid/test/data/test_etxrd/status222.xrds
deleted file mode 100644
index 84cd5c90..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/status222.xrds
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://=x" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*x</Query>
- <Status code="222">The subsegment does not exist</Status>
- <Expires>2006-08-18T00:02:35.000Z</Expires>
- <ProviderID>xri://=</ProviderID>
- </XRD>
-</XRDS> \ No newline at end of file
diff --git a/askbot/deps/openid/test/data/test_etxrd/subsegments.xrds b/askbot/deps/openid/test/data/test_etxrd/subsegments.xrds
deleted file mode 100644
index 11d2e912..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/subsegments.xrds
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRDS ref="xri://=nishitani*masaki" xmlns="xri://$xrds">
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*nishitani</Query>
- <Status code="100"/>
- <Expires>2007-12-25T11:33:39.000Z</Expires>
- <ProviderID>xri://=</ProviderID>
- <LocalID priority="10">!E117.EF2F.454B.C707</LocalID>
- <CanonicalID priority="10">=!E117.EF2F.454B.C707</CanonicalID>
- <Service priority="10">
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID>xri://!!1003!103</ProviderID>
- <URI append="none" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- <Service priority="10">
- <Type select="true">xri://$res*auth*($v*2.0)</Type>
- <ProviderID>xri://!!1003!103</ProviderID>
- <MediaType>application/xrds+xml;trust=none</MediaType>
- <URI priority="10">http://resolve.ezibroker.net/resolve/=nishitani/</URI>
- </Service>
- <Service priority="1">
- <Type match="content" select="true">xri://+i-service*(+forwarding)*($v*1.0)</Type>
- <Type match="null" select="false"/>
- <ProviderID>xri://!!1003!103</ProviderID>
- <Path match="content">(+index)</Path>
- <Path match="default"/>
- <URI append="qxri" priority="1">http://linksafe-forward.ezibroker.net/forwarding/</URI>
- </Service>
- </XRD>
- <XRD xmlns="xri://$xrd*($v*2.0)">
- <Query>*masaki</Query>
- <Status code="100">SUCCESS</Status>
- <ProviderID>xri://!!1003</ProviderID>
- <LocalID>!0000.0000.3B9A.CA01</LocalID>
- <CanonicalID>=!E117.EF2F.454B.C707!0000.0000.3B9A.CA01</CanonicalID>
- <Service>
- <Type select="true">http://openid.net/signon/1.0</Type>
- <ProviderID>xri://!!1003!103</ProviderID>
- <URI append="none" priority="1">https://linksafe.ezibroker.net/server/</URI>
- </Service>
- <Service>
- <Type select="true">xri://+i-service*(+contact)*($v*1.0)</Type>
- <Type match="null"/>
- <ProviderID>xri://!!1003!103</ProviderID>
- <Path select="true">(+contact)</Path>
- <Path match="null"/>
- <URI append="authority" priority="1">http://linksafe-contact.ezibroker.net/contact/</URI>
- </Service>
- <Service priority="1">
- <Type match="content" select="true">xri://+i-service*(+forwarding)*($v*1.0)</Type>
- <Type match="null" select="false"/>
- <ProviderID>xri://!!1003!103</ProviderID>
- <Path match="content">(+index)</Path>
- <Path match="default"/>
- <URI append="qxri" priority="1">http://linksafe-forward.ezibroker.net/forwarding/</URI>
- </Service>
- </XRD>
-</XRDS>
diff --git a/askbot/deps/openid/test/data/test_etxrd/valid-populated-xrds.xml b/askbot/deps/openid/test/data/test_etxrd/valid-populated-xrds.xml
deleted file mode 100644
index 60e5ca7b..00000000
--- a/askbot/deps/openid/test/data/test_etxrd/valid-populated-xrds.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS
- xmlns:xrds="xri://$xrds"
- xmlns:openid="http://openid.net/xmlns/1.0"
- xmlns:typekey="http://typekey.com/xmlns/1.0"
- xmlns="xri://$xrd*($v*2.0)">
- <XRD>
-
- <Service priority="0">
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://www.myopenid.com/server</URI>
- <openid:Delegate>http://josh.myopenid.com/</openid:Delegate>
- </Service>
-
- <Service priority="20">
- <Type>http://lid.netmesh.org/sso/2.0b5</Type>
- <Type>http://lid.netmesh.org/2.0b5</Type>
- <URI>http://mylid.net/josh</URI>
- </Service>
-
- <Service priority="10">
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://www.livejournal.com/openid/server.bml</URI>
- <openid:Delegate>http://www.livejournal.com/users/nedthealpaca/</openid:Delegate>
- </Service>
-
- <Service priority="15">
- <Type>http://typekey.com/services/1.0</Type>
- <typekey:MemberName>joshhoyt</typekey:MemberName>
- </Service>
-
- <Service priority="5">
- <Type>http://openid.net/signon/1.0</Type>
- <URI>http://www.schtuff.com/openid</URI>
- <openid:Delegate>http://users.schtuff.com/josh</openid:Delegate>
- </Service>
-
- </XRD>
-</xrds:XRDS>
diff --git a/askbot/deps/openid/test/data/trustroot.txt b/askbot/deps/openid/test/data/trustroot.txt
deleted file mode 100644
index 3d948a4f..00000000
--- a/askbot/deps/openid/test/data/trustroot.txt
+++ /dev/null
@@ -1,150 +0,0 @@
-========================================
-Trust root parsing checking
-========================================
-
-----------------------------------------
-21: Does not parse
-----------------------------------------
-baz.org
-*.foo.com
-http://*.schtuff.*/
-ftp://foo.com
-ftp://*.foo.com
-http://*.foo.com:80:90/
-http:///
-http://
-foo.*.com
-http://foo.*.com
-http://www.*
-http://*foo.com/
-http://foo.com\/
-http://localhost:1900foo/
-http://foo.com/invalid#fragment
-http://Ï€.pi.com/
-http://lambda.com/Λ
-
-
-
-5
-
-----------------------------------------
-15: Insane
-----------------------------------------
-http://*/
-https://*/
-http://*.com
-http://*.com/
-https://*.com/
-http://*.com.au/
-http://*.co.uk/
-http://*.foo.notatld/
-https://*.foo.notatld/
-http://*.museum/
-https://*.museum/
-http://www.schtuffcom/
-http://it/
-http://..it/
-http://.it/
-
-----------------------------------------
-18: Sane
-----------------------------------------
-http://*.schtuff.com./
-http://*.schtuff.com/
-http://*.foo.schtuff.com/
-http://*.schtuff.com
-http://www.schtuff.com/
-http://www.schtuff.com./
-http://www.schutff.com
-http://*.this.that.schtuff.com/
-http://*.foo.com/path
-http://*.foo.com/path?action=foo2
-http://x.foo.com/path?action=foo2
-http://x.foo.com/path?action=%3D
-http://localhost:8081/
-http://localhost:8082/?action=openid
-https://foo.com/
-http://kink.fm/should/be/sane
-http://beta.lingu.no/
-http://goathack.livejournal.org:8020/openid/login.bml
-
-========================================
-return_to matching
-========================================
-
-----------------------------------------
-45: matches
-----------------------------------------
-http://*/ http://cnn.com/
-http://*/ http://livejournal.com/
-http://*/ http://met.museum/
-http://*:8081/ http://met.museum:8081/
-http://localhost:8081/x?action=openid http://localhost:8081/x?action=openid
-http://*.foo.com http://b.foo.com
-http://*.foo.com http://b.foo.com/
-http://*.foo.com/ http://b.foo.com
-http://b.foo.com http://b.foo.com
-http://b.foo.com http://b.foo.com/
-http://b.foo.com/ http://b.foo.com
-http://*.b.foo.com http://b.foo.com
-http://*.b.foo.com http://b.foo.com/
-http://*.b.foo.com/ http://b.foo.com
-http://*.b.foo.com http://x.b.foo.com
-http://*.b.foo.com http://w.x.b.foo.com
-http://*.bar.co.uk http://www.bar.co.uk
-http://*.uoregon.edu http://x.cs.uoregon.edu
-http://x.com/abc http://x.com/abc
-http://127.1/abc http://127.1/abc
-http://10.0.0.1/abc http://10.0.0.1/abc
-http://x.com/abc http://x.com/abc/def
-http://*.x.com http://x.com/gallery
-http://*.x.com http://foo.x.com/gallery
-http://foo.x.com http://foo.x.com/gallery/xxx
-http://*.x.com/gallery http://foo.x.com/gallery
-http://localhost:8082/?action=openid http://localhost:8082/?action=openid
-http://goathack.livejournal.org:8020/ http://goathack.livejournal.org:8020/openid/login.bml
-https://foo.com https://foo.com
-http://Foo.com http://foo.com
-http://foo.com http://Foo.com
-http://foo.com:80/ http://foo.com/
-http://foo.com/?x=y http://foo.com/?x=y&a=b
-http://foo.com/x http://foo.com/x?y
-http://mylid.net/j3h. http://mylid.net/j3h.?x=y
-http://j3h.us http://j3h.us?ride=unicycle
-https://www.filmclans.com:443/mattmartin/FilmClans https://www.filmclans.com/mattmartin/FilmClans/Logon.aspx?nonce=BVjqSOee
-http://foo.com:80 http://foo.com
-http://foo.com http://foo.com:80
-http://foo.com http://foo.com/
-http://foo.com/ http://foo.com
-http://foo.com/ http://foo.com:80
-http://foo.com:80/ http://foo.com:80/stuff
-http://foo.com:80/ http://foo.com/stuff
-http://foo.com/ HTTP://foo.com/
-
-----------------------------------------
-24: does not match
-----------------------------------------
-http://*/ ftp://foo.com/
-http://*/ xxx
-http://*.x.com/abc http://foo.x.com
-http://*.x.com/abc http://*.x.com
-http://*.com/ http://*.com/
-http://x.com/abc http://x.com/
-http://x.com/abc http://x.com/a
-http://x.com/abc http://x.com/ab
-http://x.com/abc http://x.com/abcd
-http://*.cs.uoregon.edu http://x.uoregon.edu
-http://*.foo.com http://bar.com
-http://*.foo.com http://www.bar.com
-http://*.bar.co.uk http://xxx.co.uk
-https://foo.com http://foo.com
-http://foo.com https://foo.com
-http://foo.com:81 http://foo.com:80
-http://*:80 http://foo.com:81
-http://foo.com/?a=b http://foo.com/?x=y
-http://foo.com/?a=b http://foo.com/?x=y&a=b
-http://foo.com/?a=b http://foo.com/
-http://*.oo.com/ http://foo.com/
-http://foo.com/* http://foo.com/anything
-http://foo.com http://foo.com:443
-https://foo.com https://foo.com:80
diff --git a/askbot/deps/openid/test/datadriven.py b/askbot/deps/openid/test/datadriven.py
deleted file mode 100644
index 2dbcfd0d..00000000
--- a/askbot/deps/openid/test/datadriven.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import unittest
-import types
-
-class DataDrivenTestCase(unittest.TestCase):
- cases = []
-
- def generateCases(cls):
- return cls.cases
-
- generateCases = classmethod(generateCases)
-
- def loadTests(cls):
- tests = []
- for case in cls.generateCases():
- if isinstance(case, tuple):
- test = cls(*case)
- elif isinstance(case, dict):
- test = cls(**case)
- else:
- test = cls(case)
- tests.append(test)
- return tests
-
- loadTests = classmethod(loadTests)
-
- def __init__(self, description):
- unittest.TestCase.__init__(self, 'runOneTest')
- self.description = description
-
- def shortDescription(self):
- return '%s for %s' % (self.__class__.__name__, self.description)
-
-def loadTests(module_name):
- loader = unittest.defaultTestLoader
- this_module = __import__(module_name, {}, {}, [None])
-
- tests = []
- for name in dir(this_module):
- obj = getattr(this_module, name)
- if (isinstance(obj, (type, types.ClassType)) and
- issubclass(obj, unittest.TestCase)):
- if hasattr(obj, 'loadTests'):
- tests.extend(obj.loadTests())
- else:
- tests.append(loader.loadTestsFromTestCase(obj))
-
- return unittest.TestSuite(tests)
diff --git a/askbot/deps/openid/test/dh.py b/askbot/deps/openid/test/dh.py
deleted file mode 100644
index c4478d15..00000000
--- a/askbot/deps/openid/test/dh.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import os.path
-from askbot.deps.openid.dh import DiffieHellman, strxor
-
-def test_strxor():
- NUL = '\x00'
-
- cases = [
- (NUL, NUL, NUL),
- ('\x01', NUL, '\x01'),
- ('a', 'a', NUL),
- ('a', NUL, 'a'),
- ('abc', NUL * 3, 'abc'),
- ('x' * 10, NUL * 10, 'x' * 10),
- ('\x01', '\x02', '\x03'),
- ('\xf0', '\x0f', '\xff'),
- ('\xff', '\x0f', '\xf0'),
- ]
-
- for aa, bb, expected in cases:
- actual = strxor(aa, bb)
- assert actual == expected, (aa, bb, expected, actual)
-
- exc_cases = [
- ('', 'a'),
- ('foo', 'ba'),
- (NUL * 3, NUL * 4),
- (''.join(map(chr, xrange(256))),
- ''.join(map(chr, xrange(128)))),
- ]
-
- for aa, bb in exc_cases:
- try:
- unexpected = strxor(aa, bb)
- except ValueError:
- pass
- else:
- assert False, 'Expected ValueError, got %r' % (unexpected,)
-
-def test1():
- dh1 = DiffieHellman.fromDefaults()
- dh2 = DiffieHellman.fromDefaults()
- secret1 = dh1.getSharedSecret(dh2.public)
- secret2 = dh2.getSharedSecret(dh1.public)
- assert secret1 == secret2
- return secret1
-
-def test_exchange():
- s1 = test1()
- s2 = test1()
- assert s1 != s2
-
-def test_public():
- f = file(os.path.join(os.path.dirname(__file__), 'dhpriv'))
- dh = DiffieHellman.fromDefaults()
- try:
- for line in f:
- parts = line.strip().split(' ')
- dh._setPrivate(long(parts[0]))
-
- assert dh.public == long(parts[1])
- finally:
- f.close()
-
-def test():
- test_exchange()
- test_public()
- test_strxor()
-
-if __name__ == '__main__':
- test()
diff --git a/askbot/deps/openid/test/dhpriv b/askbot/deps/openid/test/dhpriv
deleted file mode 100644
index 0fa52314..00000000
--- a/askbot/deps/openid/test/dhpriv
+++ /dev/null
@@ -1,29 +0,0 @@
-130706940119084053627151828062879423433929180135817317038378606310097533503449582079984816816837125851552273641820339909167103200910805078308128174143174269944095368580519322913514764528012639683546377014716235962867583443566164615728897857285824741767070432119909660645255499710701356135207437699643611094585 139808169914464096465921128085565621767096724855516655439365028496569658038844954238931647642811548254956660405394116677296461848124300258439895306367561416289126854788101396379292925819850897858045772500578222021901631436550118958972312221974009238050517034542286574826081826542722270952769078386418682059418
-91966407878983240112417790733941098492087186469785726449910011271065622315680646030230288265496017310433513856308693810812043160919214636748486185212617634222158204354206411031403206076739932806412551605172319515223573351072757800448643935018534945933808900467686115619932664888581913179496050117713298715475 88086484332488517006277516020842172054013692832175783214603951240851750819999098631851571207693874357651112736088114133607400684776234181681933311972926752846692615822043533641407510569745606256772455614745111122033229877596984718963046218854103292937700694160593653595134512369959987897086639788909618660591
-94633950701209990078055218830969910271587805983595045023718108184189787131629772007048606080263109446462048743696369276578815611098215686598630889831104860221067872883514840819381234786050098278403321905311637820524177879167250981289318356078312300538871435101338967079907049912435983871847334104247675360099 136836393035803488129856151345450008294260680733328546556640578838845312279198933806383329293483852515700876505956362639881210101974254765087350842271260064592406308509078284840473735904755203614987286456952991025347168970462354352741159076541157478949094536405618626397435745496863324654768971213730622037771
-24685127248019769965088146297942173464487677364928435784091685260262292485380918213538979925891771204729738138857126454465630594391449913947358655368215901119137728648638547728497517587701248406019427282237279437409508871300675355166059811431191200555457304463617727969228965042729205402243355816702436970430 103488011917988946858248200111251786178288940265978921633592888293430082248387786443813155999158786903216094876295371112716734481877806417714913656921169196196571699893360825510307056269738593971532017994987406325068886420548597161498019372380511676314312298122272401348856314619382867707981701472607230523868
-116791045850880292989786005885944774698035781824784400772676299590038746153860847252706167458966356897309533614849402276819438194497464696186624618374179812548893947178936305721131565012344462048549467883494038577857638815386798694225798517783768606048713198211730870155881426709644960689953998714045816205549 25767875422998856261320430397505398614439586659207416236135894343577952114994718158163212134503751463610021489053571733974769536157057815413209619147486931502025658987681202196476489081257777148377685478756033509708349637895740799542063593586769082830323796978935454479273531157121440998804334199442003857410
-75582226959658406842894734694860761896800153014775231713388264961517169436476322183886891849966756849783437334069692683523296295601533803799559985845105706728538458624387103621364117548643541824878550074680443708148686601108223917493525070861593238005735446708555769966855130921562955491250908613793521520082 51100990616369611694975829054222013346248289055987940844427061856603230021472379888102172458517294080775792439385531234808129302064303666640376750139242970123503857186428797403843206765926798353022284672682073397573130625177187185114726049347844460311761033584101482859992951420083621362870301150543916815123
-22852401165908224137274273646590366934616265607879280260563022941455466297431255072303172649495519837876946233272420969249841381161312477263365567831938496555136366981954001163034914812189448922853839616662859772087929140818377228980710884492996109434435597500854043325062122184466315338260530734979159890875 35017410720028595029711778101507729481023945551700945988329114663345341120595162378885287946069695772429641825579528116641336456773227542256911497084242947904528367986325800537695079726856460817606404224094336361853766354225558025931211551975334149258299477750615397616908655079967952372222383056221992235704
-37364490883518159794654045194678325635036705086417851509136183713863262621334636905291385255662750747808690129471989906644041585863034419130023070856805511017402434123099100618568335168939301014148587149578150068910141065808373976114927339040964292334109797421173369274978107389084873550233108940239410902552 40916262212189137562350357241447034318002130016858244002788189310078477605649010031339865625243230798681216437501833540185827501244378529230150467789369234869122179247196276164931090039290879808162629109742198951942358028123056268054775108592325500609335947248599688175189333996086475013450537086042387719925
-42030470670714872936404499074069849778147578537708230270030877866700844337372497704027708080369726758812896818567830863540507961487472657570488625639077418109017434494794778542739932765561706796300920251933107517954265066804108669800167526425723377411855061131982689717887180411017924173629124764378241885274 124652439272864857598747946875599560379786580730218192165733924418687522301721706620565030507816884907589477351553268146177293719586287258662025940181301472851649975563004543250656807255226609296537922304346339513054316391667044301386950180277940536542183725690479451746977789001659540839582630251935163344393
-33176766914206542084736303652243484580303865879984981189372762326078776390896986743451688462101732968104375838228070296418541745483112261133079756514082093269959937647525005374035326747696591842313517634077723301677759648869372517403529488493581781546743147639937580084065663597330159470577639629864369972900 67485835091897238609131069363014775606263390149204621594445803179810038685760826651889895397414961195533694176706808504447269558421955735607423135937153901140512527504198912146656610630396284977496295289999655140295415981288181545277299615922576281262872097567020980675200178329219970170480653040350512964539
-131497983897702298481056962402569646971797912524360547236788650961059980711719600424210346263081838703940277066368168874781981151411096949736205282734026497995296147418292226818536168555712128736975034272678008697869326747592750850184857659420541708058277866000692785617873742438060271311159568468507825422571 5400380840349873337222394910303409203226429752629134721503171858543984393161548520471799318518954232197106728096866840965784563043721652790856860155702760027304915133166173298206604451826182024471262142046935060360564569939062438160049193241369468208458085699995573492688298015026628427440418009025072261296
-83265103005695640943261961853521077357830295830250157593141844209296716788437615940096402365505416686459260302419338241462783388722843946886845478224048360927114533590583464979009731440049610985062455108831881153988321298531365779084012803908832525921630534096740755274371500276660832724874701671184539131864 141285570207910287798371174771658911045525474449663877845558585668334618068814605961306961485855329182957174312715910923324965889174835444049526313968571611940626279733302104955951067959291852710640374412577070764165811275030632465290729619533330733368808295932659463215921521905553936914975786500018720073003
-68435028583616495789148116911096163791710022987677894923742899873596891423986951658100606742052014161171185231735413902875605720814417622409817842932759492013585936536452615480700628719795872201528559780249210820284350401473564919576289210869896327937002173624497942136329576506818749730506884927872345019446 134655528287263100540003157571441260698452262106680191153945271167894435782028803135774578949200580551016388918860856991026082917835209212892423567114480975540305860034439015788120390011692862968771136814777768281366591257663821495720134621172848947971117885754539770645621669309650476331439675400544167728223
-97765390064836080322590528352647421920257073063706996347334558390461274981996865736612531330863478931481491964338380362350271734683183807511097331539820133036984271653285063355715726806139083282458695728902452215405696318402583540317419929113959816258829534543044153959951908676300847164682178008704099351835 92552521881196975294401505656851872247567784546370503402756239533783651371688190302773864319828182042605239246779598629409815474038541272600580320815319709309111399294952620375093803971373108792300726524826209329889463854451846561437729676142864421966497641824498079067929811613947148353921163336822026640804
-145767094672933012300753301037546647564595762930138884463767054235112032706630891961371504668013023047595721138624016493638510710257541241706724342585654715468628355455898091951826598092812212209834746162089753649871544789379424903025374228231365026585872808685759231756517703720396301355299998059523896918448 116669462839999965355861187716880953863237226719689755457884414384663576662696981997535568446560375442532084973721539944428004043491468494548231348032618218312515409944970197902589794303562379864012797605284844016184274353252071642511293089390472576498394410829972525726474727579603392265177009323768966538608
-34172517877854802711907683049441723730724885305592620486269966708379625109832852005775048584124451699198484092407720344962116726808090368739361658889584507734617844212547181476646725256303630128954338675520938806905779837227983648887192531356390902975904503218654196581612781227843742951241442641220856414232 126013077261793777773236390821108423367648447987653714614732477073177878509574051196587476846560696305938891953527959347566502332765820074506907037627115954790645652211088723122982633069089920979477728376746424256704724173255656757918995039125823421607024407307091796807227896314403153380323770001854211384322
-9979624731056222925878866378063961280844793874828281622845276060532093809300121084179730782833657205171434732875093693074415298975346410131191865198158876447591891117577190438695367929923494177555818480377241891190442070100052523008290671797937772993634966511431668500154258765510857129203107386972819651767 76559085024395996164590986654274454741199399364851956129137304209855150918182685643729981600389513229011956888957763987167398150792454613751473654448162776379362213885827651020309844507723069713820393068520302223477225569348080362344052033711960892643036147232270133731530049660264526964146237693063093765111
-18162696663677410793062235946366423954875282212790518677684260521370996677183041664345920941714064628111537529793170736292618705900247450994864220481135611781148410617609559050220262121494712903009168783279356915189941268264177631458029177102542745167475619936272581126346266816618866806564180995726437177435 63244550218824945129624987597134280916829928261688093445040235408899092619821698537312158783367974202557699994650667088974727356690181336666077506063310290098995215324552449858513870629176838494348632073938023916155113126203791709810160925798130199717340478393420816876665127594623142175853115698049952126277
-4817943161362708117912118300716778687157593557807116683477307391846133734701449509121209661982298574607233039490570567781316652698287671086985501523197566560479906850423709894582834963398034434055472063156147829131181965140631257939036683622084290629927807369457311894970308590034407761706800045378158588657 61612160237840981966750225147965256022861527286827877531373888434780789812764688703260066154973576040405676432586962624922734102370509771313805122788566405984830112657060375568510809122230960988304085950306616401218206390412815884549481965750553137717475620505076144744211331973240555181377832337912951699135
-36363324947629373144612372870171042343590861026293829791335153646774927623889458346817049419803031378037141773848560341251355283891019532059644644509836766167835557471311319194033709837770615526356168418160386395260066262292757953919140150454538786106958252854181965875293629955562111756775391296856504912587 86831561031659073326747216166881733513938228972332631084118628692228329095617884068498116676787029033973607066377816508795286358748076949738854520048303930186595481606562375516134920902325649683618195251332651685732712539073110524182134321873838204219194459231650917098791250048469346563303077080880339797744
-26406869969418301728540993821409753036653370247174689204659006239823766914991146853283367848649039747728229875444327879875275718711878211919734397349994000106499628652960403076186651083084423734034070082770589453774926850920776427074440483233447839259180467805375782600203654373428926653730090468535611335253 100139935381469543084506312717977196291289016554846164338908226931204624582010530255955411615528804421371905642197394534614355186795223905217732992497673429554618838376065777445760355552020655667172127543653684405493978325270279321013143828897100500212200358450649158287605846102419527584313353072518101626851
-92613116984760565837109105383781193800503303131143575169488835702472221039082994091847595094556327985517286288659598094631489552181233202387028607421487026032402972597880028640156629614572656967808446397456622178472130864873587747608262139844319805074476178618930354824943672367046477408898479503054125369731 30023391082615178562263328892343821010986429338255434046051061316154579824472412477397496718186615690433045030046315908170615910505869972621853946234911296439134838951047107272129711854649412919542407760508235711897489847951451200722151978578883748353566191421685659370090024401368356823252748749449302536931
-31485815361342085113278193504381994806529237123359718043079410511224607873725611862217941085749929342777366642477711445011074784469367917758629403998067347054115844421430072631339788256386509261291675080191633908849638316409182455648806133048549359800886124554879661473112614246869101243501787363247762961784 114503770698890543429251666713050844656853278831559195214556474458830029271801818536133531843456707474500106283648085144619097572354066554819887152106174400667929098257361286338795493838820850475790977445807435511982704395422526800272723708548541616513134676140304653112325071112865020365664833601046215694089
-76882090884790547431641385530818076533805072109483843307806375918023300052767710853172670987385376253156912268523505310624133905633437815297307463917718596711590885553760690350221265675690787249135345226947453988081566088302642706234126002514517416493192624887800567412565527886687096028028124049522890448168 15056463217273240496622619354104573042767532856243223052125822509781815362480522535564283485059790932505429110157271454207173426525345813426696743168079246510944969446574354255284952839036431873039487144279164893710061580467579842173706653409487110282515691099753380094215805485573768509475850463001549608836
-52345178981230648108672997265819959243255047568833938156267924185186047373470984278294897653277996726416846430969793375429223610099546622112048283560483136389901514170116723365811871938630317974150540909650396429631704968748113009366339718498979597226137532343384889080245796447593572468846438769413505393967 32148494517199936472358017244372701214529606506776255341152991328091526865643069587953759877295255050519124541457805199596762210567333445908166076384465183589342153762720515477404466193879418014196727238972417616122646440870364200208488239778452378059236162633837824948613596114768455832408342040970780086
-41095268619128788015767564971105114602454449306041732792746397800275041704886345704294273937217484580365505320134717320083763349380629342859670693445658118959823430378844830923452105707338162448974869312012791385772125813291388247857971218575518319578818336960572244046567099555399203328678654466958536663208 92166550199033418923713824997841892577149715275633481076285269142670107687867024550593869464613175882141630640739938334001211714884975032600306279287443909448541179109981755796752132502127330056736913454039526413284519137059580845856736918773597087836203497066909257930043736166431682872083389105176299181629
-40049143661018504441607875135884755310012910557581028447435354354754245291878800571089144452035026644953322330676651798951447670184106450649737772686119714700743396359069052813433030118630105307022867200053964644574786137276428546712005171080129190959914708907200288299169344380390093918556722227705114244981 108159089972386282154772900619022507336076619354549601813179459338897131937353741544606392560724999980281424266891537298473163753022749859939445293926707568015958367188089915420630082556748668489756475027008449860889202622698060097015044886961901650857610841562477736791450080980702347705778074391774667412741
-69905259478181995876884927656894491893594530150260951315109404530530357998889589977208787140430938039028941393673520799460431992051993157468616168400324834880926190141581037597526917869362292931957289043707855837933490285814769110495657056206391880865972389421774822461752702336812585852278453803972600333734 71821415380277072313878763768684432371552628204186742842154591000123020597011744840460964835414360968627162765288463383113375595799297552681618876474019263288277398833725479226930770694271622605114061622753165584075733358178384410640349907375170170910499615355511313349300918885560131539570707695789106185664
-26945345439378873515011714350080059082081595419023056538696949766471272811362104837806324694947413603019863785876836706911406330379274553386254346050697348395574746891556054334903838949157798006141473389066020212044825140294048709654273698482867946522782450500680195477050110145664069582549935651920545151500 80313315938584480048642653013876614091607852535582224914294013785054094052454758327935781971746329853786568549510067442145637007308960551652864942042189241081946607011847245280773379099020221884296226818685556430275385068764313042226925852500883894269809033380734632866477789520106865758504064806906234130588
diff --git a/askbot/deps/openid/test/discoverdata.py b/askbot/deps/openid/test/discoverdata.py
deleted file mode 100644
index f618290f..00000000
--- a/askbot/deps/openid/test/discoverdata.py
+++ /dev/null
@@ -1,125 +0,0 @@
-"""Module to make discovery data test cases available"""
-import urlparse
-import os.path
-
-from askbot.deps.openid.yadis.discover import DiscoveryResult, DiscoveryFailure
-from askbot.deps.openid.yadis.constants import YADIS_HEADER_NAME
-
-tests_dir = os.path.dirname(__file__)
-data_path = os.path.join(tests_dir, 'data')
-
-testlist = [
-# success, input_name, id_name, result_name
- (True, "equiv", "equiv", "xrds"),
- (True, "header", "header", "xrds"),
- (True, "lowercase_header", "lowercase_header", "xrds"),
- (True, "xrds", "xrds", "xrds"),
- (True, "xrds_ctparam", "xrds_ctparam", "xrds_ctparam"),
- (True, "xrds_ctcase", "xrds_ctcase", "xrds_ctcase"),
- (False, "xrds_html", "xrds_html", "xrds_html"),
- (True, "redir_equiv", "equiv", "xrds"),
- (True, "redir_header", "header", "xrds"),
- (True, "redir_xrds", "xrds", "xrds"),
- (False, "redir_xrds_html", "xrds_html", "xrds_html"),
- (True, "redir_redir_equiv", "equiv", "xrds"),
- (False, "404_server_response", None, None),
- (False, "404_with_header", None, None),
- (False, "404_with_meta", None, None),
- (False, "201_server_response", None, None),
- (False, "500_server_response", None, None),
- ]
-
-def getDataName(*components):
- sanitized = []
- for part in components:
- if part in ['.', '..']:
- raise ValueError
- elif part:
- sanitized.append(part)
-
- if not sanitized:
- raise ValueError
-
- return os.path.join(data_path, *sanitized)
-
-def getExampleXRDS():
- filename = getDataName('example-xrds.xml')
- return file(filename).read()
-
-example_xrds = getExampleXRDS()
-default_test_file = getDataName('test1-discover.txt')
-
-discover_tests = {}
-
-def readTests(filename):
- data = file(filename).read()
- tests = {}
- for case in data.split('\f\n'):
- (name, content) = case.split('\n', 1)
- tests[name] = content
- return tests
-
-def getData(filename, name):
- global discover_tests
- try:
- file_tests = discover_tests[filename]
- except KeyError:
- file_tests = discover_tests[filename] = readTests(filename)
- return file_tests[name]
-
-def fillTemplate(test_name, template, base_url, example_xrds):
- mapping = [
- ('URL_BASE/', base_url),
- ('<XRDS Content>', example_xrds),
- ('YADIS_HEADER', YADIS_HEADER_NAME),
- ('NAME', test_name),
- ]
-
- for k, v in mapping:
- template = template.replace(k, v)
-
- return template
-
-def generateSample(test_name, base_url,
- example_xrds=example_xrds,
- filename=default_test_file):
- try:
- template = getData(filename, test_name)
- except IOError, why:
- import errno
- if why[0] == errno.ENOENT:
- raise KeyError(filename)
- else:
- raise
-
- return fillTemplate(test_name, template, base_url, example_xrds)
-
-def generateResult(base_url, input_name, id_name, result_name, success):
- input_url = urlparse.urljoin(base_url, input_name)
-
- # If the name is None then we expect the protocol to fail, which
- # we represent by None
- if id_name is None:
- assert result_name is None
- return input_url, DiscoveryFailure
-
- result = generateSample(result_name, base_url)
- headers, content = result.split('\n\n', 1)
- header_lines = headers.split('\n')
- for header_line in header_lines:
- if header_line.startswith('Content-Type:'):
- _, ctype = header_line.split(':', 1)
- ctype = ctype.strip()
- break
- else:
- ctype = None
-
- id_url = urlparse.urljoin(base_url, id_name)
-
- result = DiscoveryResult(input_url)
- result.normalized_uri = id_url
- if success:
- result.xrds_uri = urlparse.urljoin(base_url, result_name)
- result.content_type = ctype
- result.response_text = content
- return input_url, result
diff --git a/askbot/deps/openid/test/kvform.py b/askbot/deps/openid/test/kvform.py
deleted file mode 100644
index e63d4178..00000000
--- a/askbot/deps/openid/test/kvform.py
+++ /dev/null
@@ -1,174 +0,0 @@
-from askbot.deps.openid import kvform
-from askbot.deps.openid import oidutil
-import unittest
-
-class KVBaseTest(unittest.TestCase):
- def shortDescription(self):
- return '%s test for %r' % (self.__class__.__name__, self.kvform)
-
- def log(self, message, unused_priority=None):
- self.warnings.append(message)
-
- def checkWarnings(self, num_warnings):
- self.failUnlessEqual(num_warnings, len(self.warnings), repr(self.warnings))
-
- def setUp(self):
- self.warnings = []
- self.old_log = oidutil.log
- self.log_func = oidutil.log = self.log
- self.failUnless(self.log_func is oidutil.log,
- (oidutil.log, self.log_func))
-
- def tearDown(self):
- oidutil.log = self.old_log
-
-class KVDictTest(KVBaseTest):
- def __init__(self, kv, dct, warnings):
- unittest.TestCase.__init__(self)
- self.kvform = kv
- self.dict = dct
- self.expected_warnings = warnings
-
- def runTest(self):
- # Convert KVForm to dict
- d = kvform.kvToDict(self.kvform)
-
- # make sure it parses to expected dict
- self.failUnlessEqual(self.dict, d)
-
- # Check to make sure we got the expected number of warnings
- self.checkWarnings(self.expected_warnings)
-
- # Convert back to KVForm and round-trip back to dict to make
- # sure that *** dict -> kv -> dict is identity. ***
- kv = kvform.dictToKV(d)
- d2 = kvform.kvToDict(kv)
- self.failUnlessEqual(d, d2)
-
-class KVSeqTest(KVBaseTest):
- def __init__(self, seq, kv, expected_warnings):
- unittest.TestCase.__init__(self)
- self.kvform = kv
- self.seq = seq
- self.expected_warnings = expected_warnings
-
- def cleanSeq(self, seq):
- """Create a new sequence by stripping whitespace from start
- and end of each value of each pair"""
- clean = []
- for k, v in self.seq:
- if type(k) is str:
- k = k.decode('utf8')
- if type(v) is str:
- v = v.decode('utf8')
- clean.append((k.strip(), v.strip()))
- return clean
-
- def runTest(self):
- # seq serializes to expected kvform
- actual = kvform.seqToKV(self.seq)
- self.failUnlessEqual(self.kvform, actual)
- self.failUnless(type(actual) is str)
-
- # Parse back to sequence. Expected to be unchanged, except
- # stripping whitespace from start and end of values
- # (i. e. ordering, case, and internal whitespace is preserved)
- seq = kvform.kvToSeq(actual)
- clean_seq = self.cleanSeq(seq)
-
- self.failUnlessEqual(seq, clean_seq)
- self.checkWarnings(self.expected_warnings)
-
-kvdict_cases = [
- # (kvform, parsed dictionary, expected warnings)
- ('', {}, 0),
- ('college:harvey mudd\n', {'college':'harvey mudd'}, 0),
- ('city:claremont\nstate:CA\n',
- {'city':'claremont', 'state':'CA'}, 0),
- ('is_valid:true\ninvalidate_handle:{HMAC-SHA1:2398410938412093}\n',
- {'is_valid':'true',
- 'invalidate_handle':'{HMAC-SHA1:2398410938412093}'}, 0),
-
- # Warnings from lines with no colon:
- ('x\n', {}, 1),
- ('x\nx\n', {}, 2),
- ('East is least\n', {}, 1),
-
- # But not from blank lines (because LJ generates them)
- ('x\n\n', {}, 1),
-
- # Warning from empty key
- (':\n', {'':''}, 1),
- (':missing key\n', {'':'missing key'}, 1),
-
- # Warnings from leading or trailing whitespace in key or value
- (' street:foothill blvd\n', {'street':'foothill blvd'}, 1),
- ('major: computer science\n', {'major':'computer science'}, 1),
- (' dorm : east \n', {'dorm':'east'}, 2),
-
- # Warnings from missing trailing newline
- ('e^(i*pi)+1:0', {'e^(i*pi)+1':'0'}, 1),
- ('east:west\nnorth:south', {'east':'west', 'north':'south'}, 1),
- ]
-
-kvseq_cases = [
- ([], '', 0),
-
- # Make sure that we handle non-ascii characters (also wider than 8 bits)
- ([(u'\u03bbx', u'x')], '\xce\xbbx:x\n', 0),
-
- # If it's a UTF-8 str, make sure that it's equivalent to the same
- # string, decoded.
- ([('\xce\xbbx', 'x')], '\xce\xbbx:x\n', 0),
-
- ([('openid', 'useful'), ('a', 'b')], 'openid:useful\na:b\n', 0),
-
- # Warnings about leading whitespace
- ([(' openid', 'useful'), ('a', 'b')], ' openid:useful\na:b\n', 2),
-
- # Warnings about leading and trailing whitespace
- ([(' openid ', ' useful '),
- (' a ', ' b ')], ' openid : useful \n a : b \n', 8),
-
- # warnings about leading and trailing whitespace, but not about
- # internal whitespace.
- ([(' open id ', ' use ful '),
- (' a ', ' b ')], ' open id : use ful \n a : b \n', 8),
-
- ([(u'foo', 'bar')], 'foo:bar\n', 0),
- ]
-
-kvexc_cases = [
- [('openid', 'use\nful')],
- [('open\nid', 'useful')],
- [('open\nid', 'use\nful')],
- [('open:id', 'useful')],
- [('foo', 'bar'), ('ba\n d', 'seed')],
- [('foo', 'bar'), ('bad:', 'seed')],
- ]
-
-class KVExcTest(unittest.TestCase):
- def __init__(self, seq):
- unittest.TestCase.__init__(self)
- self.seq = seq
-
- def shortDescription(self):
- return 'KVExcTest for %r' % (self.seq,)
-
- def runTest(self):
- self.failUnlessRaises(ValueError, kvform.seqToKV, self.seq)
-
-class GeneralTest(KVBaseTest):
- kvform = '<None>'
-
- def test_convert(self):
- result = kvform.seqToKV([(1,1)])
- self.failUnlessEqual(result, '1:1\n')
- self.checkWarnings(2)
-
-def pyUnitTests():
- tests = [KVDictTest(*case) for case in kvdict_cases]
- tests.extend([KVSeqTest(*case) for case in kvseq_cases])
- tests.extend([KVExcTest(case) for case in kvexc_cases])
- tests.append(unittest.defaultTestLoader.loadTestsFromTestCase(GeneralTest))
- return unittest.TestSuite(tests)
diff --git a/askbot/deps/openid/test/linkparse.py b/askbot/deps/openid/test/linkparse.py
deleted file mode 100644
index 28cab023..00000000
--- a/askbot/deps/openid/test/linkparse.py
+++ /dev/null
@@ -1,109 +0,0 @@
-from askbot.deps.openid.consumer.html_parse import parseLinkAttrs
-import os.path
-import codecs
-import unittest
-
-def parseLink(line):
- parts = line.split()
- optional = parts[0] == 'Link*:'
- assert optional or parts[0] == 'Link:'
-
- attrs = {}
- for attr in parts[1:]:
- k, v = attr.split('=', 1)
- if k[-1] == '*':
- attr_optional = 1
- k = k[:-1]
- else:
- attr_optional = 0
-
- attrs[k] = (attr_optional, v)
-
- return (optional, attrs)
-
-def parseCase(s):
- header, markup = s.split('\n\n', 1)
- lines = header.split('\n')
- name = lines.pop(0)
- assert name.startswith('Name: ')
- desc = name[6:]
- return desc, markup, map(parseLink, lines)
-
-def parseTests(s):
- tests = []
-
- cases = s.split('\n\n\n')
- header = cases.pop(0)
- tests_line, _ = header.split('\n', 1)
- k, v = tests_line.split(': ')
- assert k == 'Num Tests'
- num_tests = int(v)
-
- for case in cases[:-1]:
- desc, markup, links = parseCase(case)
- tests.append((desc, markup, links, case))
-
- return num_tests, tests
-
-class _LinkTest(unittest.TestCase):
- def __init__(self, desc, case, expected, raw):
- unittest.TestCase.__init__(self)
- self.desc = desc
- self.case = case
- self.expected = expected
- self.raw = raw
-
- def shortDescription(self):
- return self.desc
-
- def runTest(self):
- actual = parseLinkAttrs(self.case)
- i = 0
- for optional, exp_link in self.expected:
- if optional:
- if i >= len(actual):
- continue
-
- act_link = actual[i]
- for k, (o, v) in exp_link.items():
- if o:
- act_v = act_link.get(k)
- if act_v is None:
- continue
- else:
- act_v = act_link[k]
-
- if optional and v != act_v:
- break
-
- self.assertEqual(v, act_v)
- else:
- i += 1
-
- assert i == len(actual)
-
-def pyUnitTests():
- here = os.path.dirname(os.path.abspath(__file__))
- test_data_file_name = os.path.join(here, 'linkparse.txt')
- test_data_file = codecs.open(test_data_file_name, 'r', 'utf-8')
- test_data = test_data_file.read()
- test_data_file.close()
-
- num_tests, test_cases = parseTests(test_data)
-
- tests = [_LinkTest(*case) for case in test_cases]
-
- def test_parseSucceeded():
- assert len(test_cases) == num_tests, (len(test_cases), num_tests)
-
- check_desc = 'Check that we parsed the correct number of test cases'
- check = unittest.FunctionTestCase(
- test_parseSucceeded, description=check_desc)
- tests.insert(0, check)
-
- return unittest.TestSuite(tests)
-
-if __name__ == '__main__':
- suite = pyUnitTests()
- runner = unittest.TextTestRunner()
- runner.run(suite)
diff --git a/askbot/deps/openid/test/linkparse.txt b/askbot/deps/openid/test/linkparse.txt
deleted file mode 100644
index 74c63ca7..00000000
--- a/askbot/deps/openid/test/linkparse.txt
+++ /dev/null
@@ -1,584 +0,0 @@
-Num Tests: 72
-
-OpenID link parsing test cases
-Copyright (C) 2005-2008, JanRain, Inc.
-See COPYING for license information.
-
-File format
------------
-
-All text before the first triple-newline (this chunk) should be ignored.
-
-This file may be interpreted as Latin-1 or UTF-8.
-
-Test cases separated by three line separators (`\n\n\n'). The test
-cases consist of a headers section followed by a data block. These are
-separated by a double newline. The headers consist of the header name,
-followed by a colon, a space, the value, and a newline. There must be
-one, and only one, `Name' header for a test case. There may be zero or
-more link headers. The `Link' header consists of whitespace-separated
-attribute pairs. A link header with an empty string as a value
-indicates an empty but present link tag. The attribute pairs are `='
-separated and not quoted.
-
-Optional Links and attributes have a trailing `*'. A compilant
-implementation may produce this as output or may not. A compliant
-implementation will not produce any output that is absent from this
-file.
-
-
-Name: No link tag at all
-
-<html>
-<head>
-</head>
-</html>
-
-
-Name: Link element first
-
-<link>
-
-
-Name: Link inside HTML, not head
-
-<html>
-<link>
-
-
-Name: Link inside head, not html
-
-<head>
-<link>
-
-
-Name: Link inside html, after head
-
-<html>
-<head>
-</head>
-<link>
-
-
-Name: Link inside html, before head
-
-<html>
-<link>
-<head>
-
-
-Name: Link before html and head
-
-<link>
-<html>
-<head>
-
-
-Name: Link after html document with head
-
-<html>
-<head>
-</head>
-</html>
-<link>
-
-
-Name: Link inside html inside head, inside another html
-
-<html>
-<head>
-<html>
-<link>
-
-
-Name: Link inside html inside head
-
-<head>
-<html>
-<link>
-
-
-Name: link inside body inside head inside html
-
-<html>
-<head>
-<body>
-<link>
-
-
-Name: Link inside head inside head inside html
-
-<html>
-<head>
-<head>
-<link>
-
-
-Name: Link inside script inside head inside html
-
-<html>
-<head>
-<script>
-<link>
-</script>
-
-
-Name: Link inside comment inside head inside html
-
-<html>
-<head/>
-<link>
-
-
-Name: Link inside of head after short head
-
-<html>
-<head/>
-<head>
-<link>
-
-
-Name: Plain vanilla
-Link:
-
-<html>
-<head>
-<link>
-
-
-Name: Ignore tags in the <script:... > namespace
-Link*:
-
-<html>
-<head>
-<script:paddypan>
-<link>
-</script:paddypan>
-
-
-Name: Short link tag
-Link:
-
-<html>
-<head>
-<link/>
-
-
-Name: Spaces in the HTML tag
-Link:
-
-<html >
-<head>
-<link>
-
-
-Name: Spaces in the head tag
-Link:
-
-<html>
-<head >
-<link>
-
-
-Name: Spaces in the link tag
-Link:
-
-<html>
-<head>
-<link >
-
-
-Name: No whitespace
-Link:
-
-<html><head><link>
-
-
-Name: Closed head tag
-Link:
-
-<html>
-<head>
-<link>
-</head>
-
-
-Name: One good, one bad (after close head)
-Link:
-
-<html>
-<head>
-<link>
-</head>
-<link>
-
-
-Name: One good, one bad (after open body)
-Link:
-
-<html>
-<head>
-<link>
-<body>
-<link>
-
-
-Name: ill formed (missing close head)
-Link:
-
-<html>
-<head>
-<link>
-</html>
-
-
-Name: Ill formed (no close head, link after </html>)
-Link:
-
-<html>
-<head>
-<link>
-</html>
-<link>
-
-
-Name: Ignore random tags inside of html
-Link:
-
-<html>
-<delicata>
-<head>
-<title>
-<link>
-
-
-Name: case-folding
-Link*:
-
-<HtMl>
-<hEaD>
-<LiNk>
-
-
-Name: unexpected tags
-Link:
-
-<butternut>
-<html>
-<summer>
-<head>
-<turban>
-<link>
-
-
-Name: un-closed script tags
-Link*:
-
-<html>
-<head>
-<script>
-<link>
-
-
-Name: un-closed script tags (no whitespace)
-Link*:
-
-<html><head><script><link>
-
-
-Name: un-closed comment
-Link*:
-
-<html>
-<head>
-<!--
-<link>
-
-
-Name: un-closed CDATA
-Link*:
-
-<html>
-<head>
-<![CDATA[
-<link>
-
-
-Name: cdata-like
-Link*:
-
-<html>
-<head>
-<![ACORN[
-<link>
-]]>
-
-
-Name: comment close only
-Link:
-
-<html>
-<head>
-<link>
--->
-
-
-Name: Vanilla, two links
-Link:
-Link:
-
-<html>
-<head>
-<link>
-<link>
-
-
-Name: extra tag, two links
-Link:
-Link:
-
-<html>
-<gold nugget>
-<head>
-<link>
-<link>
-
-
-Name: case-fold, body ends, two links
-Link:
-Link*:
-
-<html>
-<head>
-<link>
-<LiNk>
-<body>
-<link>
-
-
-Name: simple, non-quoted rel
-Link: rel=openid.server
-
-<html><head><link rel=openid.server>
-
-
-Name: short tag has rel
-Link: rel=openid.server
-
-<html><head><link rel=openid.server/>
-
-
-Name: short tag w/space has rel
-Link: rel=openid.server
-
-<html><head><link rel=openid.server />
-
-
-Name: extra non-attribute, has rel
-Link: rel=openid.server
-
-<html><head><link hubbard rel=openid.server>
-
-
-Name: non-attr, has rel, short
-Link: rel=openid.server
-
-<html><head><link hubbard rel=openid.server/>
-
-
-Name: non-attr, has rel, short, space
-Link: rel=openid.server
-
-<html><head><link hubbard rel=openid.server />
-
-
-Name: misplaced slash has rel
-Link: rel=openid.server
-
-<html><head><link / rel=openid.server>
-
-
-Name: quoted rel
-Link: rel=openid.server
-
-<html><head><link rel="openid.server">
-
-
-Name: single-quoted rel
-Link: rel=openid.server
-
-<html><head><link rel='openid.server'>
-
-
-Name: two links w/ rel
-Link: x=y
-Link: a=b
-
-<html><head><link x=y><link a=b>
-
-
-Name: non-entity
-Link: x=&y
-
-<html><head><link x=&y>
-
-
-Name: quoted non-entity
-Link: x=&y
-
-<html><head><link x="&y">
-
-
-Name: quoted entity
-Link: x=&
-
-<html><head><link x="&amp;">
-
-
-Name: entity not processed
-Link: x=&#26;
-
-<html><head><link x="&#26;">
-
-
-Name: &lt;
-Link: x=<
-
-<html><head><link x="&lt;">
-
-
-Name: &gt;
-Link: x=>
-
-<html><head><link x="&gt;">
-
-
-Name: &quot;
-Link: x="
-
-<html><head><link x="&quot;">
-
-
-Name: &amp;&quot;
-Link: x=&"
-
-<html><head><link x="&amp;&quot;">
-
-
-Name: mixed entity and non-entity
-Link: x=&"&hellip;>
-
-<html><head><link x="&amp;&quot;&hellip;&gt;">
-
-
-Name: mixed entity and non-entity (w/normal chars)
-Link: x=x&"&hellip;>x
-
-<html><head><link x="x&amp;&quot;&hellip;&gt;x">
-
-
-Name: broken tags
-Link*: x=y
-
-<html><head><link x=y<>
-
-
-Name: missing close pointy
-Link*: x=y
-Link: z=y
-
-<html><head><link x=y<link z=y />
-
-
-Name: missing attribute value
-Link: x=y y*=
-Link: x=y
-
-<html><head><link x=y y=><link x=y />
-
-
-Name: Missing close pointy (no following)
-Link*: x=y
-
-<html><head><link x=y
-
-
-Name: Should be quoted
-Link*: x=<
-
-<html><head><link x="<">
-
-
-Name: Should be quoted (2)
-Link*: x=>
-
-<html><head><link x=">">
-
-
-Name: Repeated attribute
-Link: x=y
-
-<html><head><link x=z x=y>
-
-
-Name: Repeated attribute (2)
-Link: x=y
-
-<html><head><link x=y x=y>
-
-
-Name: Two attributes
-Link: x=y y=z
-
-<html><head><link x=y y=z>
-
-
-Name: Well-formed link rel="openid.server"
-Link: rel=openid.server href=http://www.myopenid.com/server
-
-<html>
- <head>
- <link rel="openid.server"
- href="http://www.myopenid.com/server" />
- </head>
-</html>
-
-
-Name: Well-formed link rel="openid.server" and "openid.delegate"
-Link: rel=openid.server href=http://www.myopenid.com/server
-Link: rel=openid.delegate href=http://example.myopenid.com/
-
-<html><head><link rel="openid.server"
- href="http://www.myopenid.com/server" />
- <link rel="openid.delegate" href="http://example.myopenid.com/" />
-</head></html>
-
-
-Name: from brian's livejournal page
-Link: rel=stylesheet href=http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711 type=text/css
-Link: rel=openid.server href=http://www.livejournal.com/openid/server.bml
-
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <link rel="stylesheet"
- href="http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711"
- type="text/css" />
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta name="foaf:maker"
- content="foaf:mbox_sha1sum '12f8abdacb5b1a806711e23249da592c0d316260'" />
- <meta name="robots" content="noindex, nofollow, noarchive" />
- <meta name="googlebot" content="nosnippet" />
- <link rel="openid.server"
- href="http://www.livejournal.com/openid/server.bml" />
- <title>Brian</title>
- </head>
-
-
-Name: non-ascii (Latin-1 or UTF8)
-Link: x=®
-
-<html><head><link x="®">
-
-
diff --git a/askbot/deps/openid/test/n2b64 b/askbot/deps/openid/test/n2b64
deleted file mode 100644
index b12a2460..00000000
--- a/askbot/deps/openid/test/n2b64
+++ /dev/null
@@ -1,650 +0,0 @@
-AA== 0
-AQ== 1
-Ag== 2
-Aw== 3
-BA== 4
-BQ== 5
-Bg== 6
-Bw== 7
-CA== 8
-CQ== 9
-Cg== 10
-Cw== 11
-DA== 12
-DQ== 13
-Dg== 14
-Dw== 15
-EA== 16
-EQ== 17
-Eg== 18
-Ew== 19
-FA== 20
-FQ== 21
-Fg== 22
-Fw== 23
-GA== 24
-GQ== 25
-Gg== 26
-Gw== 27
-HA== 28
-HQ== 29
-Hg== 30
-Hw== 31
-IA== 32
-IQ== 33
-Ig== 34
-Iw== 35
-JA== 36
-JQ== 37
-Jg== 38
-Jw== 39
-KA== 40
-KQ== 41
-Kg== 42
-Kw== 43
-LA== 44
-LQ== 45
-Lg== 46
-Lw== 47
-MA== 48
-MQ== 49
-Mg== 50
-Mw== 51
-NA== 52
-NQ== 53
-Ng== 54
-Nw== 55
-OA== 56
-OQ== 57
-Og== 58
-Ow== 59
-PA== 60
-PQ== 61
-Pg== 62
-Pw== 63
-QA== 64
-QQ== 65
-Qg== 66
-Qw== 67
-RA== 68
-RQ== 69
-Rg== 70
-Rw== 71
-SA== 72
-SQ== 73
-Sg== 74
-Sw== 75
-TA== 76
-TQ== 77
-Tg== 78
-Tw== 79
-UA== 80
-UQ== 81
-Ug== 82
-Uw== 83
-VA== 84
-VQ== 85
-Vg== 86
-Vw== 87
-WA== 88
-WQ== 89
-Wg== 90
-Ww== 91
-XA== 92
-XQ== 93
-Xg== 94
-Xw== 95
-YA== 96
-YQ== 97
-Yg== 98
-Yw== 99
-ZA== 100
-ZQ== 101
-Zg== 102
-Zw== 103
-aA== 104
-aQ== 105
-ag== 106
-aw== 107
-bA== 108
-bQ== 109
-bg== 110
-bw== 111
-cA== 112
-cQ== 113
-cg== 114
-cw== 115
-dA== 116
-dQ== 117
-dg== 118
-dw== 119
-eA== 120
-eQ== 121
-eg== 122
-ew== 123
-fA== 124
-fQ== 125
-fg== 126
-fw== 127
-AIA= 128
-AIE= 129
-AII= 130
-AIM= 131
-AIQ= 132
-AIU= 133
-AIY= 134
-AIc= 135
-AIg= 136
-AIk= 137
-AIo= 138
-AIs= 139
-AIw= 140
-AI0= 141
-AI4= 142
-AI8= 143
-AJA= 144
-AJE= 145
-AJI= 146
-AJM= 147
-AJQ= 148
-AJU= 149
-AJY= 150
-AJc= 151
-AJg= 152
-AJk= 153
-AJo= 154
-AJs= 155
-AJw= 156
-AJ0= 157
-AJ4= 158
-AJ8= 159
-AKA= 160
-AKE= 161
-AKI= 162
-AKM= 163
-AKQ= 164
-AKU= 165
-AKY= 166
-AKc= 167
-AKg= 168
-AKk= 169
-AKo= 170
-AKs= 171
-AKw= 172
-AK0= 173
-AK4= 174
-AK8= 175
-ALA= 176
-ALE= 177
-ALI= 178
-ALM= 179
-ALQ= 180
-ALU= 181
-ALY= 182
-ALc= 183
-ALg= 184
-ALk= 185
-ALo= 186
-ALs= 187
-ALw= 188
-AL0= 189
-AL4= 190
-AL8= 191
-AMA= 192
-AME= 193
-AMI= 194
-AMM= 195
-AMQ= 196
-AMU= 197
-AMY= 198
-AMc= 199
-AMg= 200
-AMk= 201
-AMo= 202
-AMs= 203
-AMw= 204
-AM0= 205
-AM4= 206
-AM8= 207
-ANA= 208
-ANE= 209
-ANI= 210
-ANM= 211
-ANQ= 212
-ANU= 213
-ANY= 214
-ANc= 215
-ANg= 216
-ANk= 217
-ANo= 218
-ANs= 219
-ANw= 220
-AN0= 221
-AN4= 222
-AN8= 223
-AOA= 224
-AOE= 225
-AOI= 226
-AOM= 227
-AOQ= 228
-AOU= 229
-AOY= 230
-AOc= 231
-AOg= 232
-AOk= 233
-AOo= 234
-AOs= 235
-AOw= 236
-AO0= 237
-AO4= 238
-AO8= 239
-APA= 240
-APE= 241
-API= 242
-APM= 243
-APQ= 244
-APU= 245
-APY= 246
-APc= 247
-APg= 248
-APk= 249
-APo= 250
-APs= 251
-APw= 252
-AP0= 253
-AP4= 254
-AP8= 255
-AQA= 256
-AQE= 257
-AQI= 258
-AQM= 259
-AQQ= 260
-AQU= 261
-AQY= 262
-AQc= 263
-AQg= 264
-AQk= 265
-AQo= 266
-AQs= 267
-AQw= 268
-AQ0= 269
-AQ4= 270
-AQ8= 271
-ARA= 272
-ARE= 273
-ARI= 274
-ARM= 275
-ARQ= 276
-ARU= 277
-ARY= 278
-ARc= 279
-ARg= 280
-ARk= 281
-ARo= 282
-ARs= 283
-ARw= 284
-AR0= 285
-AR4= 286
-AR8= 287
-ASA= 288
-ASE= 289
-ASI= 290
-ASM= 291
-ASQ= 292
-ASU= 293
-ASY= 294
-ASc= 295
-ASg= 296
-ASk= 297
-ASo= 298
-ASs= 299
-ASw= 300
-AS0= 301
-AS4= 302
-AS8= 303
-ATA= 304
-ATE= 305
-ATI= 306
-ATM= 307
-ATQ= 308
-ATU= 309
-ATY= 310
-ATc= 311
-ATg= 312
-ATk= 313
-ATo= 314
-ATs= 315
-ATw= 316
-AT0= 317
-AT4= 318
-AT8= 319
-AUA= 320
-AUE= 321
-AUI= 322
-AUM= 323
-AUQ= 324
-AUU= 325
-AUY= 326
-AUc= 327
-AUg= 328
-AUk= 329
-AUo= 330
-AUs= 331
-AUw= 332
-AU0= 333
-AU4= 334
-AU8= 335
-AVA= 336
-AVE= 337
-AVI= 338
-AVM= 339
-AVQ= 340
-AVU= 341
-AVY= 342
-AVc= 343
-AVg= 344
-AVk= 345
-AVo= 346
-AVs= 347
-AVw= 348
-AV0= 349
-AV4= 350
-AV8= 351
-AWA= 352
-AWE= 353
-AWI= 354
-AWM= 355
-AWQ= 356
-AWU= 357
-AWY= 358
-AWc= 359
-AWg= 360
-AWk= 361
-AWo= 362
-AWs= 363
-AWw= 364
-AW0= 365
-AW4= 366
-AW8= 367
-AXA= 368
-AXE= 369
-AXI= 370
-AXM= 371
-AXQ= 372
-AXU= 373
-AXY= 374
-AXc= 375
-AXg= 376
-AXk= 377
-AXo= 378
-AXs= 379
-AXw= 380
-AX0= 381
-AX4= 382
-AX8= 383
-AYA= 384
-AYE= 385
-AYI= 386
-AYM= 387
-AYQ= 388
-AYU= 389
-AYY= 390
-AYc= 391
-AYg= 392
-AYk= 393
-AYo= 394
-AYs= 395
-AYw= 396
-AY0= 397
-AY4= 398
-AY8= 399
-AZA= 400
-AZE= 401
-AZI= 402
-AZM= 403
-AZQ= 404
-AZU= 405
-AZY= 406
-AZc= 407
-AZg= 408
-AZk= 409
-AZo= 410
-AZs= 411
-AZw= 412
-AZ0= 413
-AZ4= 414
-AZ8= 415
-AaA= 416
-AaE= 417
-AaI= 418
-AaM= 419
-AaQ= 420
-AaU= 421
-AaY= 422
-Aac= 423
-Aag= 424
-Aak= 425
-Aao= 426
-Aas= 427
-Aaw= 428
-Aa0= 429
-Aa4= 430
-Aa8= 431
-AbA= 432
-AbE= 433
-AbI= 434
-AbM= 435
-AbQ= 436
-AbU= 437
-AbY= 438
-Abc= 439
-Abg= 440
-Abk= 441
-Abo= 442
-Abs= 443
-Abw= 444
-Ab0= 445
-Ab4= 446
-Ab8= 447
-AcA= 448
-AcE= 449
-AcI= 450
-AcM= 451
-AcQ= 452
-AcU= 453
-AcY= 454
-Acc= 455
-Acg= 456
-Ack= 457
-Aco= 458
-Acs= 459
-Acw= 460
-Ac0= 461
-Ac4= 462
-Ac8= 463
-AdA= 464
-AdE= 465
-AdI= 466
-AdM= 467
-AdQ= 468
-AdU= 469
-AdY= 470
-Adc= 471
-Adg= 472
-Adk= 473
-Ado= 474
-Ads= 475
-Adw= 476
-Ad0= 477
-Ad4= 478
-Ad8= 479
-AeA= 480
-AeE= 481
-AeI= 482
-AeM= 483
-AeQ= 484
-AeU= 485
-AeY= 486
-Aec= 487
-Aeg= 488
-Aek= 489
-Aeo= 490
-Aes= 491
-Aew= 492
-Ae0= 493
-Ae4= 494
-Ae8= 495
-AfA= 496
-AfE= 497
-AfI= 498
-AfM= 499
-AfQ= 500
-AfU= 501
-AfY= 502
-Afc= 503
-Afg= 504
-Afk= 505
-Afo= 506
-Afs= 507
-Afw= 508
-Af0= 509
-Af4= 510
-Af8= 511
-AgA= 512
-ALDs7paJl5xPh6ORH61iDA6pONpV0rTjGiTkLEW2JsVsRKaRiS4AGn2PTR1UZXP0vXAmRXwdSegQgWPUp3Hm3RofRcDh1SykZBLif7ulau1hVO+rhwRyKc7F8F+7LcMf/v+s73eOXUDbbI2r52wfr7skZy/IELhsC8EK6HzhACI3 124241322153253947064453752054205174382289463089695815605736438952932114700118408072544073767229325045596832952652232288773280299665950768731398747700657715829631597019676014848183966683866396215048196276450953653433516126074463193382764063985175903718735372053536664711482497859539116009770850968340298474039
-AOzgU1s6Pd2IkrJlvGND8legXTe50nyDCocI5mwT9rW0YsisY5jaaEOcu51BAq9MmXBPeVX0k/jlXwH4Pn3mCpUAU1rEOsTdcmSJp35siKliDdhTZHHdZNMW+igfXGX5OCsA/BaBcGnE6NnrGWXKyTOoVUGQLEkL2T5yhNUaCT83 166340174936369324883416612727439279977041963320514134445183426741643586944819834936989524033374309932122967866930503619179389342537723598234062828695747850043368572301869699886931403612266216965783079972698791813140295203826980649434652168563255385527187360027803388963151668338040517316899628026707657178935
-AO8hrpw+lDiJ13JahLtCb1RenupQcNd0wlTSck9OLL8wB/x6gAoj0PTLV05eZIbz43N3GUSDmmckjlxdHXiBJ9rsoB0P95l1CWIV+4rXblCqxmOdmlm6VZ13bqbI0x7l0cjeMrkmk+yJ067WqUolqQBlUWMTuJVfkxALJYH5xr/C 167923899524385316022824282304301434707626789716026029252173742527362300338760906999615029022863637963070711762128687835779073122264515776657475985362344360699359591353388569856862973447791264902182048648600267737826849280828116753682917256540180401899752566540869918949003470368970029744573140084219550547906
-QxAn7yrdVs5tlHV+Glbqdaj67c6Ni8am3bBLOL8PV5HbdrLf2xIPmNugo6MfUwFSnT+ZPJ51+VTOsItaNwCFju0Eh1cqyP3JWyLRPE7emKuo6xRhf+5ik0pTg77LEF4JXW6ofDqirpR4alFi0G2d9yImQPphsYJwYGF/nNT8u0Q= 47093316905427544098193936500644355852669366083115552072584429220248776817916430034648347490325490701471113667554329499736495877969341478442613611948220957798780043076906836236556612316544460763366275536846463456405604189392790111985912854476264292503164100482712281088955640964034295834935468665872932715332
-AI9PVzrbJUvmCihwSFans1lBKwudGEZpWWu8pkSK2zVgzGhMvUoGgMp6TG2zsUd1tV8zv7KsVD2t6pXmjT1wPUynufq97GVHI06SGpflDTt30WboYRh3DgYxvso1sOjUXpnDezcaqc2Aiz4nV5MSShkBlyBjA8z2worHDE+uXqw0 100635651531872121827765663065728398779771663753008344681972226973080394359405041113312675686974926993279775427390065833081040771269307007695807025882757371805607979134114890454059957194316765342461291139168706134406917264848659448693866813989352429841300235734400772946895458374870482441457514575059390213172
-FiinVicXOqqRLpxcGTorQpSAGeQ/PfDOuzYK9ViFtmPv6D0cYPfhUH4qXEHOejvmX+0b4lfaX8MWPVZxlqpfXiU9BhG76HJxkLF4ysipukeOvhoHzvcxE5bnhSF1i//bOSifATBLBEZInwqSVg5tHHPuuCkwTL91NqhOulp7Lsk= 15560440884463435471963622630292643727112462888414585143143739400703889930416938984547754943252935620248108237258540176511252143752416771350868493435174026287082706690332705481726295797196444796135827460509780634261726494455068460028424141500629527968240913757449787164107068039175831847071025316475940056777
-aYrxyQN/hkBne2ayqo2/iDLF3DZGgk080SOMJfsj9h3Z1OfFZM7TJA+y+/O7niqatosvKrfHrAw+Qs7c6tCZ6NPwYJ4QJLOF9bqH2u2a3fkI954voNUctlUagYUJsZXV8hdhLM6NwUyIZ3ZFkPcpTZp7nKQQ84tr1a8VjDIT5/o= 74114640794666001532816944350975062126079079113921109750255283189037502412929005615388097912507598112836936032143435813588205939470002911374442844578739574773399427907766548612582213272643279263782396527705126350063372192910060171635870872236876399794128383338399728947176692692942605589343038282957050865658
-AMpCUeKUX/vtRslWiUUuXNl1KA9uDAWjMUkTrdsxxRDESI7iZIn3TR9lW+0kV5fzkLF18iYLAwSGBmX1PS/T0UVFmoBPJ9yS7yktNL0lpQ3noyGFn8HHZ6XB3FkH3jegIfGbvwwhnhhFzpHPrXlpO5iU5Y+rexzp2XHWt4yJGuIL 142031143422642739313498629438991149460874309300342349421794421544918823888598660275343727563280565210534243383322796489809683834300630555650331646026843796764549231159336347965502383849513994449309613369541991287590422095953275586374371960367000083487965487661436037637475372929033613295072397262739084075531
-AIMIQVz0JIEKEI+PREu94m3v9XoiU/Q0CpsSuqkwSSje+Wyul5ea9oU5qgtOpdkMUOW91BJo0DW/GMZ8v3C4qyyP29TtjCcAHObJi9hfLSlnTSuzXZnDStooYYKqzfToLToCaAJKCXiXAVW0vWtapLnyqafrf/KgyGZ5u4HfXKY0 92013973253053602863003242446596060337454881568126916916519869242232429836082762281129448384605359749247852792606718908482332975424967542242332487707042773885428473061056052851768940900752317020681189773407893371297668591494665352294885305475871917069040377145530889271334616499701769138948975263435137525300
-ANfP+zPBTR27afneyac1KJhOB5Pq3AXB+SoAXJvQI/GkSoNhw5KdfqoIkLcoJi8wClCm424Gm1AdrdGwDFOM/iKTSPkrvMag93+b2EbQGX66/n2X3YRFNkgq/Gtb+2M8oCcAL054Z/iiMD67aU5RWzjqS64ePHsn01bJ7dqLgpMO 151548639867177154896951257541227014781655576169318283047778755573323724856619156348444192550664853912434681577093459933599575436686424046466113215132845213008587152894642577278656978304699131916299275797578171518984206145555369576872231567191579337901913492071976578289189524123204040497290426960375042970382
-AK0kHtacLGu1NFWMADq2rG8hpzM4UEYyPOL+aMJbnwXcUYptRIxb0YFZg35RN/RiZs4lQsiq+kEJKzMMV71TsJq59vMkIZhZoB3t8g9ZqBZuq0JYcTICDwRpNSttJidVpJ6P9sR3s1xPMYKdlSwt6EEc9htOXfZU+yHKYgn98X60 121583812047864398969816595368193171848971298823388059338224714026742264861090347096116404814514279627148994345584790617974476594451626305761040465570524035369799925437276511604752129817947910677564301623631349399504187314174538914591944778074509068973226322566160587813128746039859381466427380402262866230964
-W3sZlWW1Aev3x/DiH9MzwCAZzBj++x9cknLfGAHwgFqkLH6vimEH/r8hi85hzlCOG5CjwhoZ0D/Hsfr26ZJ3X4chG84byrfDnek1V9mm1++v+clJvlYgcuVgn2Opsba2TILTm1MDB+Ujs9brJ2AAKrE9+ep5nvtQVeG9PUGtdlo= 64240043913835461386212515483198059541440539167395859777194837833769712010594411295323900074066077107346806786205590345517755715510695858065925747020336398305793661773798243627926904542715123849691490667964262778804487343218972081260210371192903128886030021862362141928329650003493687310970684093289133340250
-FTQRk9/BIj21gbLwI22fHJWYj+8Ghdcc613hOtJ+/hQmh73HwTXLpaGK9aCptxVbpjW0r/bxaRjmgxu9u1CCZh5yRd7Z46Wk/LIPXGd3ycQzqRMFB7TISFQGJIcFoxRp3Eb5wa2OyrUg7c/D+kb7oFJq9P7mEwIh8TpLzwmu4SU= 14889529068556301710329043521845510156960298822469914567758538023025100741826628180855835334285179977296740667353391766487166458692144569279381035582718738461626140662441222061900764829681913534146898551570916312642104487829660946024590782808750587095559047648957238487820069966851521487428624726655438348581
-APYXO6uGvs9qWiEAkcWsaCaCrGJJCP2Z1g++XlJ67oZIgEoWITn3T/R2/c4edAfwUUzNHAYZN1h2dSrRoqlrRXrbxFtGOuRCUrXcGLFFcEbTrtm+z5z8xGRfcorx7Cu3FIBPMK5XcGPcbRZdyP1gBkeDMvuBNAo0/To+LP/dhCNM 172810804474418448604443090732221483571611665465870520701624598983692130272337358406272727413570938793741430131635927237320173996217984860203754686741782921346604605228620148450611724714868551781003004492587584071978757421616871762681049508123223983431502852926521520561941051298696758046005573332373854233420
-AIDNxhnDEe1kTJ3XGfTS8zKXeXPRdw5yifm8j8Ibzj/quExy7hFPtKct8hRskPR2qwTlMiW9Ra8Npg2USsqHV0rBoIkX7E3psxq5LBfp/q00l3SEBuLL4K2FGR87bPgU+Duk3RVrNMnColiTcnAR5XkoeWhn/r9MfJMIN9Y0FEh8 90449107125498302548188660544012777357148118984122992664008792590422284061463729084479315745509706793674355738023180454297730948397413371686013210006834869294564190666543874617716180411178090109573192518129248278410216362657350215009192850017507998797754539132540293137589672869131300859207213449571846080636
-AIRWavxYRsGlH0Yr0DudwrpYtbrByf9ZsDawKom7ubiRfepqYzcBlwt4adMMnkYSaXeYtOsD4KBm2ZvLKN3++RkYNmxgkyarORBEg7ERyiThBj7Ksw57pNHCAoHtBEhH7Wp9mHhuZtPvPgCEptmwCu9rYhLt4zZp+Zq8a02dkXvM 92930601962515884925250459851491509622611227724602941760145671636277317511265759558869239180653492283311584982044597979173761619470326096725838197524704577188104121460089235709339932110663536557497112887112782062772810759971739760085128369628777812332518137107605855679096146402427144185104230596200130247628
-AMNJGLcAiJtL5fUfkesWKYJurdYSnvsOZeZcrg7bemkEVjF6S9CcojimUl+ncr/YY5/EXnU0mg84fObtDxWWdJ7z7l0CFcoALTyEatDYKshT0xvdKY3u+LUShxIAyk8EcGnf+KoEaa4Mx3tg2oTBnVegXClOakNTWw8bu2ItagoQ 137134165107366719462230252606689766470445826753581409513106273517221906418464863733870948759313279128624638614534848890858250894834883265387344539280755177217350585564186248554307335197387734431939154077778003706720017441895613190141376534460438929588407764609772857975000507660651583780079804513519571438096
-BmGPZt8XqqI1PuLN4K1/PZMi2rfOYtHEMrcwZdSjKRm5qTkd0Pbb/5zPV07TnM0uLRvIQYTLloEY+GYyn0K5gDTEZpEtQ8ee6Y87zYGDwcf20eqYNxkA7FVV71vqCP/Uw3Oi6B+hMvsWZbvv2vH6MkAeADCrezOtwqVS+irftyc= 4480956865245875120472829476982311611308898564405318773810939350829150182630548948231116574193987272498161864310429976564278532538229396846813874244969927890037756969704618336242255039858182439641759659872128285423988638335967412040624105824571426792562334458751137508116412821914961236269913776304372561703
-APqFgCIYbJWuRyEGuOStPvcprj2PILQ0JpgwQ2jLKn3DvkWSd83qh7PWGKozGavsjh803K+ZzI7P2wP+Nc0r0El3q4nzaHvKaCtVRyMwbXv9wYLFZICeM6J1l9ljUMts4tbDoPzkIy3ScU7pYxarBWqMkcBU8qL6NN1vEdkeu0fW 175922170410080716883576123079908758276229469783745771772401183721225804343343063277676406040455068452258961299511343441961963941297631097736305638850193978800615558067791016294285848963023036905095022181004058235239390870177623185946205281141386416867569004073524130001309977475780893497185890756991672600534
-APA/rCcGeH6A+6ZwaBBDM6mB6tTD8mjkrOWEo/pK3MCZ+rrErMBnFp2S19GhlLOfuY8BHS+D834Fdm8+3wKYkWnXZpGb+e3v8ofOQ34G1HvzULOYtrEiC4ISZRt2SSyz2hU+PBXjVnplsHWTRxZDmBxTJdgli4ItAqxGCxj/aJ9m 168708388929747822981923386197903561880341990893945097067702518857172133291360611402092714329372304718329568897960770488377524912057166920574319430820488930520807742026377043178502591886293565177404635365772829346030773275726024973460121300339258054215286249329967181244588558220467488638468686270735376228198
-AKmwrLP108dCGWOWxE/6woJVLRi/Kra/DvdsPkkrZQmWIlUT7IvwM4gU6bUr4f6wpT08cIQls2cGh7dbSEaO0xLa3mmtKhPiAlzSnz0wuifF3JT9U3uXgUfCZuFtE0z7Oi7WTOrpl3k3GA7JFvXnY0lwblIQALVf6oWyNETnajGl 119160465301384937485959146028591622947513292915838943629387700439301197965652871741710280647524383590817798553034250156068573474278225305190573334054718387045488098320076877626430189054572361967283632592181431701411266656256255758079114072932140551282607247364388070762970060420036793573956057551235306893733
-VTe3rCzAL1Sljo3QAXEkAdBy1ZARHZwtrj6ZNRa5ttqd6/l21g4z3iHCeGo4rnE2F8wYTy+NlugjXw86OS+XojW5y6UzTtx0HX5IJ4POqN64aXWmaklGzroBEYWeuFFKcgQN3NOxkuJoDQ6VElP7Epz69kj5CsKJUwL0SjbNrFY= 59841866347633473702601462509811342285929528424012250265905695635971518533504187799047710303717472950129869674786231155102509311322791323986824635569605105662070745033595366004805920086888891275288347907772640070278731650628917037915863439204501060041944275512863990729926528905725569467329169134226609384534
-AIZt1xGhC/HrvpPASsvVIVdsu//tn0noyJmVYh3FdQ6yIh1uce47iCsrV1yvYqx5ZTbC0vnfnbjFcWqH+HtLX/DelgvhEwzqJ8hwQrfE1ShLG4ZjAVo1Z4GCjrDcEUMlwKcunuSJssuxeQuXwTLS92+q6QeBSS7OmfxPX29CLb4B 94399298271083745508290936113986978382457275531684761701599029877008571741877683365769553170771833981099580359640421358853566501815723434822307977440496208486103754978934472597505865596938563438311337045817621762649604204720249750058676095769230214181772215323235427976398686727606000594646472236822594174465
-NIhTPpWXS82VTA0LTd6TfM+HgLgUcmvnMYtLqPpuqCKZwalAycwl0XFYNyVvaY21J94j92ts/lRYgVtHDhk7/9nLXq5js/lsUnG8rWPHJo11JTxvW+df88aX0pw8u+biOWt87vc1MW1dsMTTsJFJAeBx77qU/Cwto95IVqM7vSE= 36889590210230649939994518345793530042252563793069578097360569338647730438860274349862767107939590441616825589851005429465345268710487649366046960918184701290985280638488938340668212498212581853679035928093386035688597446809895381618260692378376844452061580510108168030682664507293277674052032318576713776417
-KXdi4A2Z7tSiiX9YGtDtxUXIfQvPhcc48rUH+Q2SnXL7fLNmr+F4Rf3RiFBRiHKocPfE94pothop5qQJ5X221/DbEKWK6s+ChfQ636jvRxojoLMab3dPtaAPpDJHrfZMxbT4ZaDJT0tpA2e+zZrzBuDs+UUgCpty9nxtdm1gS7A= 29118662951481660380477444121362422614202367719725087486810943918529894738076273660245405874301505615796632229852040910511025841576465052938308369421493312085081188509808322692130449282585522349552501983296872614029139293444558468751646868108213623606366977549477663987815308260383403466635254115908032940976
-AIOTBZQR2EJJRmoWdRNFLG4fceoS3KnRTHRpPdllhHODqdg+QxTOcOvqIzBqgdD0JgO12SuNAjLQOiz0jhd02qkXw9Y1adGuKvL97ARFtNEuJiNzFAj7KpDLy2zk2rPJp4Lp7cjQs0fe8BQYnTzTsNRGm+4ybln/gse1YWu9w8y5 92394618277596007469808288231093678404089765494062813665106014405059399079199990128824492247005602685377185496959522609467906358619318009231448503013528692450191782140091818984176967246749464502089280153086163239846744554575017530385347720563798041108608545014076448155956762636929707905789978331102411214009
-NzfbJRBF4pqEeborJrjoknJgpfK+DZh2k9cE5dcElMPZ2Zn9im7desWGiBSQnu3KbTO4L/t4+m6nFTNcbIJnqbVSMDHdsfG72rG/t89aOuECQw0HMVVgONNNa6i/mw0jZSWnRLD4fa1YgbUlMd8jeqO9XcBDB4mVtDTxyeGa3vU= 38775530011374537813502898274019389132620116890266344603221997943675706375698597061571989090674289834838060050848545748579361837989319487970580969082824601965845786771062335733318139530316825802589479118956745739691326447349403950997231306042638797277408335778415717988679050762936401945487285814799382535925
-Y4BVPZ6necuLSwaqYEPeZp0lt9tTGFl/WCJJbwg7XpyvuwYKtzagC1NLzY5ymBfwGFw1yRlQuyGsYd9mBfC99DuVCIeh0JNrhJN1bNfoSzy5UO5+dmTr+dm66VGSRS0tFcViDTfCIleTV+zxo/xuZT+Bjxq7kZue8zGkjp42Kmo= 69872189501616471647606976308259279995249122669120675885925763529037695584466011511740991152346215507625265226811128801733353566555339153627478941716586678793853828514394269931890370517258825006937741437480128878717892485074131232336852490940507703859793477547154689914725314529986438108117871674332626168426
-AKCP9Mto4q/a2xNqM4N7PekbKspwt48OGPre+iqVwPrSP/jWKxg3CvvLNZzN5P+/FiUGIklMMFJ8w76OaHIPqKuwckj1gvCLECJEE+UAZWrNKPmpzd/ootN9/kQhNMuloTFCyhXAUUOXJ7Z0WVLb2u6fn4zroszSMBoWQEKC6lcq 112750701794692134675959811050012620191158543234019977304167102486465198271340022889272244811582365901584420008564301920174477182946432553537794834985703732129975734658113610563794129371053853971031300761815004524681756388784922001759202643614966614186697992611399618828963452661554240362943588548146868410154
-APOTAFA2waoAODECaGNgCHa8dNN+cjMnD01M+IeQFytzo9RLMzzzg/gpTUFpyLtFMcfbCkDYQMLXwE4crTimdz5sVvjGQ+5fSFQjoDY6Bw7MO6NAcLzlV/sI/1WyNBKaLQbcl2720n16tdUcdckQNnV+cC2J48CVxYM1c7QQlxA0 171043636512232272455501595416608280460445723238023572475354665686544174728784633443479486247342724860289312593374524429736857970220153680852977711594899595712511352458264354251161579203922747468321999465061463474727943140910084880926005209538535217464825087114791420210981711903880998556269523363208766099508
-AMGpxRlB8WVnsGqyyiy3/mzrPymtJW1o1HcDErK11ZwQV5PwTF3c0THwlnxDmcziLWHSWgPQwfRddVDCXMGW9BffJn+XO6aTcWDPmDAh+1DbWJPE1aqApGbHvQ8HONy90dQMZf1ayuwceWCVTuU1wnHdo9F/sIsRbuu7ic2OJDzY 135994898408425255747055209966103741651849229328236418804928584233229830656742052333413774490626915784901255640138520158698845938184666683995579777154437927013722740366497459963753542029774185193376253885864514386760437194444013834088425088260658670140534670789371556026135595577395047002643901630053097946328
-AJAw4uDYdSYkOrjtwJVWLv3pi1+UxWge4RmkWKqVquTsAVcT2tRZ+MFdHM457Hl7fmFIyxvGZQy4c2v1AbHEfPR8ID2sCRQpdcfrxEUZPMDqxfnHHm0ziny6W4X6ggdBzMp/sBWaVNTBL0e61/pELBGYNRGFMzGws7HQkr/sro1D 101254336834199527040756567675327011562230719161388328289463594628690618298993695452746353237675715087353241661592074446889034411683413957950360025295995263477031608845241728493807755308798509893719674568267846671753070163272328014412744008880395248474446310603301447848026040555910147467745595720879397834051
-AM09TdtXgYL4FI5CGNiVjf0T/AN/pZ5zZsBOi1MAUKMURiXnc1x8VKYTqM9Xb86mqNBBqphynIQG6/3e/YbGJgHlsSdrmKbo+P9daMr02I/7Z76/7Osa8+7Ky6lhVCbU3F0tBH4WvopkCQmuJ267afgvDD5kB+9uNr28deMH00cY 144124056591600568767398029380314564902309327093641173350205276895603332085753288682409279238417493662029954512382520307259348748813767324609446500382301421328754981718014234615523158887865271179104711373675849713359713282937065993613915015084108700238420759344034475478243507306107546245540340758766909867800
-AKDhK+/BKGXbrbBh2vM61OP8LN81YwlJKe68KNwUu4tjXlQg7i49Jis7QKPI/YFPUpSNTu5N2iCgeMnCX4+r3NAfivOao9lw4N3nc9bi839SIWdlokhwBHBYmCIgjehUeBAdkU4jKqlE06pIrpRmSvBtn7O4aWTbT+C++ViYAcGF 112973480670453665543892521898882856059335781900313607790238402438320486344365203510769919022496690291280873287383392088872774202832124927485754495093552572232234532821756395965072330282810574669371524103814871172318519695921477775100282448247625395376072233777533359104085023946019406729587713120941266551173
-ALxDiSxHjfxvP8ETvpE+SyDPTS7q3o3zCK519WTepygC58KSRfvDnIVIyV3toQKzgqD50kF1Ni5D/wuaSs62y3zg3kELX1g+WuBCc8+x50+kDtbHXa1Me3et/OqVS/QeppkcjK1UZMU29fXze6P/w6aQfvKQkE7koeQtZBKkYc0p 132203344567902304830160099595561253300484092355345272411265169562971473393256361094745618829297250316196312398486598077249124198329075791740755862221465178128527292695331061023291345396067863215552021206609309872689233899464919108147533679134727064586730810633196817136739658243232643507412032417747255282985
-VF0YUTvy8Mfi5o6X06DEvLm87r72mAtTdyyLNr0/GXlk0Xj3L2Oi2bVUMtcXQNRXg/mkdGP88pgdaP/eMzqkUU++vJ7t3UgOC1i3SHegpiBhhZh+aZHH/wjFV8Mz2XZB5z8MpMgN+QwALK1TT2Pyt/feQTsOy0imVanB5+OvCeQ= 59242171319056188000481457618922567543461456096441095927600135114274111606802456239311634638536207588762066940095527920532936960549439269891703098017342732142860571277442598349453761561189719823290643146391349978698217357430495238876700400634593256155537598291759795109752990651995982467695091946768443574756
-ezpwBt0N6QhTusiPcKrBvSB6yuk/KShTLUFQHdf5J1u1fgDYrp+aOWuXOFVfOd0bweiG4UxBQNXB2IDFWfYON0fBoaDqNk/41YyqXBSkKbiNWLi1y3zPmwTAiwK0PzYp2EPfk/t/j0HsDbvebu0ygcxb2tPqj4EQ1TXEdD007kU= 86533835313999945727720083706940213467453975054116752898416709637030456504024135513972566184073843025739226187558143854850980654667596935003124034699919861200483994576288766702308068265526535622439762454501169018136389983894783905946543636163866717367545972667876983557989192393479830223914708619684891389509
-U8BT26zT46tTZnkmTNxGUAlXbJhk5cNi4AMSd8fSvZHm55siMFGJ8Jl7mtdzEFR1UFAyEztf2fUhxdtMLe8ei/OJgM0j7myQ9STucEwnsShT7QS/DjBmfvcC42sl1CRpXkb0ZLrEJCPf+crtLKGrG7ExS1oawIAgALBiMQIL6mE= 58812148564290791415180898639607206220554150794356494356250223429674091688305329629529905854147200457536549527135776329004085047145097927266797668252160196098870200925284256433894773392353678965699083286106628662506590268955650280670838340651598082083455821825076016227525614626726458235627297885815646710369
-HfYii3U1SIkBZl09RHaGGA7H3np+qxyNeeCNY07PDl8LwZAaaYk/bHPeBVboan0I2X4o78zCD/gFXFBJ4rxwwUsVjHEioyO2JcpV2/oDOelJBD//78WzBMMSWt7ZKbJV9uYr9ZUM0BUD3fsk1esFCEdnDJdr86U0UMmiig2R+ME= 21039655953870571289679214995029926285040274249531458675115179004718812090027267801012507748013357317597416722235988917212676802092082137617336199787762782958420742299451435320649616271885264333948336627286638368859041172783505464468640994920853000441536629081040963398001710173320125308624362209157720438977
-AICOlee3daFyqTrTdtWjVb5M2rclh9BpIo1CRvKo2bF7NYcjrU0/VvbOnTVXDwdeGMLupbi76f0BrfDxYtkzMXvIZlgoTit4g5ennnklDHFBC5cogaGlri8U28w4/h5oMunZ1O4ezdpRgVJe9nTP/sSEMYiNS5IA7Zshdvm/XccF 90275777798511290102824338787811725003177532250296755103300529948194832904403489332420505850668003332750291879153080212231952155092379375422537931240723308384652734942204313672973885652497290433943089371705605128843469306776615573873479312715317072986990219294942040272550822460408702072075001377245051602693
-L0QUSVIjxvE201b1ztRZyOOxy8vkUz6626TH4tbLwXjjc+AhmrvplaVlavnOgHqve+/L18XNuAYP4BqdxIcWTx+yxBKm4ZS92dRJdcAtccvZpEJtYjdJvI6qbL5Ph6HluaVZwp4dyFyXuZOJGTfYdTb7PUWM0jNT/xsqyjxSQ2U= 33191267986826803728285073844005357792766429917696698533494382218509532051029343127452480789088572904364699220151221680328978554239767633887572649589456766209242252549993823283929686430100804479376247660556781589549613316880150951333982646510273364068770923588389668733632648346075516618646974067295703417701
-APlD9ECKJuACUmQUsbd2GTOpb2PgQVT08C/5hyNEVdA5bWoICX7epmoCKCybdolk+cfEBP6fSz33j+Vn8MbeiHBLdmF6ETbmcyOjldJ902MDvU8dqAa8IgEZN5Uh5x/xzN+3dqk9o0ji7yi291u90rpfIh85PPpDat2B4l5zs9i5 175040148659257809883308984693597046378367187659749953472629929701758633206586720399909808941145946314755491399962797299295431089674294356220216615950668954164397362123668926410543898553191541662075745481299747832013627018846822876386760538344447600390187421938699064459451308870669878673306013635576901916857
-KB7N0tE+A5vFhyrd/m6Qe1wTihkjqmBn+rinfmMAzRlvtxIBSyDLzQsOQs7L4oTG64ABU+YwcWVijvoeZNamaxGl4hatAH1pRqmC/r8FMvC4vqiFTbFHzQhkjM7uoHD1aKnxyBVgjMj0E0KZjrRxydZjIR2p13FXjLP3UQSFtII= 28173452509830313810392326357601136401754938805266458365469366750775669869895498658593356375710132149836430968810246171974040975430205200958564616924399794768861923079158311829444850822144940112488994119845741191519421434257276977333662656888696213514226866147767570046232093727585815615828360199830275208322
-bxFgV7eXwnbQScl4VzS3RTdcMW+NY6pcGkT1UsqHIeDVyBb8DnH/2/Z+DX3zniR1iW6FPdvhJJeQyPIax1ohILa11R27C1TLxGvTrRBGUycxjEcBIxamHveBsXbECWusYLEakeSDg9x4BTWMz1rTQajkorBoeEjYuW+xBxQtXME= 77994515143740690952370766995249847650881300682406161400195705464876513409097078624084133111941171517535435606295232558665316819077765607639545069239931096306624817379462598756505457054433358548941076472902905065316335603665413114267741896000877284610377452471067725794013283338924419969559537339967562669249
-AOH6E2eBzD76QdTJ6QbR/7OeF7AagUif9pEYx7fMqrIsXCJKKpLV/RHIItCDYP2WO4URCaVueoAJe3M/Shj4o6efvH9pf5Q8MLM0rn5MTHWhThivqYQDwjCp1ZsPgq1VFS+gcnmwgHhj2W7XzJxiNPeRXlxI2vL+XTT/wPBYhqEP 158686346608862569574095184731081143351413141116869402750758091813874232272198082464382169470744476593016502816563462778075467588097653320101723165887488327616477297401486647183409348122990505635004320879840358339260797834264972100385692477324858942142372580281421734058008608134075577990829273447077276721423
-ANDDgNXOB/rXwmS4KEjiHj7RCDocVrMv5SU0aw6AJzNTBfseFngqidXx2AJKOEeG7RDDN2gzn4K4qJktF0AIPG2JbELlLUu0MFlpOLxamp586qyp67Cl9OuPq3UZTyQhIsSIE3VQkvxuQkGsaV1owDV3BKIWQbQEqMQI3yT4ELHm 146598844784260148346676185962272439320781765598895126402049215152385925250917998794921584290777625240122575975327405909800121511343265147922400813488099624745229653124857224399973509428158163452130086943873214460600035260925149630502192183407327427517292065083168010281295559088633086659209316582810260124134
-Vprr6oBnWuxIzyTZjuxlKSdZhBc0upeNBHVIlXpQEnN1Q+XURKzp4/6Vg/koITftr3SMSgGpE7LkrERMGFgYaqM5XZ1RXYFKT9dRJnz9VRDITVZtdkDrU04bqo2Ur+jvZhvg/oHBDTgQ4nPLJfHO3+GEmUtck+g/wOVozMMgufY= 60816213163057201559480662231646403262735082707152897397414589876256824040344252799972529759737904461369360580708093117244392116003622336721789703580184437841209963565058475060017600871779929808204093448248984201640754565635410002090180110910120481044515630478472999135146756643143415057403006410330361346550
-do4LGsm0afQLHl9alWF2RVyEKPxLIErsf4pTPgScRE7ZiTSVErbCDeyzd/KHzhBLQs/DhHHcw+OXj541cIRm6jaLVKiT8EwLW/dVG0AkVli83sFh2f56Kk+bCGSKvfGEQcGLY2k7nQ06zoMlYR/xbZCka6Q6kSq4YBDQgigQ1lU= 83252051731120517035090523892596419800592471447735288551342681962005778435125655090199060145942826521644585427683714084736143440310518046334877897672493531918539106001203807757254797471481884534543367685912500572052457610702790097953420236852480969038388056545966568595395722585797418296411673622376893961813
-OL2Qoj4xkqRrQmuuLwrABG3BMMBNGjfBtVBNTdBf7g027Ghkk/z3aK3jKT1EPpdiOdn8zXYBSO1mTRGyK3n7Jo8ICOcnlBOF6cZtDsb9bvSVE26MOD2wzl6irU7vzS+s3vGBkN3AazrxPD4czk3xezA9y13DJVnNzgAgIQHEols= 39844525812817530522650122383059885756573694015271773938493414420875846359054562126060762455794481186614035892021706051863945033061233991184379580556219478200155757966121832613842937722944431875100059046588723473670448006803481527981834627086055642349130254917244469014754132003347635357123155857820000494171
-Ljgn+3Hcg5DOf6usRumk7P+ZrdTBRmo968HdZU1mS7LwLW3Hii2KNkwMV7J77zA0P1pnvhMSEEeh1RbCUjLtSIbt3RIcOEoc+aO0eINF8r99l83xF57CBI3MDA3AAbtaYATy/NUXSC2h4W5kdsQuR88139MFi5y8E5njqxHu3UI= 32456338403763561215581247445990611953939298888251578685087656354454727113846722731945605696397627662593375001096230320486703167389461057538581895745078593206660798580358701927596287363374862536765135996838944212622199018632046955402325290145163082309469649329852148345837780541107029165352782710901375425858
-AMt5/u+ZUNm+Xsucr4RQPUu6ExAOq/Jbcjm/Kb2YIAaEQ1czIL82wsu6YmpHcfMaxLjY+EnaaF+eCWQPeGd1av919+QFbQPeh5DT7ZT9klK7BFyVsN0nEDJQ3AMMJqq6lm4sUeVxDVTmMypYnkzRl7jqzyCRY1MHA+o2LyMECdOg 142886089970163885609957244378225169093559131065687633458877059657380607541767850701139140472705242750285722732461954100519608059127637509286558848391554697942686619832870045594188204522385787253648018847569919409782188708374165437385572046835539379151066214153911415525465041951116179326632238059135825466272
-AMvXeHCaa+zk5VdB27KoS8XpjSUngaw7Gwlq6e2RrkEOxBhU2rGWGJ3fhq1HBNRxDf0quqfYTMd1speisaEr3cIyx9BhYwB6A+Nex/Sf9DSixezhcgEz6c5CfwUYP0QTTOiZDqzz+GcjKikjN7DKJTO0WSXMRG8qX8FBbH0rlc9l 143142496664357119491819741364830737485524654099662921673419335301323845847085335210884201567922636945282124120681371777665458057821603161276185071778040317947168899788341482064834489328957963447735297898161379277478278414388733161844053774747425459239004132791029364174047523473372650441001639174571312926565
-AMxoMXHfE2i4khsAkv/lPtLQhbWUjP3kxYmlJkpacpicBB6z/TmG5zjmTC/sqzBvBn3J4UvMzKYFyk9/l7Wnuc480500a3S4HRVtMtirPueV8v/SPktL67eN2zoj1VZA/Rex0aRGjW2CzEKGwEn3G2bZSgdT8hKv7AypF69ppjz6 143539479941314279463880342636704987025205547180882175105616955926182352311179043850344463145750154442573797875223178075233807385237935671604701513551125937539235111702655902037518920150424691586943553275517626347557879039695678271564616114192941679606063184290901862703975921261779714258077775731727612132602
-ODvOKg7l9RCn5CePG1FfMitkR5l9+7JK67eU+WeA5p1YXCcKS8GbYAKCtXPD2QfxmQcrNYfAc6Yb/kksaq29oW7MzZuTDzK0HXY5xBc/fJzEuvU51gaI0PR3cuU1qRlLqwmIlyt16gto+2E64BgPgIKJcAjx+TfH/EqNeJ77/W4= 39488587053253042573878502921384752550143716864908041972426777545317969264945056510991363961916339225192727727267483337259701961148978214005913510275048195308792987888118270387288989623193626554910652030960235845935461155296845475356011099372367616732243132816329531758943935324760665826550992788664237161838
-AKkznyQtB+PGvbVroM5nUIzhJUjiNj7q4fC9sSFbmDgvehnwPElVlie6PimH2FKonGV4GSaxZ+osil+9omfkb4rO3pq8fy5KcFSw/gs09X/U2eEEcUt/4oSbjs2NaMIxQftM2CauULiwfkWdkMFTBkHnh7Bbyocc8dtmrBDdoI8a 118817437232756222334188081193205110010964766506378146125932730686679941224328135190204402802650523704343176483564284220367074983943319572348376466341132480772885833789613392397284313483009178508647973749522358005819092779831781339778163122774381387989185969990310049504391258988402795259963134610905036263194
-AJfwWA7XnYbTjlJt+9hO/Q/OubHkUkyMYrN6Jd0cN5MG9Rg8W3i8U6oJxT18p4XozkiOgPlF1lE7hIAW9KRKJKGTue+iw0okLq5UNMu2Ha6l5/wzKi0QzRVTBnQm2zjPlQpgUorBBty5mcbt/B/Y3vOE4I3iVXklVtjQ7zIBHaNK 106695084438708194568048926154027115609888551145480521213711726807296356271397749432698558860759334362315257102647885062353922543502466463770991058956633500180245599467233361812610650830611712448187310827443315947425061886163301613989593906515923245020641415290300558869209909418659128196109640872398602216266
-aCXItk5XhuNrbrqJr1Qm04U4y4AzSKDMms11PgVcdf5fCGdizibh6/oZqx5OitM26nRz2vob8F+ZIP0CIyIJU0T1M50dVTbbpwuVNdv/XI6gHekQt0d2g34x1TQJIcsT1VWwGWTPNMtht1hezBAYxwv105AGKnqdLiz04YAdEk0= 73134927546833985031652237686088635686032103401394612286045377544136784429757461671691980910279873140130943470029643791712859175007885735170485461366406852784845528918253441791024065848540598601036357817496637108534035807393364939272891745520961269029038360205258229770737579266643408540634722493263322616397
-APNeoaWlyNa554OtHP8F7GAY5V9F7LMoF2ssg5wBmsgGFktrRH1C4FdyD0COrzIb0Vcko1/HiTnA9JXlfGKc3gTHEnO0gxBSDjK41L+EIgUfR0EhAD9iftTaCoBM7qZN3R1MYrSz3sevQZNMFOOnRrzwWEXnJaPKAZXvsqPzOIF9 170899982929163229592439208307232242235219591108657660041403142612622997092685093132858257827585941687488772925553142105567685213341947938835403410054637382864108739466539574004149772568683507025358331323655651148107044968424043673850583150424463706583215452211942132017052425497789362680979074312857823248765
-ALhwBfBYpOk1pfJcNut0C2fEAd4hhYU03/ZQBqVe/7MgpEDjro7oMvSdba5kjH/VBssmZVqpvuZ5lG+vI9lXLukhwRKJg7m67HG8lZXvjDmjU/PCjxBPNt5r8/DziETYmMa+fhaMTw4hedZcwDe37t1VPIflvM94sBKu6be9yJAn 129516480651398210587505113546142851617282590236388547627336279692965778911450075230961856270046942312918567973875005814982283590898552829322178788678196583244198944578081007477482775130405341039067711963061287597331433268366003672643052056973656674139309732186091974604170508497340243515339072325943686631463
-c9vpoiZvtnj71b8XguD67WayOF57QgOX4V4L++nG2u/RY9VT2+0tJ/C4NIawVa7ScQZAPVLuhV4J50HJX7FZgtY5n+lwMzNo0av7i0IqTS+1BBO8eNJy2wkCbWWBxNybuNnF6OK7eXdPb2Mmwm2OmhN2/j7HAr0cD7rK/Hnif7I= 81358980280155473712258342299472964374474635149963153129588784719499494479288254287754874893180126149146558961101860327826747785201363745989346818037655063262173536227595206355647880155693272153902647256175878517626925488264893732295267833614283963802283320574654949992393798458265266551024756663538388467634
-APArEXNLzDydcHrieLDReJryWxFzcsN1dxjpJIVGeJp6itsJOrUtnmXVnETtaZhWsmN3/Zh0R7TgJ253f7PZ/Z2xCEdqF0hs2MmnERSywdWZQ0a0McbDUUaDjBNYFht1wvS6djbI1b8RfayrnEZ0miYdzrrP1ntU+5cM1QBAvj6T 168651870043094856205824264282870999215855903395882323164614939540734011037112413507417141209480771157672307388419164831992909066097194364645695794831939514470650008210390333649278806163193463937050083854756730458780288720541495880958909249273048328511615821480782977316719631334570687241232556472064072892051
-RhGyx6xibf0OvY1XjnmX5na3G7emG8PWbvEa1kIjR6pK6K1MrMZnxFefXpHWInFS7ADESNI9LHjZB8VW5QrjRVPMksgdEAlkhY7MyQxaclUlShFl2AfKYBfIIro+vg7mUMzMctD+07BLk+jejRHtPVIxHmNnZrZYds80ve5z3Xw= 49204219353786910100605282012781696579642953908541693903348594981245301165936599174304121350092894937817100350990938057159324959104937469442065996667276651025661016077514839755853073999975805394464570132481314896694678249282338429544941873047382467276103868995474424700207571657816852575364781281563515280764
-AKbFfU3GL6NILVyONPVD/X0tffk5HS//7FBp7n6JKMXu3VXvWnfTl32R0WyVHk2yP0iIyi6SUusSicOH9ncO8KJHmaoMGN9Fn+Zq94FTFqZne5NxHmCtwRAbFNDVGg4FeemGXEe1S5Kk1VcvWqnp+QgY0uwa7RtT8C7/T+1pZlwq 117110890075563714812929271250884717870581483065920538069845585667296154465072587148155060755111295509684258790280104272121160614620669593483929827848744548171793187278583947500205314283462739235860439216105116687015890394925743036369717346234391524403038196640934551590543386844279091801685432977718405127210
-AJ0xZ9dfRc6P4W31bMHBymgOq+38ETEIMvMtr+wB5WTcsquZY1IUB4IVkrHaOo3W2SIr479IfJOOQhmvyRS4iB05yDI88Z/fJfXarkH53gDivECuo+5+JmV7e0S6gCvOuVamwoQjlK3G32bCV2946ry4EyIsVZ6Alk9xk7X5HfGU 110384671994603894282707302829898242894456931176497230904862171369974466400767175784681299142670706023468915238955836087425993929524341269289746060546848852729416925808186253355106621584826213979718185296723694190658548757311188764342751280681935289121682174507629679900374674992438818324999211250580434317716
-fjzmb1D+YBU5Wn1GlwhxjiJS07k+fXxjeNRbOv5SjktzxOXmautO8xZ5ACOlYrTt5G2gzW2PU6sYNfByQ0xoUSyutOuQlD2r+8MnDrxCo6RxT3P0dUSX7q0IVj+oLK4GPbscnKLfe6KqUcYLMgKnDYnc+ztFD+csL6BQnM9WMLk= 88647261832601702291191332432291274285041869480562430895152086741320122435409959711452438332192792226899741738806447713240934608106883094466050154088410020909933636902495700779087737304255058561688767369900548260278700135161077055869478387490726087630962098228537973426295306997128615315548440548541717688505
-YDg99aHkQSh9RjytWknbXzcgLD8MrWUEHF46yQLHYANKXaQYyf3yGM9TYPCDUqWbOapqQe+XfOCoACLyRg7vVDsnOPRDI9ZFUgCQBNG06ZOxzktEhnNJoRC99da8jyodFqqk2f9UD1lVa8tsQdatjUDocwgJaDAOpYEyGnUlbXo= 67567767932654827067250684965667741848878457020992905661955722020937161710030993261011062929936964216357930453809610708591260182295097124272956485574313839759737390934220465669626974544253750900911093325004172643146669082793591441922014060981070503803266774197958528843445580649512373693546027107823355522426
-ANdsfO+cNtWsbT/QJHGkYAL2WCHWVPrX6oEz78pO8lUwiigVEow5roLI5Tm7GP7XffjF95z5WDxzpoam+Bfp4za75D6ZEHQmuFnpWQAmNLUHdKUE6UcsWN1rbV1uY+x+Nr5Vni/M7PfQi1yRTTJTYav40tFPb9rY48FsUotivoxd 151275723772668372472508916060743043308364940375633847663054782759325087560768667906829087958412643723335046123025802453213225972572697773468957759328009026531148112732519692142632237595562259864125679649273054426879080697360204352423668940795473103047320116317252295126635024518179060076282921965794883439709
-D2Z8YA0G/vzEVVQ6itLPUC92r9n9FKRpf6lDPWIgpZOOfIkukPp7zzTlo9Ej5IsBrZBbtGz/eYmlHeZ8Y9pQj8HFW24HeKYqjmR0ujbNxI0QgoE+VUwPVg0HhoQsOGmq47zpXpkDwpOAZbMh/t1Bafq6r2zM0qmiwOacJ8KFUas= 10814483230552506566705634583020057064935800294861277580077052473134972003523900930560478187758928889017740705417070994563709463926267126567504805864719383185267204810142444719634360655595490833208838383875687102074846353850310954150927702228780599083427768247170427544730791038729428517279760042619935478187
-XoZpSMHqlOyPYJS7dWSRNDJHCkjbo6+DECzu0FpB9O8bftcxan/06Twbo5d1lEqPlLx3w0XeWtrmCSCaeVcXVtlY3QuPjdKPv8LBnnhslPOVcbGyflaTPXU+ITWE6rwnIF+yWQl3NIwCV4EBtCT+3U//Dt/Ebif9gzfKpKltD6U= 66377743237695515693282032069691369056215169443985727092982918806809030742478033317158686828712146024066618073633406428345129492010236994055590530566431286733776441810601990431112187030942086686719669823512292071202675269428014136307286941704297995292544712278047959299939833088742083527714893795660235870117
-QUbbkyJQ0Nru9c/nPbphM6VxHp5DWlai6407KIDbTGvUReVYI7de1gO/BFphL9GA7gDareYoMuej3/SVp8lEujXywtXzjiI+j2TzR3YYiMBAMhsJO1wU9pxy69Cj5xeFFlrOycjE9sPS9nrqnEEEFNPiK/GDDTHj0KuNbWSCLrI= 45838919357034925862751142472777409057791233610959872523563363744902783251621354580995921495295078179996083468819097423327554678806691589090814275138081407920379810144694354354954459732280968086760894209634364189264517251735804373673532012530665557440070501687207620525228416650281363557992436992284712644274
-F+uI7ARCeAlnPLO1YR7RJj8LyhtE/EJMcY45lsNMff0YeENe8KOITZVxNA55FcxDYpg9sKi1UV3/ASqkqpH8MOxWpBdT2UwSX3oBkp6ETfJKqiag0C4MS8cQVsfcKF39BJ6KUE7X6KUEj11j2YIIRREmLPyZ0LatG7dN7Rmv2iI= 16797235966984072293396362937533957334369977688369659112225970370748312376722010874726300554329794854683394163379447263409228872034356195791733533528404245739693397078461712458035888813157166614479153484688995068722288153129390850561042173295997770817893349738328312152341860704179681230323810266038959856162
-ALkEoXznA7BJlBIfA3Avl9kygQcxexEMApwduVRiXeYG0uEXMQU4rgMJBlPqs+ly8LTIcLFaLnJAG2KFQn2GXz2TNa7w4xkegkrslIJEtBWX/lc7VzRtcLbhaXEs0Ci1ValnW9Up7dYOj3Qw9eNo/9M9b1fD9TI+0QXFtp1ge728 129924120553920201168632484268654219915712271781591182777925696006023100660478316445751842982460082888615429513674356810187315558964251402722465707617058251479494744427428152566665405423424700027316505872162698141109433045594670140335040479559124757490095995568556894332243767736124299898808796118800328801724
-Ki3FNTEE870E9GaNtbT418CLSmf++s6Di3hzAy8NgiDOFo+uuicJa54V3JNRxOBc99sl/chfZuaBQt14BFOQ0i+9rm2KD82okNABd+SNfXOb0Ow2taZX8CpkVJYDyphFPyHbPIKmzwMShNx9X2z9w4++tJgzBzGcFTPv1nhAlxc= 29618953883711174042338818332957726953262658484143534778541769862244883781157097499904047532839425875312731531093860721544220959674634750905085721866390609141599426547378130082409488797303960018348798930232014390380383063108812922828160584483043190739354817699497573863286563890071313017508437166939160221463
-AJq8tcSnAq6M32ViO4hVGiHY7Tb08cLVyxpl/v0Y5adYblvjrbsFcCmsNDi5PnBOBl5awR7KZdQ1xgq6jIs+SQbccEMvJvGUZW5MgcHrXBj9XVd+8oB0z0eahqXpgYBqLDeHLU6238xR3dJYFf+Xrcrzjg8swx66OmQKkAQVJtdq 108660120968150664552423780971948386965268856900017812123107864829782135741514930439461240950044759098603910762272795612101834680870627850178371693837566833495418727543557712057554231215186486008080050486837716071537742708913279026303380104388546316647349432118287628353129105425052237438199445863950767806314
-AI3mfrgcRwtE3mA12gSoQV1xyIGy/YA4pCCvja4mTjvzQOAfiZL0efadxZH5awohCC1SpZDCFsE9yYp4LugHKu/A8zMcp4k5ena8sTPDkSod1yucjybgmVJ5h17Pru28AzHQ/YUmCnojQv55aV2+AUhxzIfojY+NT2PKRqr+vuf+ 99645829268436288676280252226747461064597487404802430565833102291706103139410465131373666856042539909746769688396958963177805479987372681967013633920910376342526433530508868114301205524789149997372160919406352823342811006288909548557622230243808373083272214426118230701324879006645047374853535922112549545982
-TmXQ+D8XFKSclXwnTIH8d+sb1IV0gfm7GagJahaFL6A9rvYaZ0NTizkG5DQ0RmXyo0wPmLork/296whsdNdUxVAwnGFlWWvMV0ftR1fOvN9KoT0WtVZ4Rmu6Fuc7q1PskAZzIp7MkOAxILO4iX5dNuVC+GLZYIbpTel3Ga8fXuU= 55052751096768041533898435453266875315629605001878362193939750978427494147944918632414581744895066623527980497732722163665712245580312596487741856071020477624754815927936394948233480228964159047139170955663289543349257377302556035170334384320502468579367401821986660515827461352578142560630318492817238744805
-EF6KIBWQiQoHOnBdJs1p+WIcAv9ILt0cnQVo+o/2niOtI0C+eFBSiNgeddhotkQFgHvGUjq8BPYgtLC8A5IFKGzXu4SYj5ziagka0hqfhVs9zVHKNx2NUoMhPDG5R7+giwEGGPOayGHVNbsBf1FBYG91+mwy8hnNbhcHSnvLGk4= 11494909948912248031301686864833544028186348338729984264372557659364976118965740281229664413031002362633393381744365783802034700038490736736266032000546393704814403638058993380993275865674190555703046732456017652317200288968188655019374159412919163798248766655991273308390043613040731449231289437754791500366
-AL7wCh8tkFe07qChFAzRkrnNehvda/Teroj65X1Bmcr14+/zeJlZDObYRYBOm8YYSYNgJekcL3o9lLFE34sCMbSJgm4dGwpEVexiLVi+zc8ndnqBDSAnRqtC+3jbInm/v8l6cUvuzrUNtzXIQ/H4FrmPMiVy0EMerkMtkfw5GBsd 134080980697158076909534078193319899756347955848461100874771253577754225619652121295523443912922220564492468474647193062555347746840044705102003079330399499915801536721237211615317000955332058281901995149084303143543150689010335818219129745452688372571010816270728441637278434982752674030696337642893239393053
-APunLhlblRi3bbRBwSV8dsw8h5SvT8ncAmXPnca+e1dLzrQZzL7P2OhFope0mW1MCDl2kJPiGTdK3SiYJVsAFeR3r/0z96g3oq+8uS66T6VaJym0QToMsqQF4/fUMaTo9HsukyPyOgjVIU+6TiFd3SxQKIu1/GpQWVQIP2pkHFKM 176716779397275986910036615967409090183531310366246043951791503601618945774743601662530806467045971394247287367421508126613573039423674729894091424105133906122821596079925540513892022311039293333114333317886304014722168786051080135090242879622144693440448171583324154550086458411590240882982297314605229953676
-MM6B5AgdJKe5OLlPzcXwi9WhqQjx5KsnBYxxa3kWdGNTdk/IN6TVd4Ptn8lWkLm78mw3DXP4Ol1sQbIfkHRoKFUN6TaWg5aDCJBDXyHSTZI2FDc1di0Te1SwziYn0sIOe+R+rfuLuHlcT1xaZBgL6+dDLAZaZza36UEjn5i/pTs= 34273208848307582992498656582721015257885595139328466874135636009184357438445251703533153492315835793684794951576799764181908090765379592683793969576893243386892292517067596035059342970830813419330530731370385186653239446376170533147020072285887964430731437765184844167400169982662183791828762458682426369339
-AJK1dx77ZA4F0sYCgRL1LKSTvjGTKBHd4QBeVnE6FKJxIow82puqtsVZ7TBxbECex+LkLQPrEbuQaVr3giUDjg0aJCE0D9ZVXCUS06qulqcCCdWgGFHXDOQzTWDn6TlJCGxtTEMbMxSlUq1q0iKZ19kwMHiT3GydBn8/G7tIYd23 103022457217861194294329435482792508957642944252832971366936865663608381648431732294396977429863681671686490913575377744795372643599438468695483808375208871881849232129651519218503507811863794426234594709451104684234156597418383183271923307418704786548452806494411689822939919114966188329657999811363991575991
-fPZNsqUYBbVGA2FAiglnByxGJOZkVSpj8Y4QNW5wq6o/1e/PRwp0TLYJXIoCJRs82pAj0QDpQbHl5lCZmNxEIQP8o8xI//HCPxPIdgBJmSfm3VGetrOpqEGU0KJJqK4IsjoVpAfPFMUMOpGNz9CSvCHGk1AKrtYvrTJEKmETuig= 87751387019308584846595931543798879607048239290774788042055795835726250309378365187899578817976976035304304847968410200168743967600896348021636654074952051821111673620467434295067182213181329543946368332581250062140819766061014427755090798550122401239987766844126425179573454145697756278292448630509686471208
-EmT6DUd0bxcdprYhAnycQaxm89kltJOlIOGFFRmEK90H3RhzBGr5PRVTJVqemFVpVliO1gy1nPHgqDGVNIE1GXhrhyFJU6m+HJeNcduippRe38xPCiuraRkXao79X7WAiVYUq6RIH+UIRnfTvHBgzTwjrOvKJ5853hYmGaanjh0= 12917015385266582065020051081997430892582163827812227349569911846746592973268746845211126663077128575098045461893559476227689488349263954564361736197688317585888118974603264677576027836032271531903881104937422976121352854003385726888601980526287956222142458858211589791399646989299770657341412683499692330525
-APtOYyWzdY1A/YU0SGrtjPdMZA5E50Y3hJVXppwuuSk04TjXzcbu2Sqp7sMnKYbToRW4nB5p2UnaLPhTRy0yszOd1auLngW+0ttCybD6nTcVoP65gYOwXGfSEQysqKLb1OfV8kYq5Ba92Efn+CcWWWuS0wEr97W5M/Hccx9bGu0r 176473215292413922394356058789571494026727424839036665031567966488209592078148711908841964690807374236235612412767651029865069639786447019874344449598703213025389428836803984245755885691094364960118900160737925054803955567361126391353868279642836569627177281508980029006921064654964339077608785831304875404587
-Vs6bjpYfFA1R/QTeCfhMuZLZ+Zxo6wxq1jFZpi5SBR1LaUwAtOAj38OJC8L7zmxSOj/RGEmJHkulI3E1MH7P7xlWbY468/azfot5fX9BgHrtptV6Q0dkBUg7H91+tcxdbm4/V0HGQGa2rZp+XK1rO+U/d0ki6iNbsCsCR+OeyvI= 60957991334776853645581868230398759578123373154273044785333939425321390401088800849629483265841435899835570419798325123273632247193463641611211088549152950252041797959644227170492417662363676228611376046334386877555777556575818860902071813120592757466883038430756577949025778080997296219236534786815367760626
-GiauT9A+wmwJsFbS2OPIM6ultIbU+kT2NgACn1jFAy+vNBahdfHMCH0jJdCs5TbmKTCeiEf3ITc5TV1OSvIejJ0GRkTf80nY47TAhiP1aehZvMAv59NQHHTDUE1U4TPVYKIyFpm1V1A+JBHKJzuGrB4lvqB2ed7k4m/ZD5lFLMM= 18363925023885496669420377869542744504974590667921570026763131637088916425434675950812384919000566852243714758512996458727914094904422651029609645299422563453163291342992902510788457007623888307499601267675322986672697397389663297565071582648674012080122614260400848960757021864980761735684874056409664531651
-AL/9KOZLtZu4+ZQYQsmOgbST8F4RV4N/Z+l8qsbCFlHdXHqTTkcN0chsccE/3KkVTZsAnAyJqogbAvB/RZqttaK5a8iKlOEoerUS92FVQw/42WhsVaFggR9cHVuvCD6QqclZjSBQKQzUMy0YWPWlycAZDIv96tooA+V+Fk0jbcFs 134819194171226950171930028888667967094069342154233489571728632904658607624703819928943642011918061760802468868660586005724399808048609316802502143143910585363214684061242274402109137825176291816945489430125510625857564490981683683589784133305376252294774711594646923226452625156299996630452243345104727556460
-AK5x2N/4+PKlsW/fNrw76CnE+nS76Rd7Ugo3IKhMTB/IuCc5xG4MQHo5MlWE0oVkZ+Gs4CxUpvD/WCCjHHFlSxKG4mC6ehz3NVLglBt+f1RWfPkF28JPd0UaIOG3um8kG4J3JDN48PXOPP86A0H8ZYbE5+ImmXsGAcwvScUQRInU 122499245103202714319465533564374494931278163571999934877854825659720649344163774228004853964635693562785966889622928722984134944784141208867445419597834322541679973956606275877526560988151196822256754309120410807075405427166696093800381410682490767468563176131997424692783482903880902119461752084196789357012
-ALZ12i0hqFhwRAikcoahYzH/BUolhgZ9Jz6adLvvTO4wk6LLOpNC/zCz+LjM7HazZomT1SqeYJ2X+WeGFLADHuWo+Gp/I3S0UEneYHKJxoU7OoOtE0mB0BCncLckHao/LmbpnQpS+Lx5bRsr0yE6oWNea6gbyRm/R0to74MI3/KK 128128022342420083856194424802390993133863171077961467523372211039771843125192435716337829530528063182315478279257832480290950255315151577221042903861075751839976362752440630888566422581799720709574650482021111126414843635330535518992034746102956214991673417580508389225948159518319625680855827280146399752842
-APXxvLifWgehdwdTRAJP5KrchRzgbUsyMWKcPGm2ZkwGDJjoTl2LIOOGVFiL4CyPBxahkEHf0nMxBN5oNGX/Y4W4PuOAC8gMgHzdLkPWkpnTcyoe5DD+fQsqNuKVw9nvyB15fx8k0d6b056nfFjnnRqgybby7MSllAWSKRYRdxVm 172707950911363219032118650562553641123743396229371815589867086054370029540557395298194067635069298952836929253340374819975848769009260895874615676938511747311585257140973518651959463416682165208985512233703837931718385346209362040743041262031997793519095342415901373534535662377972036003546589624834285049190
-O+9ohtZ9SzGLJoZM8IRQAjhc/GPt2X5G+M22ZidYjx9WgOTrZDXorSyxLuHxay6djsJSgjxYMj8MuanYSn/DzPWBB1Gn4cDmIsfeYuzO+vUJ4l6d0nIvBg9Iqs61/PGFd46YxhnDiVQ9HEznyTjzESnNqc0+/OkQVJcwNHAcZBg= 42087920806448980363073662127262313840530298932643042322138035915324224188032438119079107631420338701086802583985117830416851550991102672642532160807467909040086448764318690465254898516502941122327185894900817634110254371864896139724173087625913998657136384357741816102965779105122269429701537815263708996632
-VJOZmvqrqsIUTQSSJpZPhbQIYN2tsfBhAciWnfAYpwjK9/ts7OP4Qgdp6T/V2EsSRPnfZ0VKdLg1CnEWDhfcODo+/BZcUrJ0AviFAEtdeUhoMSWXtjel9Ln2guHY4s33z2cN70+e8gfjes65lCzrxUIXEF4nKxzKBnScoooQP5k= 59391682001673484862915842850714742391303140646889359425353339320546979084250010101273851580028171449840778038774656177449549941659895629203970455580974953864068394275066532699748911169800076515776388213090834432354601344176559839798153004796057709798368011673585434643656820656931921831615507416411999846297
-FRyJCOgPziO6RDHX1JgYGZRcSAuoQFIZM4niD/B0twK3l+TRpmVigKZAJnZZFtmX+0JQkDwQn3lcBGQIL6mgy+j0hD58U2/Wd6xebuHSzf4OHVGo1cYoqZLplszA+hVCoDVTHi2YAZ+GtfQEggumcNVxqfEZd6D9Nu//hm0t21M= 14824975573460749317081504809641216868382341402512168178334301409725840669112911061147252565570697788806398498723577368905065980113760265945344671897779830912242224090954834750057278285419880820811348943398148063418809729356397202526234113316098584002071850758705282845646489058224513019380757604894853946195
-dUk5LyS7mduFJlvh5o8R73kJIeeTh0Zli/y3XjtIXfCaNRf+wDlD/pX91JEwsQ5Mvj8yq/Uq13QyWhoNwsPpXVcJtJ+02wtIn5darsBDfzcD/LbWhl7zTRUeMjZ72gAWi1djx94SWjrZJS2oWZU92Og1yOyKRG+ua0AhHfYYh6g= 82361050315899968537319599868832189063658136463903643442673674137187842597528653416212822014359684261704550279153006971937114135373937934986951573613797195556144113400128502946618028800530164890707031379614952207482505803377774320259789692177752930767589642007257364960987343146063216186985472686575891023784
-AI6rejwEznR35rIPuIz0CP2aWyhRUR3unJ90YfxyuVYxrqOJQGSDTSf6SGDDw5MqpZXa9pWuwpyrb6smOq4ZtC3Er7lipJfXDjhy+0k1qcfMjmqbATUscwXGpgW+MO71cttccEz6vhbjndi8gvG5M/vfL2l1jA8nXuBd4e254dbz 100186164434910864539376019601151338080943067893748898987236087770762310617199833479771711726248130012472861788210345311298499515751355424063761182369333224929721733015910055321263016834247318907562652286587380604998130368845939290804442878127169587599285040969551065995197981341260363722618429042861484922611
-AJ5vLZX0fSs8dUSBqd5hki48T9cYuR0atxR+qv7cRu9nD1vP8uNVR8dLitg3XH0RARt3ZmOgi/AuggZt6tTxuIBg+9JhBY9WW+BLL5CnYWHC3AKMi7MQBWciLtmBpyF152bDaEcV1PXxtml2KxX0Ba0C+hGVDmJSdi8Kjd4AkfU6 111256341508463539324514225759801553679558662737345522765042612717818066374840372549356543720386819501973783940451033901079765311790026584654529398345993992144903839534037331533660672892487693477412528974248713261092693018326068480417183236210881306241164169849090833681510163753605662526243408192127670285626
-ZhXtSzn1GiFfHHnSKUYZiTcEWqlI8owyCKFjCQ+VEvkdk50m8uN7RCQ6ZhI545tN7Uy0WdLstJhgJETBYLHHIoWsJn07mgPxuyO0XsqNroICMQEOO/YWQFk1c0VqZifcohQAwJj7fONzM7hTcA22/7gVigJ3iLq178jZOJsEPQs= 71686982768953132894579286530164112027530221141251507987469672039995314435159469907420372652392376452531392493658576814100773556880394271726970628960571077839124343525055625420896355363707908511865700866168843075071778015504724409171911254647909938237551680861008772396291072284353858575645679153885560978699
-Vc8Cw5m5yI+bJ5sUJYm/F2wyZ5x3D4ydyL0uU/3eVF2ZJu55OOlC9pUyyv7WGExClHvWpR9mhMnsqCLyseLfM2Q/YXJ7cjGPKp2xd+fvwHa4hRi1FdOxs96rJnb+HUt9hTwQByXgzpnUfs7AqrqaNf4WSlBNMu0IOOqDdB4iVHU= 60256873326783629723455608618518793848697944184579877638436234491615392142659293975260290798403892159720925893207048153291000664050780029732557737984085196691225472664027706406879051455184548871511448456651238810812870905640934953489289909009741493031472382758586341375517766302753448531830002512912250459253
-QmeUn6cbpE8YrDfMETz/+KVFaK+d4NHHzcdj/MnjcmqQSLpP/XwCW/aeudlN3SfKd6rNo1XZefunZO/ek+PHEIy899WzjiJaajhf2X05fl9WuPEaMES3Yrr+ClogFNQ+9jL8+7L+J8lDuqQzvchT0U0RPay5HSNZw+ZouVCiQ18= 46630904037845609335515965570673490721137364238213103678233212262384415738654627185220187275286458759154841820256007930773120637898228224906635911124921895934056288121005350040349882413280772888907627838315559544636626856478316691755270725623680935763476199888127096014398699432042227882284223578563208692575
-ALUBYIShA4w5kRUa6iNF8S33DqaprdOWjVBnO+j9CCGtUh+NNwfpKR8AKf536MtuFFtwaQvRIlkLpaTYXuRxzyU/YG2+UfRQF3pEmXQhcMxJqFzqZ5nWCIWlJ/KtYS4lcC/B7hD2UGAktnIdjVUTSxX60VzA+zxeunV2iBZXQlEs 127106299687401374061881872616647348819431126560557369258073443762502337592227172639640997680536372567116568811258505773087926491911004324918919511363985868314578663758269650473780772688462266790559846182685481907703974916356209771821075179827563487466641669110315430790405454641953880582274165368514679034156
-ANyAdMnVCVjmUZGiVdyvGE5mUQpKoJOJINqMAfzVUGvvxXFmGdoAx+xsDRNAP4KoijpXk6E3yPBPBZEWyhiHnyjEkktK/gX6gnb745afS0QIlsjhKCk/W/BHXkzC862Llnc1ZGAIsERnGceEoZHdICfDUh/7nMFp5WuSMzPB7nEO 154841617115465511611746667401422322067517612306328612547616471923266281876818466022676728696273611923942543658633762267658490816264271663863494188027433799849037906883352478212451733963905925106470599843045599411842850386623187980045961158399934160107237440980574028985561404965317132715808604373199725949198
-AJ4nfhDe+HojR2YrprDHW9FVUxsZvoIekwlNL2iKFRFcTB9IcEdh6QnGcaRinev7yEYUsL6saSxUj39uWlqo8udJFdszuuQUmnloIi34L5uj0m1OpLy2dawpFQr8pqyA7go4ugMMj6XCtiVnISUcK8wjHgY3Jed/EKK8k5ce0Jxt 111059703393618496515021583605572584329116596402705082562306930876194742195701060137568030171429700588269665205795898835699633817098262654446852249498668467827435829513531633390969638488553144849154126899372953755511962841193763362947708260103832329116485114451074371844037650417731807385491783373627950406765
-AL+heSTflb2MkRYFTKghfzqlVQ1oE5vcx0eCIsy9NJ2NGFXCRRvoGDVoB8UEsUWIRnaA+MIpwDKGpbOS8kRQrvBvPe/xM/t3jrGkaS6pN064+bCBx8Y/Jq31ZXNG8oUol+y1Eo6fkUKNl4EOetmZWK8VmhVwol5YngDffj4Q8ned 134567692290185631768518572983694048149859804864902017394351513816079806629664302312927579302025923096596995134868068794900003728293470554490807959649153000914807604036531509869958441069678002226922395630284261949256022972967357884468325217602330254290548618134453007903724438628204981673400911693835033278365
-AI272d2sbYIi637kHZC+6lievgcDvT5VKaCnus3fHwm2vfao7oYu31P4st9DlqPWJ635X6QtLkU5HgvVSy66MDj2fcOfwVL09ffkZYnoGNdhMADVgOq62Ro5cCpOdw8Ko0cCyVpVIaSysPuqY7kiClf9GTdyZz/uYHDgwWeNrc4R 99528854246023003959943182132914587584844397870416002887630245681136432049666385367430032197518895755482367603560037194955739661569172773017279832774100155646116233705958563163070414171045438199561777058338188494271322834524386565519620661180246416329082614115142485663975718653564590519408413408765689056785
-AN9S8vPzo4SkyKsk07nfyD0um1riJzRqqWF9KCL+kWMHajurgPACikYzu61tL7l1mNEaIU16Ndz541o+y76DgsTLYszu4KXUOEt1Gu3eHy05Fq18zCDlNesSVjkZjPmuJr2ku+p0cP0TLLMn7/KuVOm4GlEVc6OvBNZuEzRriSYZ 156823459768092337875922818543729136404805918580285507923139232733465414368775678369646914249412830351437211620056021568154043505276475345347569200977945836210758870414054407438380975491139001471954448623922841964684437333066353208837709613982022690623722155151315252634380695513434502419141555410441456920089
-AMc5H8kywLgiT4zz5xgoI90jejsHorbqUGtBeX9wke7zyvEKyWxRKScZwzRbinjDZzN48eg/30qTZOV2Rw97JFg+EA63iZ0vqfF8jErIt3hODniKX8zayCuNmiSb5kiZL0UDU1SNh8ER4m6o5vshBKkmqs0PeozfCGQtR3bZXlx4 139899247405256530335276706333424670310599977544642091674186635734421385499036688803073040921114325725234673132788498809189814711681909865484671959982394306416477300458309408833281654917008031099378445580498219376391819745965887864647387211647794422908411100892195529730435423964537342228510107659017578765432
-AKv+3H/TruTX3wdMWnLzD05em8u/QMl6lCHT4VkK+uZwBXoLeji54Tcs/hZIhj0Bdj0URrRt+7JdGSTy4Sr986AtVFxBJZA3lT+JT4JSrq3oY1Tv+tX/yg8ZodQmbpQyyfaFg3BgeHNmsUoCrdqhj4IwBqEXoOBRIXnzaTuqqSEw 120779384043726135670909127168686589868907326577918074234323699599475436892003731971700278391108690400460261929381703781833059801757700386671579819341589048987186473249926590758009001670959004477454905417357202448886738669226760846888369186457452643053236389556969071303251275912453385963613554945645058007344
-ANXIB+HxOyJd3YYsscMpqZpi/eYjZi5q6A0MohU4BiWEJK/E4uIObLJDH5yd4ng+hn7UMhc+R/AxG88hIdOc5NyG/QyFs95ZLUC26F9rkRifu2CBkgqR5EQi2cgwC8jGxQOkC62YND6cAn/ILsKTYaH0iavtO9Tz04vQp9Ypc82H 150122383481070201614242107655752525590609186454390549085509458064289390813495886095936526832230958746095739308601699615024239939948911472291507190108935262129646691795733786714291498653838550751365834947465294261687773081563139416397262227609481906371677917295227469553787085145970923979142676551778927103367
-ZQLFoW+dJ7vrHdMlcLRGKY6T6PZKnE2L3NjXymS/55my2CDBLdDf3oXwLlRjVt9KnEiXyQzLhyY2PrFA4k3N/3P5lVDLHero5c36TMshbHgbIKRGN2CGWPEFeQ4j040IwVbQCPJeuF3jL5ikCxWZFXfeEnTL6TqumLfD9yLQfKA= 70932215714423143395949105745758445705072524008235214324766464113352968998429901322485575506330607802260244612268338586532462314021433435523464635419846126736185176246740838082062856583684393425704173881940108783636582561707441482446854068022535943408999200681879161519209676205165680598258447492092651404448
-LzzvPw0FdtM2G/RRiqoajJiIH+Lw3jpL4H+08yOpp1bNITR2Aq0beu2nP0H4o2Z1/FNr2hzuGakkAhVbmmRXc8keoOkeaAQAP/8OYxHpjrqou3WPWaKx+vUCTSqVYYf8gnVKpAAC2cD+3lW+/ZJ538o+c0ovbUKNu1u1j1OBtA0= 33171669664542509840621265032202455391098253465550501094201777336478104142847268103467889435377685359857979277521589539506627375165485879405453566052091202280471235979376217319335800766353336252760793484157724210008639813552207624049019149744883918494762511376489708611103181576211531366514802868659603747853
-APrGj1lIIlxA57DNh+bTEAFbJK2Y2P3MxLShb4fPx2aY6j88k3umoe07ISQLf9PzNPeml4/0I3w0KNd2x4s9KHbj7NsIT64lhO6eQSEteqZXZGXUYUyNzhrTbAjt+Q9LVKItQhsTkTW2HTQ5RQZfGrkL118b/I18J4P+T8CGZdDz 176100632478477421621142147788721746818712752858710594712903769452749028606541677227413333567013253138397373757811889654342173021761934591400685421771460440213093509170325205622261487145789848227404883040799927313402244625239515162996390018403365063394514244196976794479529075569412676472840544017222373593331
-Fvcl/LemWk29I5LCjU1QedTjGlkvFF/kZXNkRJv+vNZ7qgq6pX8WB9yVkk6AoclDYAhCRfKTKuEpR23iafVuHpprPfNXcqBH8n01kq3U27xqIy2hS+D6BRBK67PQaekq31EB0aOcEb/DuNaXakS9+mtTMx6BKt+WoEY+NkzHK6c= 16126868736093163702771491576570380743773057522016869811780571865928979861357811080042796140032050364543242385458140594532945509386155523162799601656485075247603490060565663264947465987286983338572455184901756399862440455644131755848583379822279676555143231305246033911608913609591095831135803702269767527335
-AKW8tvaB8YZ7J5W2lmquBniJzUhRfqFdPZPqvBoMzR4cRh1CMNdSFsYsnsaF3KolNzogdsxFpHAaEMG6zSvpNJAoi4nixCqb5SETXrSLASXvNjI9MvCoE2JCRq7kMbjPL7cem+mBPWZITGUI6KVlJPLxQngHYSFxukqlx7jznwJH 116384596458828069344020651216200368975621068920641012055593076864629080375946542748377736186556382088448816531408136815533164209947323588157210859294774679831647934533061547276394884474877353537242203645373945111105805934070657589374883764420038511061919092743520704686962593876316976299391579463759429567047
-D5N2P4FrqDf7/2Z2BJsqah4SjUtolic/yNqdNzvNEogDKZKAJyGq4zhnHvkYXkEm2ueU/FDPJRqisszG0oULdU6c7p8acirEwsGLVh4RamnFRgmQSK1vbiYB3bR+P+iFX/bZ+TWjN2Y3YMa5UB//I6Zb5kEIjmTpjY2LEPI1e6s= 10937855369372570149476727082965401421189236366492771695094788039313362971972373068736123833330006002198346944149230147444718818161877123407713821100752433128205189334393732633989950841577315682292180735057952587083688644195300641998709155269462601925653013312848413290208844194513502358901613104779186502571
-V/A1ktS0xrcwlI8xrYqvlLCFYrdVp8tEzZaZ9iNNpPH/pzVsA0WbnnUeHbdilkje+4OdoX9C4U2xaOuWOfvqLR0c7GeCkSffCqyf4ZsBmjy/BQL6rCpxMF0gIHXO5O8aJ1h17hy9LTuNzWm4zVh4pNFuHC9L6nAcf92udMiIQzk= 61752386563628388546439207444896778638632243226541303179646524864765343154194512297447627825411023405896612559648434895675553567405277169056807223959390559391191382555701580549902639604424290133917402316755076644943742815711432111554988540913643347167948778404861099845961151998728662878854088239266688156473
-APoPgEKA0/r1FYmt/Iso6ChYK6dDU62Y+vH5h/LVE00biBYG1f7aL3GdllUTN+XQSHpqlDw8CD+9xojwZIMfgpgjOwLbbe7Aso460zLrg3R8aHBpbVt8iZUgjACwPYr5UyKbFzIAWaXcnYYQ+tCO9aDIuOz+/7eIF62C81zXFJVZ 175598490446477604563905754135475294999639698464908622773037381109011373179895295130424828038708319325919451724985361900259676699137657615076219968061941008972496322083528922054390781811699677037439989404270415929836486610353098273115864435328533577114470407444852521009919911888840405368858409835197558461785
-cL54ymLJhRx3U20Y9aUTIsXy9Ags+XHy4qk3F7uJyO46eiXSL7VrrR9vTQXAbETbu1YiVWfslsPht810eUDUVaVir6yLnXkywn46Ci42FEvVoTEFjO22uYcCh8nqB8H589w/+lVSlNrcILugwfdfCvK1iZzVimOO6l3qzfXToOU= 79171550718114578361958369278761819285111811576818442980166457146638966315793211967882077899426611721874954146020093740153495693185472340728106727284441726113022873005252623222594060645383105757498856463065370975867121188445567981809371870213273555432308279508351518168027875538720367440153667708369625129189
-QdQN4qW2QZq8/fmSaqlRiPSoDbhmF0oYjaY29HcKYGHdlOH0AMJb+RUIq1aszvVtjh7AYay2TNhaZMWQ6Qi3c42SNk3A1MVknT6zqiRCGjNFfxf/matbRLbTFQF832MAId708vrFLF/o2HpekMkc5hcHB6bkUUhEI1NLcMXwGck= 46226230186280253581676626651942823886592433541360244612432763620730826574920825070086312767146345247802570752482654580909236388357139147786783758670999083804670979821212991224400629053427330483809790366665043598754931511997925850227997764381723288657884346974360232490075739442406431704368767588177525348809
-cxHvCK/dyVDvaqCCQyLeaiBGA36mV5el+1lc2eUTkHGUzX5gU0QQCEp+iSXNJhIOON8VFpKOFsziuV0Z+3cegWRw/VnxnjXcBh6IDKdupzOPB+Yl8MA1ti/GrQjLC6ikcNYNjQT0ZThL7KTqEvvZJH68WYmD0IuK26swjNGIGaI= 80804939616399473443737611589382762718815989847332356984276911837267997590368701684135326680567847542004499684038240485603420973682522792156533112356849436451918522884749244246467852622918805139990256619014116276456718693703261686778030658826952213058982142604346352178078750879100976710761147710018148637090
-AIQ3OIZevkYoRGBmsFaXJobSfLeInuKKReVYNjP5VEPoMq0mXTltY6l09/rQ3d1JjsMD1PfA7emhxex+H9t3leBIfCi6Ux34GQEjXWpQc4awuiy9tbR077HaJyecvb8Qy1FTnOHoH5C043QJzrKYT/sFXjgB60piI8Y0R/hwxO4r 92845026347218330987427785323244729176754623818531419911990153715676845614711324345879159989637824921793015074978358052562420379797956750450245721653716740651389924718711940869162230097839047895842495414221110468446944827052871968998907462191349838598297775847512250220907563815783358238473966349820476321323
-LoG6ib5lUh57rdmSkZSWzBoudytFohS4uoU/uly6OaQDOi34GeNVxu/yr6RszJyL9JWkGNgFaBIv/HirH5zA9VQAL/6kpL93a0/GQ/nuHkHy3GWZPF/2+yJ0PfazQ40fWhHZfRxBngWslbguFPjj1XaJ37YzpQAYb/+QcUai9ic= 32658152290878644668906121702816147999633088014476055330179597550087921141413344679134407016170035735846077181424615228657687216737432274043674411132745299610950657139041836412322040866250189120286839287690983293111362228893996267791120043532014262644480689231457941173330523718758287779526551822788227954215
-AKu2jgOQCCfYZ3CLkXEH44aO4TtwMPeK/eq4FtNj9HZ9FxT0LLNJh0ZXPOaPJjgznvIw5C7/hNm7rUs1JeV8I8dj3nbS3EVERQz1gc/ckYB3H1bViWREOD5+TScDusi86YO/z4ar3dauKkg5kT1kKDuU/OP5kNMWvtJjHc4Vd3L3 120581042599355202025471829872601846477331097842315143148145881424071317426176264583672725691485724160094190478865850305422057632110749683552966861219554215519032344086824849470294473808177223497912069335635933312949412445851201918768630656712413082629164792850095444166888072453190903931430551124946191872759
-ANLs7OsR7oBM5jSjVADrk+Mx9d0TeieTIkxwWiJ5STKNQmW2EzPOjgbfcLhbYEhzzDFJveXO2dzz6/c8V5oW2yqg7VMx88DzEbpQnQpk/rOQRw9jbI4fxXNJHkNZCeysEVvFfLJb4ecsGA0xJ3Aylny/jP10ahPv2z5K99edGZSU 148116916208650944522110872759145096907599612943009577897396622287067669897712748449324334650112672914917664881091633448764667172850435775162090891556266912697811031318228334453406561952979778127173704706529448647577013482442758465809198730066784986763500579667100246958959793527011919373534159474250508506260
-AL+Er3n1qj+SBsZVtOMJYg4m0CN+DE6gRnC1F7nPvd2XnBe+QE0+LKfcpUDHVNxoydW4BDzNVwnUNbyjXZ+iuddPtO9hchVEI36UiuL0ydeldFpOZ9mtHJaAF6abd0MlHw4vXRf8CbOvXb5N4s76ggijlZBjRtU563sSmBcyq6Zt 134488725667189507159811764480908602790838430340670328479145818969651133017546803581865897303917708192047926432630297993507146075655594931523561067937580218599890162311074002344315818494246433967228889645359283635389151927472221799543158424012020308449895562192866672439712148770104592027035768027605661099629
-AK/04XOBSjjPpuFXTDF82RNWnKqZz9mJQbS2B5bn0ehFnBa6j+B+MazX+AxXTL/d5+hPLT1uexcnSMl3DcGGwKipOXg7Dtuj3pfJXHTrCqXAUYrIXI+8vKVQO55yQPGfzIg9SVgetwW1sDk+a28ZhJ5a9OddqNoi5C+dLce7ZtNb 123560902006294001923570614486104726169564351074482936927091682096999779538353161007361361829586988452098646362280351148131540524964916445100589671458589346440250329883789099771417949746709217272531950438336245613419967556433467843237384555807236658182067742367748737224684334525934210197178231424396818830171
-PzOEGHlihiveoWFAALY+LOfkRJfm0NUF/uR6cSU/tbpGAq4onNpr+iZIzEP5o3JBLOtDC595/NBPI0fzaXl0vQvgJs6KG8iKANjsLKQjIpZBkoKhdbG9MzTVQuAeuDW0w3sn2iMZ/v2dgAzRwfqmQYXJr3I2BbcwWraIJuZXw5A= 44381416070253681813077725822442106641846565789204187691647505370231831464947935035197059366680327425453811558282831465960889061956588244308214943856009686127871667376028831540813257349779756631357122923723235595360268572998278795110672666089470210929411514949652537714634611421849780859192966935514197771152
-APnuduN01GS9dO2m2uCLs400AR2lX7elOnIPC5U6e17qbukxWYzNhilZlM4kdGXAIeYpzFdSIW/gxRMZe6TXq9krFWRaaPyT2QwRfGHYnazS9F1QNYmW1zXdt+qVp0JGxmh5PyDstbP8Z3x50/E8Mb0gLLPhNAvzY2Jnr9A8Q1Hy 175507868985304663005133968393406051624825489142498103948374797086106732382869120248515993626061853699363294022457032257026588816021007648668265488426495800459085474654859258116280251546902009156490112550154951965894022789029787886785376415437170872937201839249103828294508088966180386198213606090453461193202
-QHEhL4iVzNdUsfG0izTEepwTOvxka8t/9MwuF1Ey6kxsI+ry4g4sJPgR2xMnbtOmvQn2NitAkfvA8JPCiL7a8+gmf+DVRDjKDfpfrtgAVmo+3rH+uJYTrKhAp8R7ggU2xIrvbIrgeUj7ieThPI3Rtap+IdkPCL853JC/+oKtytM= 45252649968839515171157821292772647085425694172492111870169593872127007254353374581972876464918186509502070064028725519394859148593053614163356612260257013360168930649423732336969778875205250872728821432415158634190866775855521719727700464116412886964736859295086745723651735554245035077902615220578218265299
-APeaekK4mVhEShCfM0mkRebcg1Iq5CgrFIEGOoh1nHzgebr5A9Wrhm9yD1Vd3e+fFD9urDRB4y5MHPJHX1U2NFToC+H8nQkFXL8bfd/9Wl2c7y8m0Mxwi53pLIdzETLbbfeOOtJvuSYYT3n8+/PeMnJ46UD8OfqtnFuS0/bVpFLS 173873040145444066957050580959132871919216036714423404143335635770937773583761934638398867981658394368476005882852706046614562314432695052874974848076542261910660410561876043187368112065303981001507235893831108658530338308496461162623683138693880482650786841100027392293758260448606244283355655751440485602002
-FqC/wgZDPTUoObPFSH5w4QR79zj/O+ZiHGTEnsBMwNZD3Gl/ClRDIsFMDDupNLgwgXsqCQbpwSOHOtAvUuAFwRpzt5B7lwIgtP5ism/AZRno5p+9WVSmUAM3glHsNtvYydz2MkXtnXzSMIR1ZVoLrdwMnckE4pbMzggqz+JZqxw= 15889870005716350976759704672045310928616256175405784574141006779373730686049218680335525720670897894546334915362899913262232170795516176419192840427996647372619000239408311568577050460995518058850793096827271653902583271225799114408537346367483775593212272587811309978019791973449354003275559762102731778844
-AJXNbv2AMWadF5h99ZAUy5gLnVK/hMaakFo0ZedtPNRJobxPmwj+h52G+Czd0U48G0V0wpdeUJC9v/4BhjzhCvNhNsdAT1+vQXDuteYQ1aspsEKLQ6b+NknO88QSbRJw53+KeOY2xe7PKOa4V89XnFFBF7wljRnIYrM8vvcqVQDk 105194875227030598769888785590198577650278341586165110611689226597424766274486797264032300493674927704016605741286512271390703088626381669060095573361828932336327125438452066548897528158329044309005232090053420259033538936293519762277428283316506398965916381374819450858053512398634116052299066189424983605476
-AIDRnUpBHepjBqYAlU4MG/8JxzX1mPxVNHpWvnEVgvqTQx/bisFPpXrYs3jAKIR/lzevYwhH0K/8Vvw4NK9iTMFqgSnU44AZztKsoxUXsEsl1UU56UscY5C7ciKU6vjjWI7nm/uHNOXdE82TQXkk2WX8ferNqZU5DaLFCb+zxb7w 90459642084794142567976043425270153270545560059973413835786695756473295513758287577749768786155290305189883600338986370836806413936196854410098516254596146039255388020628703824195128439558127783534033672712705194483515442668075394018677699876614329419492391568463215822656901183478205197671375262145069825776
-AIdvVNzJqWPgAShvi3GhbhMQft+SLigKGrhoqas2Saz/bA9u9Td6fAxa2LjrAqshW6cnm2aalc3Yv6RW/Y8vg7Ho31NSaRjT4zMUenykcC0/Y88UNxREi85wdnHwGytms6Lq49H8/7EFGJIyL1PLRWPmZn6XFkegscI/HUq/hiKm 95105613103051650721863964216778532448106311156426028879315612217763044797186635476805213120469258258125661666950525364331551671653846368977016286153840829836509696804585927581668281228810410814602664419962214359687545209312836366693384158782798559255789953908588601637765910472073600954502095647132310971046
-DdchOPjXrI6lpV84IdKCisPmdqZan8AARXRLADEhixsfXCYuO+WhNatI/fM1vgv+/TxwwIQjIfG1vOZcB36JUfjHYdItYQ70vUXaVFdpqvoBGyfOTU50Ds/11iGPCF8mWiQwR30/XAXytqDZtaVJVWsgHD3RigBSnSHhnvZAWYg= 9719024770319024562623340689338530708271347986326272393419504304391837979619189392867902307307106771234732135400958362219711925045600118964223238147375808749507928768896918369395426933218443166133187066167663170936604731896932630589251946733237697936733924510107175304126061649311812536190882160340308613512
-I+Z6rdTOt26/v3dtUP1plITb15fjb6aMDvqFS3AD1+nxBqnnk7ISGE9j6dv762EIWQpMzcCG5NCCq35KOHEwRXP28zup6olOMt3CBFgYVcBE2pWOpGiO19G/iFweYZXZPY5HgIkex7HBbb7l6HhomPc2sLL/IRhh2oogyHx2JMM= 25210054612455888156900839678249806510561198051210010474517915819801056434402727631042894881559517808906460418029149538469607239850657781476308872923928122553395468026744382526167194202058040459679991391557937527079948356545086684521068912222036707113005006607012596093923970784177288565193670152033981048003
-ALbBoyelCs4UkfnPjMT3S67ujhBHBEE0uxLx6kSGZq2IOMU/QdWYPFElRgYC/y++334FSEycjS6NAJJo2ITpZCO5AjNJ93J3WYgbDLiwu1VzKHX6ItfFNEk45km+QTi07+pDKcKNd1k0mxqpLd/PuZd5hRpPDDoKBb6i+mrCb2yF 128335905497646745013379107761994003743181143126608677203818152878840562628631384684712779135591095534911406031545494164782375276574093777950840330452805743803067864740000758175436633463846967335728314347497013853264454015790847388463800323796888198433722196292529074568758149650782323407298620158495364705413
-ANwlxEkeqmqYTxw1ZwMi1v2wo4ntPaEYZYoTLTJQfa+kuIksnHW9va243HAiOixd+rviVdm1dEwzESBbX0wiJNtRBpP+bnRxy4xOBjNoOB0c/tfka5JVwu5eeskyHx4V3inLviUaj86Yck42n5NaJFMfBvhzVftZ/YF9WBITI8g6 154592850289860621115358362871905683265658659789986179554827712019629689749439795961607030363152337159590319622241556795951071651584979664762468782303706550885785493534656062553770262954861884613383561063525714923031691298088562054236178003658891902606245782350998076658704876516153027797371814038658244397114
diff --git a/askbot/deps/openid/test/oidutil.py b/askbot/deps/openid/test/oidutil.py
deleted file mode 100644
index ec84b1b6..00000000
--- a/askbot/deps/openid/test/oidutil.py
+++ /dev/null
@@ -1,176 +0,0 @@
-import unittest
-import codecs
-import string
-import random
-from askbot.deps.openid import oidutil
-
-def test_base64():
- allowed_s = string.ascii_letters + string.digits + '+/='
- allowed_d = {}
- for c in allowed_s:
- allowed_d[c] = None
- isAllowed = allowed_d.has_key
-
- def checkEncoded(s):
- for c in s:
- assert isAllowed(c), s
-
- cases = [
- '',
- 'x',
- '\x00',
- '\x01',
- '\x00' * 100,
- ''.join(map(chr, range(256))),
- ]
-
- for s in cases:
- b64 = oidutil.toBase64(s)
- checkEncoded(b64)
- s_prime = oidutil.fromBase64(b64)
- assert s_prime == s, (s, b64, s_prime)
-
- # Randomized test
- for _ in xrange(50):
- n = random.randrange(2048)
- s = ''.join(map(chr, map(lambda _: random.randrange(256), range(n))))
- b64 = oidutil.toBase64(s)
- checkEncoded(b64)
- s_prime = oidutil.fromBase64(b64)
- assert s_prime == s, (s, b64, s_prime)
-
-class AppendArgsTest(unittest.TestCase):
- def __init__(self, desc, args, expected):
- unittest.TestCase.__init__(self)
- self.desc = desc
- self.args = args
- self.expected = expected
-
- def runTest(self):
- result = oidutil.appendArgs(*self.args)
- self.assertEqual(self.expected, result, self.args)
-
- def shortDescription(self):
- return self.desc
-
-
-
-class TestSymbol(unittest.TestCase):
- def testCopyHash(self):
- import copy
- s = oidutil.Symbol("Foo")
- d = {s: 1}
- d_prime = copy.deepcopy(d)
- self.failUnless(s in d_prime, "%r isn't in %r" % (s, d_prime))
-
- t = oidutil.Symbol("Bar")
- self.failIfEqual(hash(s), hash(t))
-
-
-def buildAppendTests():
- simple = 'http://www.example.com/'
- cases = [
- ('empty list',
- (simple, []),
- simple),
-
- ('empty dict',
- (simple, {}),
- simple),
-
- ('one list',
- (simple, [('a', 'b')]),
- simple + '?a=b'),
-
- ('one dict',
- (simple, {'a':'b'}),
- simple + '?a=b'),
-
- ('two list (same)',
- (simple, [('a', 'b'), ('a', 'c')]),
- simple + '?a=b&a=c'),
-
- ('two list',
- (simple, [('a', 'b'), ('b', 'c')]),
- simple + '?a=b&b=c'),
-
- ('two list (order)',
- (simple, [('b', 'c'), ('a', 'b')]),
- simple + '?b=c&a=b'),
-
- ('two dict (order)',
- (simple, {'b':'c', 'a':'b'}),
- simple + '?a=b&b=c'),
-
- ('escape',
- (simple, [('=', '=')]),
- simple + '?%3D=%3D'),
-
- ('escape (URL)',
- (simple, [('this_url', simple)]),
- simple + '?this_url=http%3A%2F%2Fwww.example.com%2F'),
-
- ('use dots',
- (simple, [('openid.stuff', 'bother')]),
- simple + '?openid.stuff=bother'),
-
- ('args exist (empty)',
- (simple + '?stuff=bother', []),
- simple + '?stuff=bother'),
-
- ('args exist',
- (simple + '?stuff=bother', [('ack', 'ack')]),
- simple + '?stuff=bother&ack=ack'),
-
- ('args exist',
- (simple + '?stuff=bother', [('ack', 'ack')]),
- simple + '?stuff=bother&ack=ack'),
-
- ('args exist (dict)',
- (simple + '?stuff=bother', {'ack': 'ack'}),
- simple + '?stuff=bother&ack=ack'),
-
- ('args exist (dict 2)',
- (simple + '?stuff=bother', {'ack': 'ack', 'zebra':'lion'}),
- simple + '?stuff=bother&ack=ack&zebra=lion'),
-
- ('three args (dict)',
- (simple, {'stuff': 'bother', 'ack': 'ack', 'zebra':'lion'}),
- simple + '?ack=ack&stuff=bother&zebra=lion'),
-
- ('three args (list)',
- (simple, [('stuff', 'bother'), ('ack', 'ack'), ('zebra', 'lion')]),
- simple + '?stuff=bother&ack=ack&zebra=lion'),
- ]
-
- tests = []
-
- for name, args, expected in cases:
- test = AppendArgsTest(name, args, expected)
- tests.append(test)
-
- return unittest.TestSuite(tests)
-
-def pyUnitTests():
- some = buildAppendTests()
- some.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestSymbol))
- return some
-
-def test_appendArgs():
- suite = buildAppendTests()
- suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestSymbol))
- runner = unittest.TextTestRunner()
- result = runner.run(suite)
- assert result.wasSuccessful()
-
-# XXX: there are more functions that could benefit from being better
-# specified and tested in oidutil.py These include, but are not
-# limited to appendArgs
-
-def test(skipPyUnit=True):
- test_base64()
- if not skipPyUnit:
- test_appendArgs()
-
-if __name__ == '__main__':
- test(skipPyUnit=False)
diff --git a/askbot/deps/openid/test/storetest.py b/askbot/deps/openid/test/storetest.py
deleted file mode 100644
index 0aa834e0..00000000
--- a/askbot/deps/openid/test/storetest.py
+++ /dev/null
@@ -1,397 +0,0 @@
-from askbot.deps.openid.association import Association
-from askbot.deps.openid.cryptutil import randomString
-from askbot.deps.openid.store.nonce import mkNonce, split
-
-import unittest
-import string
-import time
-import socket
-import random
-import os
-
-db_host = 'dbtest'
-
-allowed_handle = []
-for c in string.printable:
- if c not in string.whitespace:
- allowed_handle.append(c)
-allowed_handle = ''.join(allowed_handle)
-
-def generateHandle(n):
- return randomString(n, allowed_handle)
-
-generateSecret = randomString
-
-def getTmpDbName():
- hostname = socket.gethostname()
- hostname = hostname.replace('.', '_')
- hostname = hostname.replace('-', '_')
- return "%s_%d_%s_openid_test" % \
- (hostname, os.getpid(), \
- random.randrange(1, int(time.time())))
-
-def testStore(store):
- """Make sure a given store has a minimum of API compliance. Call
- this function with an empty store.
-
- Raises AssertionError if the store does not work as expected.
-
- OpenIDStore -> NoneType
- """
- ### Association functions
- now = int(time.time())
-
- server_url = 'http://www.myopenid.com/openid'
- def genAssoc(issued, lifetime=600):
- sec = generateSecret(20)
- hdl = generateHandle(128)
- return Association(hdl, sec, now + issued, lifetime, 'HMAC-SHA1')
-
- def checkRetrieve(url, handle=None, expected=None):
- retrieved_assoc = store.getAssociation(url, handle)
- assert retrieved_assoc == expected, (retrieved_assoc, expected)
- if expected is not None:
- if retrieved_assoc is expected:
- print ('Unexpected: retrieved a reference to the expected '
- 'value instead of a new object')
- assert retrieved_assoc.handle == expected.handle
- assert retrieved_assoc.secret == expected.secret
-
- def checkRemove(url, handle, expected):
- present = store.removeAssociation(url, handle)
- assert bool(expected) == bool(present)
-
- assoc = genAssoc(issued=0)
-
- # Make sure that a missing association returns no result
- checkRetrieve(server_url)
-
- # Check that after storage, getting returns the same result
- store.storeAssociation(server_url, assoc)
- checkRetrieve(server_url, None, assoc)
-
- # more than once
- checkRetrieve(server_url, None, assoc)
-
- # Storing more than once has no ill effect
- store.storeAssociation(server_url, assoc)
- checkRetrieve(server_url, None, assoc)
-
- # Removing an association that does not exist returns not present
- checkRemove(server_url, assoc.handle + 'x', False)
-
- # Removing an association that does not exist returns not present
- checkRemove(server_url + 'x', assoc.handle, False)
-
- # Removing an association that is present returns present
- checkRemove(server_url, assoc.handle, True)
-
- # but not present on subsequent calls
- checkRemove(server_url, assoc.handle, False)
-
- # Put assoc back in the store
- store.storeAssociation(server_url, assoc)
-
- # More recent and expires after assoc
- assoc2 = genAssoc(issued=1)
- store.storeAssociation(server_url, assoc2)
-
- # After storing an association with a different handle, but the
- # same server_url, the handle with the later issue date is returned.
- checkRetrieve(server_url, None, assoc2)
-
- # We can still retrieve the older association
- checkRetrieve(server_url, assoc.handle, assoc)
-
- # Plus we can retrieve the association with the later issue date
- # explicitly
- checkRetrieve(server_url, assoc2.handle, assoc2)
-
- # More recent, and expires earlier than assoc2 or assoc. Make sure
- # that we're picking the one with the latest issued date and not
- # taking into account the expiration.
- assoc3 = genAssoc(issued=2, lifetime=100)
- store.storeAssociation(server_url, assoc3)
-
- checkRetrieve(server_url, None, assoc3)
- checkRetrieve(server_url, assoc.handle, assoc)
- checkRetrieve(server_url, assoc2.handle, assoc2)
- checkRetrieve(server_url, assoc3.handle, assoc3)
-
- checkRemove(server_url, assoc2.handle, True)
-
- checkRetrieve(server_url, None, assoc3)
- checkRetrieve(server_url, assoc.handle, assoc)
- checkRetrieve(server_url, assoc2.handle, None)
- checkRetrieve(server_url, assoc3.handle, assoc3)
-
- checkRemove(server_url, assoc2.handle, False)
- checkRemove(server_url, assoc3.handle, True)
-
- checkRetrieve(server_url, None, assoc)
- checkRetrieve(server_url, assoc.handle, assoc)
- checkRetrieve(server_url, assoc2.handle, None)
- checkRetrieve(server_url, assoc3.handle, None)
-
- checkRemove(server_url, assoc2.handle, False)
- checkRemove(server_url, assoc.handle, True)
- checkRemove(server_url, assoc3.handle, False)
-
- checkRetrieve(server_url, None, None)
- checkRetrieve(server_url, assoc.handle, None)
- checkRetrieve(server_url, assoc2.handle, None)
- checkRetrieve(server_url, assoc3.handle, None)
-
- checkRemove(server_url, assoc2.handle, False)
- checkRemove(server_url, assoc.handle, False)
- checkRemove(server_url, assoc3.handle, False)
-
- ### test expired associations
- # assoc 1: server 1, valid
- # assoc 2: server 1, expired
- # assoc 3: server 2, expired
- # assoc 4: server 3, valid
- assocValid1 = genAssoc(issued=-3600,lifetime=7200)
- assocValid2 = genAssoc(issued=-5)
- assocExpired1 = genAssoc(issued=-7200,lifetime=3600)
- assocExpired2 = genAssoc(issued=-7200,lifetime=3600)
-
- store.cleanupAssociations()
- store.storeAssociation(server_url + '1', assocValid1)
- store.storeAssociation(server_url + '1', assocExpired1)
- store.storeAssociation(server_url + '2', assocExpired2)
- store.storeAssociation(server_url + '3', assocValid2)
-
- cleaned = store.cleanupAssociations()
- assert cleaned == 2, cleaned
-
- ### Nonce functions
-
- def checkUseNonce(nonce, expected, server_url, msg=''):
- stamp, salt = split(nonce)
- actual = store.useNonce(server_url, stamp, salt)
- assert bool(actual) == bool(expected), "%r != %r: %s" % (actual, expected,
- msg)
-
- for url in [server_url, '']:
- # Random nonce (not in store)
- nonce1 = mkNonce()
-
- # A nonce is allowed by default
- checkUseNonce(nonce1, True, url)
-
- # Storing once causes useNonce to return True the first, and only
- # the first, time it is called after the store.
- checkUseNonce(nonce1, False, url)
- checkUseNonce(nonce1, False, url)
-
- # Nonces from when the universe was an hour old should not pass these days.
- old_nonce = mkNonce(3600)
- checkUseNonce(old_nonce, False, url, "Old nonce (%r) passed." % (old_nonce,))
-
-
- old_nonce1 = mkNonce(now - 20000)
- old_nonce2 = mkNonce(now - 10000)
- recent_nonce = mkNonce(now - 600)
-
- from askbot.deps.openid.store import nonce as nonceModule
- orig_skew = nonceModule.SKEW
- try:
- nonceModule.SKEW = 0
- store.cleanupNonces()
- # Set SKEW high so stores will keep our nonces.
- nonceModule.SKEW = 100000
- assert store.useNonce(server_url, *split(old_nonce1))
- assert store.useNonce(server_url, *split(old_nonce2))
- assert store.useNonce(server_url, *split(recent_nonce))
-
- nonceModule.SKEW = 3600
- cleaned = store.cleanupNonces()
- assert cleaned == 2, "Cleaned %r nonces." % (cleaned,)
-
- nonceModule.SKEW = 100000
- # A roundabout method of checking that the old nonces were cleaned is
- # to see if we're allowed to add them again.
- assert store.useNonce(server_url, *split(old_nonce1))
- assert store.useNonce(server_url, *split(old_nonce2))
- # The recent nonce wasn't cleaned, so it should still fail.
- assert not store.useNonce(server_url, *split(recent_nonce))
- finally:
- nonceModule.SKEW = orig_skew
-
-
-def test_filestore():
- from askbot.deps.openid.store import filestore
- import tempfile
- import shutil
- try:
- temp_dir = tempfile.mkdtemp()
- except AttributeError:
- import os
- temp_dir = os.tmpnam()
- os.mkdir(temp_dir)
-
- store = filestore.FileOpenIDStore(temp_dir)
- try:
- testStore(store)
- store.cleanup()
- except:
- raise
- else:
- shutil.rmtree(temp_dir)
-
-def test_sqlite():
- from askbot.deps.openid.store import sqlstore
- try:
- from pysqlite2 import dbapi2 as sqlite
- except ImportError:
- pass
- else:
- conn = sqlite.connect(':memory:')
- store = sqlstore.SQLiteStore(conn)
- store.createTables()
- testStore(store)
-
-def test_mysql():
- from askbot.deps.openid.store import sqlstore
- try:
- import MySQLdb
- except ImportError:
- pass
- else:
- db_user = 'openid_test'
- db_passwd = ''
- db_name = getTmpDbName()
-
- from MySQLdb.constants import ER
-
- # Change this connect line to use the right user and password
- try:
- conn = MySQLdb.connect(user=db_user, passwd=db_passwd, host = db_host)
- except MySQLdb.OperationalError, why:
- if why[0] == 2005:
- print ('Skipping MySQL store test (cannot connect '
- 'to test server on host %r)' % (db_host,))
- return
- else:
- raise
-
- conn.query('CREATE DATABASE %s;' % db_name)
- try:
- conn.query('USE %s;' % db_name)
-
- # OK, we're in the right environment. Create store and
- # create the tables.
- store = sqlstore.MySQLStore(conn)
- store.createTables()
-
- # At last, we get to run the test.
- testStore(store)
- finally:
- # Remove the database. If you want to do post-mortem on a
- # failing test, comment out this line.
- conn.query('DROP DATABASE %s;' % db_name)
-
-def test_postgresql():
- """
- Tests the PostgreSQLStore on a locally-hosted PostgreSQL database
- cluster, version 7.4 or later. To run this test, you must have:
-
- - The 'psycopg' python module (version 1.1) installed
-
- - PostgreSQL running locally
-
- - An 'openid_test' user account in your database cluster, which
- you can create by running 'createuser -Ad openid_test' as the
- 'postgres' user
-
- - Trust auth for the 'openid_test' account, which you can activate
- by adding the following line to your pg_hba.conf file:
-
- local all openid_test trust
-
- This test connects to the database cluster three times:
-
- - To the 'template1' database, to create the test database
-
- - To the test database, to run the store tests
-
- - To the 'template1' database once more, to drop the test database
- """
- from askbot.deps.openid.store import sqlstore
- try:
- import psycopg
- except ImportError:
- pass
- else:
- db_name = getTmpDbName()
- db_user = 'openid_test'
-
- # Connect once to create the database; reconnect to access the
- # new database.
- conn_create = psycopg.connect(database = 'template1', user = db_user,
- host = db_host)
- conn_create.autocommit()
-
- # Create the test database.
- cursor = conn_create.cursor()
- cursor.execute('CREATE DATABASE %s;' % (db_name,))
- conn_create.close()
-
- # Connect to the test database.
- conn_test = psycopg.connect(database = db_name, user = db_user,
- host = db_host)
-
- # OK, we're in the right environment. Create the store
- # instance and create the tables.
- store = sqlstore.PostgreSQLStore(conn_test)
- store.createTables()
-
- # At last, we get to run the test.
- testStore(store)
-
- # Disconnect.
- conn_test.close()
-
- # It takes a little time for the close() call above to take
- # effect, so we'll wait for a second before trying to remove
- # the database. (Maybe this is because we're using a UNIX
- # socket to connect to postgres rather than TCP?)
- import time
- time.sleep(1)
-
- # Remove the database now that the test is over.
- conn_remove = psycopg.connect(database = 'template1', user = db_user,
- host = db_host)
- conn_remove.autocommit()
-
- cursor = conn_remove.cursor()
- cursor.execute('DROP DATABASE %s;' % (db_name,))
- conn_remove.close()
-
-def test_memstore():
- from askbot.deps.openid.store import memstore
- testStore(memstore.MemoryStore())
-
-test_functions = [
- test_filestore,
- test_sqlite,
- test_mysql,
- test_postgresql,
- test_memstore,
- ]
-
-def pyUnitTests():
- tests = map(unittest.FunctionTestCase, test_functions)
- load = unittest.defaultTestLoader.loadTestsFromTestCase
- return unittest.TestSuite(tests)
-
-if __name__ == '__main__':
- import sys
- suite = pyUnitTests()
- runner = unittest.TextTestRunner()
- result = runner.run(suite)
- if result.wasSuccessful():
- sys.exit(0)
- else:
- sys.exit(1)
diff --git a/askbot/deps/openid/test/support.py b/askbot/deps/openid/test/support.py
deleted file mode 100644
index 1573edbd..00000000
--- a/askbot/deps/openid/test/support.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from askbot.deps.openid import message
-from askbot.deps.openid import oidutil
-
-class OpenIDTestMixin(object):
- def failUnlessOpenIDValueEquals(self, msg, key, expected, ns=None):
- if ns is None:
- ns = message.OPENID_NS
-
- actual = msg.getArg(ns, key)
- error_format = 'Wrong value for openid.%s: expected=%s, actual=%s'
- error_message = error_format % (key, expected, actual)
- self.failUnlessEqual(expected, actual, error_message)
-
- def failIfOpenIDKeyExists(self, msg, key, ns=None):
- if ns is None:
- ns = message.OPENID_NS
-
- actual = msg.getArg(ns, key)
- error_message = 'openid.%s unexpectedly present: %s' % (key, actual)
- self.failIf(actual is not None, error_message)
-
-class CatchLogs(object):
- def setUp(self):
- self.old_logger = oidutil.log
- oidutil.log = self.gotLogMessage
- self.messages = []
-
- def gotLogMessage(self, message):
- self.messages.append(message)
-
- def tearDown(self):
- oidutil.log = self.old_logger
-
- def failUnlessLogMatches(self, *prefixes):
- """
- Check that the log messages contained in self.messages have
- prefixes in *prefixes. Raise AssertionError if not, or if the
- number of prefixes is different than the number of log
- messages.
- """
- assert len(prefixes) == len(self.messages), \
- "Expected log prefixes %r, got %r" % (prefixes,
- self.messages)
-
- for prefix, message in zip(prefixes, self.messages):
- assert message.startswith(prefix), \
- "Expected log prefixes %r, got %r" % (prefixes,
- self.messages)
-
- def failUnlessLogEmpty(self):
- self.failUnlessLogMatches()
diff --git a/askbot/deps/openid/test/test_accept.py b/askbot/deps/openid/test/test_accept.py
deleted file mode 100644
index 0bb491eb..00000000
--- a/askbot/deps/openid/test/test_accept.py
+++ /dev/null
@@ -1,127 +0,0 @@
-import unittest
-import os.path
-from askbot.deps.openid.yadis import accept
-
-def getTestData():
- """Read the test data off of disk
-
- () -> [(int, str)]
- """
- filename = os.path.join(os.path.dirname(__file__), 'data', 'accept.txt')
- i = 1
- lines = []
- for line in file(filename):
- lines.append((i, line))
- i += 1
- return lines
-
-def chunk(lines):
- """Return groups of lines separated by whitespace or comments
-
- [(int, str)] -> [[(int, str)]]
- """
- chunks = []
- chunk = []
- for lineno, line in lines:
- stripped = line.strip()
- if not stripped or stripped[0] == '#':
- if chunk:
- chunks.append(chunk)
- chunk = []
- else:
- chunk.append((lineno, stripped))
-
- if chunk:
- chunks.append(chunk)
-
- return chunks
-
-def parseLines(chunk):
- """Take the given chunk of lines and turn it into a test data dictionary
-
- [(int, str)] -> {str:(int, str)}
- """
- items = {}
- for (lineno, line) in chunk:
- header, data = line.split(':', 1)
- header = header.lower()
- items[header] = (lineno, data.strip())
-
- return items
-
-def parseAvailable(available_text):
- """Parse an Available: line's data
-
- str -> [str]
- """
- return [s.strip() for s in available_text.split(',')]
-
-def parseExpected(expected_text):
- """Parse an Expected: line's data
-
- str -> [(str, float)]
- """
- expected = []
- if expected_text:
- for chunk in expected_text.split(','):
- chunk = chunk.strip()
- mtype, qstuff = chunk.split(';')
- mtype = mtype.strip()
- assert '/' in mtype
- qstuff = qstuff.strip()
- q, qstr = qstuff.split('=')
- assert q == 'q'
- qval = float(qstr)
- expected.append((mtype, qval))
-
- return expected
-
-class MatchAcceptTest(unittest.TestCase):
- def __init__(self, descr, accept_header, available, expected):
- unittest.TestCase.__init__(self)
- self.accept_header = accept_header
- self.available = available
- self.expected = expected
- self.descr = descr
-
- def shortDescription(self):
- return self.descr
-
- def runTest(self):
- accepted = accept.parseAcceptHeader(self.accept_header)
- actual = accept.matchTypes(accepted, self.available)
- self.failUnlessEqual(self.expected, actual)
-
-def pyUnitTests():
- lines = getTestData()
- chunks = chunk(lines)
- data_sets = map(parseLines, chunks)
- cases = []
- for data in data_sets:
- lnos = []
- lno, header = data['accept']
- lnos.append(lno)
- lno, avail_data = data['available']
- lnos.append(lno)
- try:
- available = parseAvailable(avail_data)
- except:
- print 'On line', lno
- raise
-
- lno, exp_data = data['expected']
- lnos.append(lno)
- try:
- expected = parseExpected(exp_data)
- except:
- print 'On line', lno
- raise
-
- descr = 'MatchAcceptTest for lines %r' % (lnos,)
- case = MatchAcceptTest(descr, header, available, expected)
- cases.append(case)
- return unittest.TestSuite(cases)
-
-if __name__ == '__main__':
- runner = unittest.TextTestRunner()
- runner.run(loadTests())
diff --git a/askbot/deps/openid/test/test_association.py b/askbot/deps/openid/test/test_association.py
deleted file mode 100644
index 486be87b..00000000
--- a/askbot/deps/openid/test/test_association.py
+++ /dev/null
@@ -1,183 +0,0 @@
-from askbot.deps.openid.test import datadriven
-
-import unittest
-
-from askbot.deps.openid.message import Message, BARE_NS, OPENID_NS, OPENID2_NS
-from askbot.deps.openid import association
-import time
-from askbot.deps.openid import cryptutil
-import warnings
-
-class AssociationSerializationTest(unittest.TestCase):
- def test_roundTrip(self):
- issued = int(time.time())
- lifetime = 600
- assoc = association.Association(
- 'handle', 'secret', issued, lifetime, 'HMAC-SHA1')
- s = assoc.serialize()
- assoc2 = association.Association.deserialize(s)
- self.failUnlessEqual(assoc.handle, assoc2.handle)
- self.failUnlessEqual(assoc.issued, assoc2.issued)
- self.failUnlessEqual(assoc.secret, assoc2.secret)
- self.failUnlessEqual(assoc.lifetime, assoc2.lifetime)
- self.failUnlessEqual(assoc.assoc_type, assoc2.assoc_type)
-
-from askbot.deps.openid.server.server import \
- DiffieHellmanSHA1ServerSession, \
- DiffieHellmanSHA256ServerSession, \
- PlainTextServerSession
-
-from askbot.deps.openid.consumer.consumer import \
- DiffieHellmanSHA1ConsumerSession, \
- DiffieHellmanSHA256ConsumerSession, \
- PlainTextConsumerSession
-
-from askbot.deps.openid.dh import DiffieHellman
-
-def createNonstandardConsumerDH():
- nonstandard_dh = DiffieHellman(1315291, 2)
- return DiffieHellmanSHA1ConsumerSession(nonstandard_dh)
-
-class DiffieHellmanSessionTest(datadriven.DataDrivenTestCase):
- secrets = [
- '\x00' * 20,
- '\xff' * 20,
- ' ' * 20,
- 'This is a secret....',
- ]
-
- session_factories = [
- (DiffieHellmanSHA1ConsumerSession, DiffieHellmanSHA1ServerSession),
- (createNonstandardConsumerDH, DiffieHellmanSHA1ServerSession),
- (PlainTextConsumerSession, PlainTextServerSession),
- ]
-
- def generateCases(cls):
- return [(c, s, sec)
- for c, s in cls.session_factories
- for sec in cls.secrets]
-
- generateCases = classmethod(generateCases)
-
- def __init__(self, csess_fact, ssess_fact, secret):
- datadriven.DataDrivenTestCase.__init__(self, csess_fact.__name__)
- self.secret = secret
- self.csess_fact = csess_fact
- self.ssess_fact = ssess_fact
-
- def runOneTest(self):
- csess = self.csess_fact()
- msg = Message.fromOpenIDArgs(csess.getRequest())
- ssess = self.ssess_fact.fromMessage(msg)
- check_secret = csess.extractSecret(
- Message.fromOpenIDArgs(ssess.answer(self.secret)))
- self.failUnlessEqual(self.secret, check_secret)
-
-
-
-class TestMakePairs(unittest.TestCase):
- """Check the key-value formatting methods of associations.
- """
-
- def setUp(self):
- self.message = m = Message(OPENID2_NS)
- m.updateArgs(OPENID2_NS, {
- 'mode': 'id_res',
- 'identifier': '=example',
- 'signed': 'identifier,mode',
- 'sig': 'cephalopod',
- })
- m.updateArgs(BARE_NS, {'xey': 'value'})
- self.assoc = association.Association.fromExpiresIn(
- 3600, '{sha1}', 'very_secret', "HMAC-SHA1")
-
-
- def testMakePairs(self):
- """Make pairs using the OpenID 1.x type signed list."""
- pairs = self.assoc._makePairs(self.message)
- expected = [
- ('identifier', '=example'),
- ('mode', 'id_res'),
- ]
- self.failUnlessEqual(pairs, expected)
-
-
-
-class TestMac(unittest.TestCase):
- def setUp(self):
- self.pairs = [('key1', 'value1'),
- ('key2', 'value2')]
-
-
- def test_sha1(self):
- assoc = association.Association.fromExpiresIn(
- 3600, '{sha1}', 'very_secret', "HMAC-SHA1")
- expected = ('\xe0\x1bv\x04\xf1G\xc0\xbb\x7f\x9a\x8b'
- '\xe9\xbc\xee}\\\xe5\xbb7*')
- sig = assoc.sign(self.pairs)
- self.failUnlessEqual(sig, expected)
-
- if cryptutil.SHA256_AVAILABLE:
- def test_sha256(self):
- assoc = association.Association.fromExpiresIn(
- 3600, '{sha256SA}', 'very_secret', "HMAC-SHA256")
- expected = ('\xfd\xaa\xfe;\xac\xfc*\x988\xad\x05d6-\xeaVy'
- '\xd5\xa5Z.<\xa9\xed\x18\x82\\$\x95x\x1c&')
- sig = assoc.sign(self.pairs)
- self.failUnlessEqual(sig, expected)
-
-
-
-class TestMessageSigning(unittest.TestCase):
- def setUp(self):
- self.message = m = Message(OPENID2_NS)
- m.updateArgs(OPENID2_NS, {'mode': 'id_res',
- 'identifier': '=example'})
- m.updateArgs(BARE_NS, {'xey': 'value'})
- self.args = {'openid.mode': 'id_res',
- 'openid.identifier': '=example',
- 'xey': 'value'}
-
-
- def test_signSHA1(self):
- assoc = association.Association.fromExpiresIn(
- 3600, '{sha1}', 'very_secret', "HMAC-SHA1")
- signed = assoc.signMessage(self.message)
- self.failUnless(signed.getArg(OPENID_NS, "sig"))
- self.failUnlessEqual(signed.getArg(OPENID_NS, "signed"),
- "assoc_handle,identifier,mode,ns,signed")
- self.failUnlessEqual(signed.getArg(BARE_NS, "xey"), "value",
- signed)
-
- if cryptutil.SHA256_AVAILABLE:
- def test_signSHA256(self):
- assoc = association.Association.fromExpiresIn(
- 3600, '{sha1}', 'very_secret', "HMAC-SHA256")
- signed = assoc.signMessage(self.message)
- self.failUnless(signed.getArg(OPENID_NS, "sig"))
- self.failUnlessEqual(signed.getArg(OPENID_NS, "signed"),
- "assoc_handle,identifier,mode,ns,signed")
- self.failUnlessEqual(signed.getArg(BARE_NS, "xey"), "value",
- signed)
-
-
-class TestCheckMessageSignature(unittest.TestCase):
- def test_aintGotSignedList(self):
- m = Message(OPENID2_NS)
- m.updateArgs(OPENID2_NS, {'mode': 'id_res',
- 'identifier': '=example',
- 'sig': 'coyote',
- })
- m.updateArgs(BARE_NS, {'xey': 'value'})
- assoc = association.Association.fromExpiresIn(
- 3600, '{sha1}', 'very_secret', "HMAC-SHA1")
- self.failUnlessRaises(ValueError, assoc.checkMessageSignature, m)
-
-
-def pyUnitTests():
- return datadriven.loadTests(__name__)
-
-if __name__ == '__main__':
- suite = pyUnitTests()
- runner = unittest.TextTestRunner()
- runner.run(suite)
diff --git a/askbot/deps/openid/test/test_association_response.py b/askbot/deps/openid/test/test_association_response.py
deleted file mode 100644
index 34b2145f..00000000
--- a/askbot/deps/openid/test/test_association_response.py
+++ /dev/null
@@ -1,340 +0,0 @@
-"""Tests for consumer handling of association responses
-
-This duplicates some things that are covered by test_consumer, but
-this works for now.
-"""
-from askbot.deps.openid import oidutil
-from askbot.deps.openid.test.test_consumer import CatchLogs
-from askbot.deps.openid.message import Message, OPENID2_NS, OPENID_NS, no_default
-from askbot.deps.openid.server.server import DiffieHellmanSHA1ServerSession
-from askbot.deps.openid.consumer.consumer import GenericConsumer, \
- DiffieHellmanSHA1ConsumerSession, ProtocolError
-from askbot.deps.openid.consumer.discover import OpenIDServiceEndpoint, OPENID_1_1_TYPE, OPENID_2_0_TYPE
-from askbot.deps.openid.store import memstore
-import unittest
-
-# Some values we can use for convenience (see mkAssocResponse)
-association_response_values = {
- 'expires_in': '1000',
- 'assoc_handle':'a handle',
- 'assoc_type':'a type',
- 'session_type':'a session type',
- 'ns':OPENID2_NS,
- }
-
-def mkAssocResponse(*keys):
- """Build an association response message that contains the
- specified subset of keys. The values come from
- `association_response_values`.
-
- This is useful for testing for missing keys and other times that
- we don't care what the values are."""
- args = dict([(key, association_response_values[key]) for key in keys])
- return Message.fromOpenIDArgs(args)
-
-class BaseAssocTest(CatchLogs, unittest.TestCase):
- def setUp(self):
- CatchLogs.setUp(self)
- self.store = memstore.MemoryStore()
- self.consumer = GenericConsumer(self.store)
- self.endpoint = OpenIDServiceEndpoint()
-
- def failUnlessProtocolError(self, str_prefix, func, *args, **kwargs):
- try:
- result = func(*args, **kwargs)
- except ProtocolError, e:
- message = 'Expected prefix %r, got %r' % (str_prefix, e[0])
- self.failUnless(e[0].startswith(str_prefix), message)
- else:
- self.fail('Expected ProtocolError, got %r' % (result,))
-
-def mkExtractAssocMissingTest(keys):
- """Factory function for creating test methods for generating
- missing field tests.
-
- Make a test that ensures that an association response that
- is missing required fields will short-circuit return None.
-
- According to 'Association Session Response' subsection 'Common
- Response Parameters', the following fields are required for OpenID
- 2.0:
-
- * ns
- * session_type
- * assoc_handle
- * assoc_type
- * expires_in
-
- If 'ns' is missing, it will fall back to OpenID 1 checking. In
- OpenID 1, everything except 'session_type' and 'ns' are required.
- """
-
- def test(self):
- msg = mkAssocResponse(*keys)
-
- self.failUnlessRaises(KeyError,
- self.consumer._extractAssociation, msg, None)
-
- return test
-
-class TestExtractAssociationMissingFieldsOpenID2(BaseAssocTest):
- """Test for returning an error upon missing fields in association
- responses for OpenID 2"""
-
- test_noFields_openid2 = mkExtractAssocMissingTest(['ns'])
-
- test_missingExpires_openid2 = mkExtractAssocMissingTest(
- ['assoc_handle', 'assoc_type', 'session_type', 'ns'])
-
- test_missingHandle_openid2 = mkExtractAssocMissingTest(
- ['expires_in', 'assoc_type', 'session_type', 'ns'])
-
- test_missingAssocType_openid2 = mkExtractAssocMissingTest(
- ['expires_in', 'assoc_handle', 'session_type', 'ns'])
-
- test_missingSessionType_openid2 = mkExtractAssocMissingTest(
- ['expires_in', 'assoc_handle', 'assoc_type', 'ns'])
-
-class TestExtractAssociationMissingFieldsOpenID1(BaseAssocTest):
- """Test for returning an error upon missing fields in association
- responses for OpenID 2"""
-
- test_noFields_openid1 = mkExtractAssocMissingTest([])
-
- test_missingExpires_openid1 = mkExtractAssocMissingTest(
- ['assoc_handle', 'assoc_type'])
-
- test_missingHandle_openid1 = mkExtractAssocMissingTest(
- ['expires_in', 'assoc_type'])
-
- test_missingAssocType_openid1 = mkExtractAssocMissingTest(
- ['expires_in', 'assoc_handle'])
-
-class DummyAssocationSession(object):
- def __init__(self, session_type, allowed_assoc_types=()):
- self.session_type = session_type
- self.allowed_assoc_types = allowed_assoc_types
-
-class ExtractAssociationSessionTypeMismatch(BaseAssocTest):
- def mkTest(requested_session_type, response_session_type, openid1=False):
- def test(self):
- assoc_session = DummyAssocationSession(requested_session_type)
- keys = association_response_values.keys()
- if openid1:
- keys.remove('ns')
- msg = mkAssocResponse(*keys)
- msg.setArg(OPENID_NS, 'session_type', response_session_type)
- self.failUnlessProtocolError('Session type mismatch',
- self.consumer._extractAssociation, msg, assoc_session)
-
- return test
-
- test_typeMismatchNoEncBlank_openid2 = mkTest(
- requested_session_type='no-encryption',
- response_session_type='',
- )
-
- test_typeMismatchDHSHA1NoEnc_openid2 = mkTest(
- requested_session_type='DH-SHA1',
- response_session_type='no-encryption',
- )
-
- test_typeMismatchDHSHA256NoEnc_openid2 = mkTest(
- requested_session_type='DH-SHA256',
- response_session_type='no-encryption',
- )
-
- test_typeMismatchNoEncDHSHA1_openid2 = mkTest(
- requested_session_type='no-encryption',
- response_session_type='DH-SHA1',
- )
-
- test_typeMismatchDHSHA1NoEnc_openid1 = mkTest(
- requested_session_type='DH-SHA1',
- response_session_type='DH-SHA256',
- openid1=True,
- )
-
- test_typeMismatchDHSHA256NoEnc_openid1 = mkTest(
- requested_session_type='DH-SHA256',
- response_session_type='DH-SHA1',
- openid1=True,
- )
-
- test_typeMismatchNoEncDHSHA1_openid1 = mkTest(
- requested_session_type='no-encryption',
- response_session_type='DH-SHA1',
- openid1=True,
- )
-
-
-class TestOpenID1AssociationResponseSessionType(BaseAssocTest):
- def mkTest(expected_session_type, session_type_value):
- """Return a test method that will check what session type will
- be used if the OpenID 1 response to an associate call sets the
- 'session_type' field to `session_type_value`
- """
- def test(self):
- self._doTest(expected_session_type, session_type_value)
- self.failUnlessEqual(0, len(self.messages))
-
- return test
-
- def _doTest(self, expected_session_type, session_type_value):
- # Create a Message with just 'session_type' in it, since
- # that's all this function will use. 'session_type' may be
- # absent if it's set to None.
- args = {}
- if session_type_value is not None:
- args['session_type'] = session_type_value
- message = Message.fromOpenIDArgs(args)
- self.failUnless(message.isOpenID1())
-
- actual_session_type = self.consumer._getOpenID1SessionType(message)
- error_message = ('Returned sesion type parameter %r was expected '
- 'to yield session type %r, but yielded %r' %
- (session_type_value, expected_session_type,
- actual_session_type))
- self.failUnlessEqual(
- expected_session_type, actual_session_type, error_message)
-
- test_none = mkTest(
- session_type_value=None,
- expected_session_type='no-encryption',
- )
-
- test_empty = mkTest(
- session_type_value='',
- expected_session_type='no-encryption',
- )
-
- # This one's different because it expects log messages
- def test_explicitNoEncryption(self):
- self._doTest(
- session_type_value='no-encryption',
- expected_session_type='no-encryption',
- )
- self.failUnlessEqual(1, len(self.messages))
- self.failUnless(self.messages[0].startswith(
- 'WARNING: OpenID server sent "no-encryption"'))
-
- test_dhSHA1 = mkTest(
- session_type_value='DH-SHA1',
- expected_session_type='DH-SHA1',
- )
-
- # DH-SHA256 is not a valid session type for OpenID1, but this
- # function does not test that. This is mostly just to make sure
- # that it will pass-through stuff that is not explicitly handled,
- # so it will get handled the same way as it is handled for OpenID
- # 2
- test_dhSHA256 = mkTest(
- session_type_value='DH-SHA256',
- expected_session_type='DH-SHA256',
- )
-
-class DummyAssociationSession(object):
- secret = "shh! don't tell!"
- extract_secret_called = False
-
- session_type = None
-
- allowed_assoc_types = None
-
- def extractSecret(self, message):
- self.extract_secret_called = True
- return self.secret
-
-class TestInvalidFields(BaseAssocTest):
- def setUp(self):
- BaseAssocTest.setUp(self)
- self.session_type = 'testing-session'
-
- # This must something that works for Association.fromExpiresIn
- self.assoc_type = 'HMAC-SHA1'
-
- self.assoc_handle = 'testing-assoc-handle'
-
- # These arguments should all be valid
- self.assoc_response = Message.fromOpenIDArgs({
- 'expires_in': '1000',
- 'assoc_handle':self.assoc_handle,
- 'assoc_type':self.assoc_type,
- 'session_type':self.session_type,
- 'ns':OPENID2_NS,
- })
-
- self.assoc_session = DummyAssociationSession()
-
- # Make the session for the response's session type
- self.assoc_session.session_type = self.session_type
- self.assoc_session.allowed_assoc_types = [self.assoc_type]
-
- def test_worksWithGoodFields(self):
- """Handle a full successful association response"""
- assoc = self.consumer._extractAssociation(
- self.assoc_response, self.assoc_session)
- self.failUnless(self.assoc_session.extract_secret_called)
- self.failUnlessEqual(self.assoc_session.secret, assoc.secret)
- self.failUnlessEqual(1000, assoc.lifetime)
- self.failUnlessEqual(self.assoc_handle, assoc.handle)
- self.failUnlessEqual(self.assoc_type, assoc.assoc_type)
-
- def test_badAssocType(self):
- # Make sure that the assoc type in the response is not valid
- # for the given session.
- self.assoc_session.allowed_assoc_types = []
- self.failUnlessProtocolError('Unsupported assoc_type for session',
- self.consumer._extractAssociation,
- self.assoc_response, self.assoc_session)
-
- def test_badExpiresIn(self):
- # Invalid value for expires_in should cause failure
- self.assoc_response.setArg(OPENID_NS, 'expires_in', 'forever')
- self.failUnlessProtocolError('Invalid expires_in',
- self.consumer._extractAssociation,
- self.assoc_response, self.assoc_session)
-
-
-# XXX: This is what causes most of the imports in this file. It is
-# sort of a unit test and sort of a functional test. I'm not terribly
-# fond of it.
-class TestExtractAssociationDiffieHellman(BaseAssocTest):
- secret = 'x' * 20
-
- def _setUpDH(self):
- sess, message = self.consumer._createAssociateRequest(
- self.endpoint, 'HMAC-SHA1', 'DH-SHA1')
-
- # XXX: this is testing _createAssociateRequest
- self.failUnlessEqual(self.endpoint.compatibilityMode(),
- message.isOpenID1())
-
- server_sess = DiffieHellmanSHA1ServerSession.fromMessage(message)
- server_resp = server_sess.answer(self.secret)
- server_resp['assoc_type'] = 'HMAC-SHA1'
- server_resp['assoc_handle'] = 'handle'
- server_resp['expires_in'] = '1000'
- server_resp['session_type'] = 'DH-SHA1'
- return sess, Message.fromOpenIDArgs(server_resp)
-
- def test_success(self):
- sess, server_resp = self._setUpDH()
- ret = self.consumer._extractAssociation(server_resp, sess)
- self.failIf(ret is None)
- self.failUnlessEqual(ret.assoc_type, 'HMAC-SHA1')
- self.failUnlessEqual(ret.secret, self.secret)
- self.failUnlessEqual(ret.handle, 'handle')
- self.failUnlessEqual(ret.lifetime, 1000)
-
- def test_openid2success(self):
- # Use openid 2 type in endpoint so _setUpDH checks
- # compatibility mode state properly
- self.endpoint.type_uris = [OPENID_2_0_TYPE, OPENID_1_1_TYPE]
- self.test_success()
-
- def test_badDHValues(self):
- sess, server_resp = self._setUpDH()
- server_resp.setArg(OPENID_NS, 'enc_mac_key', '\x00\x00\x00')
- self.failUnlessProtocolError('Malformed response for',
- self.consumer._extractAssociation, server_resp, sess)
diff --git a/askbot/deps/openid/test/test_auth_request.py b/askbot/deps/openid/test/test_auth_request.py
deleted file mode 100644
index 412b77a4..00000000
--- a/askbot/deps/openid/test/test_auth_request.py
+++ /dev/null
@@ -1,206 +0,0 @@
-import cgi
-import unittest
-
-from askbot.deps.openid.consumer import consumer
-from askbot.deps.openid import message
-from askbot.deps.openid.test import support
-
-class DummyEndpoint(object):
- preferred_namespace = None
- local_id = None
- server_url = None
- is_op_identifier = False
-
- def preferredNamespace(self):
- return self.preferred_namespace
-
- def getLocalID(self):
- return self.local_id
-
- def isOPIdentifier(self):
- return self.is_op_identifier
-
-class DummyAssoc(object):
- handle = "assoc-handle"
-
-class TestAuthRequestMixin(support.OpenIDTestMixin):
- """Mixin for AuthRequest tests for OpenID 1 and 2; DON'T add
- unittest.TestCase as a base class here."""
-
- preferred_namespace = None
- immediate = False
- expected_mode = 'checkid_setup'
-
- def setUp(self):
- self.endpoint = DummyEndpoint()
- self.endpoint.local_id = 'http://server.unittest/joe'
- self.endpoint.claimed_id = 'http://joe.vanity.example/'
- self.endpoint.server_url = 'http://server.unittest/'
- self.endpoint.preferred_namespace = self.preferred_namespace
- self.realm = 'http://example/'
- self.return_to = 'http://example/return/'
- self.assoc = DummyAssoc()
- self.authreq = consumer.AuthRequest(self.endpoint, self.assoc)
-
- def failUnlessAnonymous(self, msg):
- for key in ['claimed_id', 'identity']:
- self.failIfOpenIDKeyExists(msg, key)
-
- def failUnlessHasRequiredFields(self, msg):
- self.failUnlessEqual(self.preferred_namespace,
- self.authreq.message.getOpenIDNamespace())
-
- self.failUnlessEqual(self.preferred_namespace,
- msg.getOpenIDNamespace())
-
- self.failUnlessOpenIDValueEquals(msg, 'mode',
- self.expected_mode)
-
- # Implement these in subclasses because they depend on
- # protocol differences!
- self.failUnlessHasRealm(msg)
- self.failUnlessIdentifiersPresent(msg)
-
- # TESTS
-
- def test_checkNoAssocHandle(self):
- self.authreq.assoc = None
- msg = self.authreq.getMessage(self.realm, self.return_to,
- self.immediate)
-
- self.failIfOpenIDKeyExists(msg, 'assoc_handle')
-
- def test_checkWithAssocHandle(self):
- msg = self.authreq.getMessage(self.realm, self.return_to,
- self.immediate)
-
- self.failUnlessOpenIDValueEquals(msg, 'assoc_handle',
- self.assoc.handle)
-
- def test_addExtensionArg(self):
- self.authreq.addExtensionArg('bag:', 'color', 'brown')
- self.authreq.addExtensionArg('bag:', 'material', 'paper')
- self.failUnless('bag:' in self.authreq.message.namespaces)
- self.failUnlessEqual(self.authreq.message.getArgs('bag:'),
- {'color': 'brown',
- 'material': 'paper'})
- msg = self.authreq.getMessage(self.realm, self.return_to,
- self.immediate)
-
- # XXX: this depends on the way that Message assigns
- # namespaces. Really it doesn't care that it has alias "0",
- # but that is tested anyway
- post_args = msg.toPostArgs()
- self.failUnlessEqual('brown', post_args['openid.ext0.color'])
- self.failUnlessEqual('paper', post_args['openid.ext0.material'])
-
- def test_standard(self):
- msg = self.authreq.getMessage(self.realm, self.return_to,
- self.immediate)
-
- self.failUnlessHasIdentifiers(
- msg, self.endpoint.local_id, self.endpoint.claimed_id)
-
-class TestAuthRequestOpenID2(TestAuthRequestMixin, unittest.TestCase):
- preferred_namespace = message.OPENID2_NS
-
- def failUnlessHasRealm(self, msg):
- # check presence of proper realm key and absence of the wrong
- # one.
- self.failUnlessOpenIDValueEquals(msg, 'realm', self.realm)
- self.failIfOpenIDKeyExists(msg, 'trust_root')
-
- def failUnlessIdentifiersPresent(self, msg):
- identity_present = msg.hasKey(message.OPENID_NS, 'identity')
- claimed_present = msg.hasKey(message.OPENID_NS, 'claimed_id')
-
- self.failUnlessEqual(claimed_present, identity_present)
-
- def failUnlessHasIdentifiers(self, msg, op_specific_id, claimed_id):
- self.failUnlessOpenIDValueEquals(msg, 'identity', op_specific_id)
- self.failUnlessOpenIDValueEquals(msg, 'claimed_id', claimed_id)
-
- # TESTS
-
- def test_setAnonymousWorksForOpenID2(self):
- """OpenID AuthRequests should be able to set 'anonymous' to true."""
- self.failUnless(self.authreq.message.isOpenID2())
- self.authreq.setAnonymous(True)
- self.authreq.setAnonymous(False)
-
- def test_userAnonymousIgnoresIdentfier(self):
- self.authreq.setAnonymous(True)
- msg = self.authreq.getMessage(self.realm, self.return_to,
- self.immediate)
- self.failUnlessHasRequiredFields(msg)
- self.failUnlessAnonymous(msg)
-
- def test_opAnonymousIgnoresIdentifier(self):
- self.endpoint.is_op_identifier = True
- self.authreq.setAnonymous(True)
- msg = self.authreq.getMessage(self.realm, self.return_to,
- self.immediate)
- self.failUnlessHasRequiredFields(msg)
- self.failUnlessAnonymous(msg)
-
- def test_opIdentifierSendsIdentifierSelect(self):
- self.endpoint.is_op_identifier = True
- msg = self.authreq.getMessage(self.realm, self.return_to,
- self.immediate)
- self.failUnlessHasRequiredFields(msg)
- self.failUnlessHasIdentifiers(
- msg, message.IDENTIFIER_SELECT, message.IDENTIFIER_SELECT)
-
-class TestAuthRequestOpenID1(TestAuthRequestMixin, unittest.TestCase):
- preferred_namespace = message.OPENID1_NS
-
- def setUpEndpoint(self):
- TestAuthRequestBase.setUpEndpoint(self)
- self.endpoint.preferred_namespace = message.OPENID1_NS
-
- def failUnlessHasIdentifiers(self, msg, op_specific_id, claimed_id):
- """Make sure claimed_is is *absent* in request."""
- self.failUnlessOpenIDValueEquals(msg, 'identity', op_specific_id)
- self.failIfOpenIDKeyExists(msg, 'claimed_id')
-
- def failUnlessIdentifiersPresent(self, msg):
- self.failIfOpenIDKeyExists(msg, 'claimed_id')
- self.failUnless(msg.hasKey(message.OPENID_NS, 'identity'))
-
- def failUnlessHasRealm(self, msg):
- # check presence of proper realm key and absence of the wrong
- # one.
- self.failUnlessOpenIDValueEquals(msg, 'trust_root', self.realm)
- self.failIfOpenIDKeyExists(msg, 'realm')
-
- # TESTS
-
- def test_setAnonymousFailsForOpenID1(self):
- """OpenID 1 requests MUST NOT be able to set anonymous to True"""
- self.failUnless(self.authreq.message.isOpenID1())
- self.failUnlessRaises(ValueError, self.authreq.setAnonymous, True)
- self.authreq.setAnonymous(False)
-
- def test_identifierSelect(self):
- """Identfier select SHOULD NOT be sent, but this pathway is in
- here in case some special discovery stuff is done to trigger
- it with OpenID 1. If it is triggered, it will send
- identifier_select just like OpenID 2.
- """
- self.endpoint.is_op_identifier = True
- msg = self.authreq.getMessage(self.realm, self.return_to,
- self.immediate)
- self.failUnlessHasRequiredFields(msg)
- self.failUnlessEqual(message.IDENTIFIER_SELECT,
- msg.getArg(message.OPENID1_NS, 'identity'))
-
-class TestAuthRequestOpenID1Immediate(TestAuthRequestOpenID1):
- immediate = True
- expected_mode = 'checkid_immediate'
-
-class TestAuthRequestOpenID2Immediate(TestAuthRequestOpenID2):
- immediate = True
- expected_mode = 'checkid_immediate'
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_ax.py b/askbot/deps/openid/test/test_ax.py
deleted file mode 100644
index 6d4aeac5..00000000
--- a/askbot/deps/openid/test/test_ax.py
+++ /dev/null
@@ -1,626 +0,0 @@
-"""Tests for the attribute exchange extension module
-"""
-
-import unittest
-from askbot.deps.openid.extensions import ax
-from askbot.deps.openid.message import NamespaceMap, Message, OPENID2_NS
-from askbot.deps.openid.consumer.consumer import SuccessResponse
-
-class BogusAXMessage(ax.AXMessage):
- mode = 'bogus'
-
- getExtensionArgs = ax.AXMessage._newArgs
-
-class DummyRequest(object):
- def __init__(self, message):
- self.message = message
-
-class AXMessageTest(unittest.TestCase):
- def setUp(self):
- self.bax = BogusAXMessage()
-
- def test_checkMode(self):
- check = self.bax._checkMode
- self.failUnlessRaises(ax.NotAXMessage, check, {})
- self.failUnlessRaises(ax.AXError, check, {'mode':'fetch_request'})
-
- # does not raise an exception when the mode is right
- check({'mode':self.bax.mode})
-
- def test_checkMode_newArgs(self):
- """_newArgs generates something that has the correct mode"""
- # This would raise AXError if it didn't like the mode newArgs made.
- self.bax._checkMode(self.bax._newArgs())
-
-
-class AttrInfoTest(unittest.TestCase):
- def test_construct(self):
- self.failUnlessRaises(TypeError, ax.AttrInfo)
- type_uri = 'a uri'
- ainfo = ax.AttrInfo(type_uri)
-
- self.failUnlessEqual(type_uri, ainfo.type_uri)
- self.failUnlessEqual(1, ainfo.count)
- self.failIf(ainfo.required)
- self.failUnless(ainfo.alias is None)
-
-
-class ToTypeURIsTest(unittest.TestCase):
- def setUp(self):
- self.aliases = NamespaceMap()
-
- def test_empty(self):
- for empty in [None, '']:
- uris = ax.toTypeURIs(self.aliases, empty)
- self.failUnlessEqual([], uris)
-
- def test_undefined(self):
- self.failUnlessRaises(
- KeyError,
- ax.toTypeURIs, self.aliases, 'http://janrain.com/')
-
- def test_one(self):
- uri = 'http://janrain.com/'
- alias = 'openid_hackers'
- self.aliases.addAlias(uri, alias)
- uris = ax.toTypeURIs(self.aliases, alias)
- self.failUnlessEqual([uri], uris)
-
- def test_two(self):
- uri1 = 'http://janrain.com/'
- alias1 = 'openid_hackers'
- self.aliases.addAlias(uri1, alias1)
-
- uri2 = 'http://jyte.com/'
- alias2 = 'openid_hack'
- self.aliases.addAlias(uri2, alias2)
-
- uris = ax.toTypeURIs(self.aliases, ','.join([alias1, alias2]))
- self.failUnlessEqual([uri1, uri2], uris)
-
-class ParseAXValuesTest(unittest.TestCase):
- """Testing AXKeyValueMessage.parseExtensionArgs."""
-
- def failUnlessAXKeyError(self, ax_args):
- msg = ax.AXKeyValueMessage()
- self.failUnlessRaises(KeyError, msg.parseExtensionArgs, ax_args)
-
- def failUnlessAXValues(self, ax_args, expected_args):
- """Fail unless parseExtensionArgs(ax_args) == expected_args."""
- msg = ax.AXKeyValueMessage()
- msg.parseExtensionArgs(ax_args)
- self.failUnlessEqual(expected_args, msg.data)
-
- def test_emptyIsValid(self):
- self.failUnlessAXValues({}, {})
-
- def test_missingValueForAliasExplodes(self):
- self.failUnlessAXKeyError({'type.foo':'urn:foo'})
-
- def test_countPresentButNotValue(self):
- self.failUnlessAXKeyError({'type.foo':'urn:foo',
- 'count.foo':'1'})
-
- def test_invalidCountValue(self):
- msg = ax.FetchRequest()
- self.failUnlessRaises(ax.AXError,
- msg.parseExtensionArgs,
- {'type.foo':'urn:foo',
- 'count.foo':'bogus'})
-
- def test_requestUnlimitedValues(self):
- msg = ax.FetchRequest()
-
- msg.parseExtensionArgs(
- {'mode':'fetch_request',
- 'required':'foo',
- 'type.foo':'urn:foo',
- 'count.foo':ax.UNLIMITED_VALUES})
-
- attrs = list(msg.iterAttrs())
- foo = attrs[0]
-
- self.failUnless(foo.count == ax.UNLIMITED_VALUES)
- self.failUnless(foo.wantsUnlimitedValues())
-
- def test_longAlias(self):
- # Spec minimum length is 32 characters. This is a silly test
- # for this library, but it's here for completeness.
- alias = 'x' * ax.MINIMUM_SUPPORTED_ALIAS_LENGTH
-
- msg = ax.AXKeyValueMessage()
- msg.parseExtensionArgs(
- {'type.%s' % (alias,): 'urn:foo',
- 'count.%s' % (alias,): '1',
- 'value.%s.1' % (alias,): 'first'}
- )
-
- def test_invalidAlias(self):
- types = [
- ax.AXKeyValueMessage,
- ax.FetchRequest
- ]
-
- inputs = [
- {'type.a.b':'urn:foo',
- 'count.a.b':'1'},
- {'type.a,b':'urn:foo',
- 'count.a,b':'1'},
- ]
-
- for typ in types:
- for input in inputs:
- msg = typ()
- self.failUnlessRaises(ax.AXError, msg.parseExtensionArgs,
- input)
-
- def test_countPresentAndIsZero(self):
- self.failUnlessAXValues(
- {'type.foo':'urn:foo',
- 'count.foo':'0',
- }, {'urn:foo':[]})
-
- def test_singletonEmpty(self):
- self.failUnlessAXValues(
- {'type.foo':'urn:foo',
- 'value.foo':'',
- }, {'urn:foo':[]})
-
- def test_doubleAlias(self):
- self.failUnlessAXKeyError(
- {'type.foo':'urn:foo',
- 'value.foo':'',
- 'type.bar':'urn:foo',
- 'value.bar':'',
- })
-
- def test_doubleSingleton(self):
- self.failUnlessAXValues(
- {'type.foo':'urn:foo',
- 'value.foo':'',
- 'type.bar':'urn:bar',
- 'value.bar':'',
- }, {'urn:foo':[], 'urn:bar':[]})
-
- def test_singletonValue(self):
- self.failUnlessAXValues(
- {'type.foo':'urn:foo',
- 'value.foo':'Westfall',
- }, {'urn:foo':['Westfall']})
-
-
-class FetchRequestTest(unittest.TestCase):
- def setUp(self):
- self.msg = ax.FetchRequest()
- self.type_a = 'http://janrain.example.com/a'
- self.alias_a = 'a'
-
-
- def test_mode(self):
- self.failUnlessEqual(self.msg.mode, 'fetch_request')
-
- def test_construct(self):
- self.failUnlessEqual({}, self.msg.requested_attributes)
- self.failUnlessEqual(None, self.msg.update_url)
-
- msg = ax.FetchRequest('hailstorm')
- self.failUnlessEqual({}, msg.requested_attributes)
- self.failUnlessEqual('hailstorm', msg.update_url)
-
- def test_add(self):
- uri = 'mud://puddle'
-
- # Not yet added:
- self.failIf(uri in self.msg)
-
- attr = ax.AttrInfo(uri)
- self.msg.add(attr)
-
- # Present after adding
- self.failUnless(uri in self.msg)
-
- def test_addTwice(self):
- uri = 'lightning://storm'
-
- attr = ax.AttrInfo(uri)
- self.msg.add(attr)
- self.failUnlessRaises(KeyError, self.msg.add, attr)
-
- def test_getExtensionArgs_empty(self):
- expected_args = {
- 'mode':'fetch_request',
- }
- self.failUnlessEqual(expected_args, self.msg.getExtensionArgs())
-
- def test_getExtensionArgs_noAlias(self):
- attr = ax.AttrInfo(
- type_uri = 'type://of.transportation',
- )
- self.msg.add(attr)
- ax_args = self.msg.getExtensionArgs()
- for k, v in ax_args.iteritems():
- if v == attr.type_uri and k.startswith('type.'):
- alias = k[5:]
- break
- else:
- self.fail("Didn't find the type definition")
-
- self.failUnlessExtensionArgs({
- 'type.' + alias:attr.type_uri,
- 'if_available':alias,
- })
-
- def test_getExtensionArgs_alias_if_available(self):
- attr = ax.AttrInfo(
- type_uri = 'type://of.transportation',
- alias = 'transport',
- )
- self.msg.add(attr)
- self.failUnlessExtensionArgs({
- 'type.' + attr.alias:attr.type_uri,
- 'if_available':attr.alias,
- })
-
- def test_getExtensionArgs_alias_req(self):
- attr = ax.AttrInfo(
- type_uri = 'type://of.transportation',
- alias = 'transport',
- required = True,
- )
- self.msg.add(attr)
- self.failUnlessExtensionArgs({
- 'type.' + attr.alias:attr.type_uri,
- 'required':attr.alias,
- })
-
- def failUnlessExtensionArgs(self, expected_args):
- """Make sure that getExtensionArgs has the expected result
-
- This method will fill in the mode.
- """
- expected_args = dict(expected_args)
- expected_args['mode'] = self.msg.mode
- self.failUnlessEqual(expected_args, self.msg.getExtensionArgs())
-
- def test_isIterable(self):
- self.failUnlessEqual([], list(self.msg))
- self.failUnlessEqual([], list(self.msg.iterAttrs()))
-
- def test_getRequiredAttrs_empty(self):
- self.failUnlessEqual([], self.msg.getRequiredAttrs())
-
- def test_parseExtensionArgs_extraType(self):
- extension_args = {
- 'mode':'fetch_request',
- 'type.' + self.alias_a:self.type_a,
- }
- self.failUnlessRaises(ValueError,
- self.msg.parseExtensionArgs, extension_args)
-
- def test_parseExtensionArgs(self):
- extension_args = {
- 'mode':'fetch_request',
- 'type.' + self.alias_a:self.type_a,
- 'if_available':self.alias_a
- }
- self.msg.parseExtensionArgs(extension_args)
- self.failUnless(self.type_a in self.msg)
- self.failUnlessEqual([self.type_a], list(self.msg))
- attr_info = self.msg.requested_attributes.get(self.type_a)
- self.failUnless(attr_info)
- self.failIf(attr_info.required)
- self.failUnlessEqual(self.type_a, attr_info.type_uri)
- self.failUnlessEqual(self.alias_a, attr_info.alias)
- self.failUnlessEqual([attr_info], list(self.msg.iterAttrs()))
-
- def test_extensionArgs_idempotent(self):
- extension_args = {
- 'mode':'fetch_request',
- 'type.' + self.alias_a:self.type_a,
- 'if_available':self.alias_a
- }
- self.msg.parseExtensionArgs(extension_args)
- self.failUnlessEqual(extension_args, self.msg.getExtensionArgs())
- self.failIf(self.msg.requested_attributes[self.type_a].required)
-
- def test_extensionArgs_idempotent_count_required(self):
- extension_args = {
- 'mode':'fetch_request',
- 'type.' + self.alias_a:self.type_a,
- 'count.' + self.alias_a:'2',
- 'required':self.alias_a
- }
- self.msg.parseExtensionArgs(extension_args)
- self.failUnlessEqual(extension_args, self.msg.getExtensionArgs())
- self.failUnless(self.msg.requested_attributes[self.type_a].required)
-
- def test_extensionArgs_count1(self):
- extension_args = {
- 'mode':'fetch_request',
- 'type.' + self.alias_a:self.type_a,
- 'count.' + self.alias_a:'1',
- 'if_available':self.alias_a,
- }
- extension_args_norm = {
- 'mode':'fetch_request',
- 'type.' + self.alias_a:self.type_a,
- 'if_available':self.alias_a,
- }
- self.msg.parseExtensionArgs(extension_args)
- self.failUnlessEqual(extension_args_norm, self.msg.getExtensionArgs())
-
- def test_openidNoRealm(self):
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'checkid_setup',
- 'ns': OPENID2_NS,
- 'ns.ax': ax.AXMessage.ns_uri,
- 'ax.update_url': 'http://different.site/path',
- 'ax.mode': 'fetch_request',
- })
- self.failUnlessRaises(ax.AXError,
- ax.FetchRequest.fromOpenIDRequest,
- DummyRequest(openid_req_msg))
-
- def test_openidUpdateURLVerificationError(self):
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'checkid_setup',
- 'ns': OPENID2_NS,
- 'realm': 'http://example.com/realm',
- 'ns.ax': ax.AXMessage.ns_uri,
- 'ax.update_url': 'http://different.site/path',
- 'ax.mode': 'fetch_request',
- })
-
- self.failUnlessRaises(ax.AXError,
- ax.FetchRequest.fromOpenIDRequest,
- DummyRequest(openid_req_msg))
-
- def test_openidUpdateURLVerificationSuccess(self):
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'checkid_setup',
- 'ns': OPENID2_NS,
- 'realm': 'http://example.com/realm',
- 'ns.ax': ax.AXMessage.ns_uri,
- 'ax.update_url': 'http://example.com/realm/update_path',
- 'ax.mode': 'fetch_request',
- })
-
- fr = ax.FetchRequest.fromOpenIDRequest(DummyRequest(openid_req_msg))
-
- def test_openidUpdateURLVerificationSuccessReturnTo(self):
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'checkid_setup',
- 'ns': OPENID2_NS,
- 'return_to': 'http://example.com/realm',
- 'ns.ax': ax.AXMessage.ns_uri,
- 'ax.update_url': 'http://example.com/realm/update_path',
- 'ax.mode': 'fetch_request',
- })
-
- fr = ax.FetchRequest.fromOpenIDRequest(DummyRequest(openid_req_msg))
-
- def test_fromOpenIDRequestWithoutExtension(self):
- """return None for an OpenIDRequest without AX paramaters."""
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'checkid_setup',
- 'ns': OPENID2_NS,
- })
- oreq = DummyRequest(openid_req_msg)
- r = ax.FetchRequest.fromOpenIDRequest(oreq)
- self.failUnless(r is None, "%s is not None" % (r,))
-
- def test_fromOpenIDRequestWithoutData(self):
- """return something for SuccessResponse with AX paramaters,
- even if it is the empty set."""
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'checkid_setup',
- 'realm': 'http://example.com/realm',
- 'ns': OPENID2_NS,
- 'ns.ax': ax.AXMessage.ns_uri,
- 'ax.mode': 'fetch_request',
- })
- oreq = DummyRequest(openid_req_msg)
- r = ax.FetchRequest.fromOpenIDRequest(oreq)
- self.failUnless(r is not None)
-
-
-class FetchResponseTest(unittest.TestCase):
- def setUp(self):
- self.msg = ax.FetchResponse()
- self.value_a = 'monkeys'
- self.type_a = 'http://phone.home/'
- self.alias_a = 'robocop'
- self.request_update_url = 'http://update.bogus/'
-
- def test_construct(self):
- self.failUnless(self.msg.update_url is None)
- self.failUnlessEqual({}, self.msg.data)
-
- def test_getExtensionArgs_empty(self):
- expected_args = {
- 'mode':'fetch_response',
- }
- self.failUnlessEqual(expected_args, self.msg.getExtensionArgs())
-
- def test_getExtensionArgs_empty_request(self):
- expected_args = {
- 'mode':'fetch_response',
- }
- req = ax.FetchRequest()
- msg = ax.FetchResponse(request=req)
- self.failUnlessEqual(expected_args, msg.getExtensionArgs())
-
- def test_getExtensionArgs_empty_request_some(self):
- uri = 'http://not.found/'
- alias = 'ext0'
-
- expected_args = {
- 'mode':'fetch_response',
- 'type.%s' % (alias,): uri,
- 'count.%s' % (alias,): '0'
- }
- req = ax.FetchRequest()
- req.add(ax.AttrInfo(uri))
- msg = ax.FetchResponse(request=req)
- self.failUnlessEqual(expected_args, msg.getExtensionArgs())
-
- def test_updateUrlInResponse(self):
- uri = 'http://not.found/'
- alias = 'ext0'
-
- expected_args = {
- 'mode':'fetch_response',
- 'update_url': self.request_update_url,
- 'type.%s' % (alias,): uri,
- 'count.%s' % (alias,): '0'
- }
- req = ax.FetchRequest(update_url=self.request_update_url)
- req.add(ax.AttrInfo(uri))
- msg = ax.FetchResponse(request=req)
- self.failUnlessEqual(expected_args, msg.getExtensionArgs())
-
- def test_getExtensionArgs_some_request(self):
- expected_args = {
- 'mode':'fetch_response',
- 'type.' + self.alias_a:self.type_a,
- 'value.' + self.alias_a + '.1':self.value_a,
- 'count.' + self.alias_a: '1'
- }
- req = ax.FetchRequest()
- req.add(ax.AttrInfo(self.type_a, alias=self.alias_a))
- msg = ax.FetchResponse(request=req)
- msg.addValue(self.type_a, self.value_a)
- self.failUnlessEqual(expected_args, msg.getExtensionArgs())
-
- def test_getExtensionArgs_some_not_request(self):
- req = ax.FetchRequest()
- msg = ax.FetchResponse(request=req)
- msg.addValue(self.type_a, self.value_a)
- self.failUnlessRaises(KeyError, msg.getExtensionArgs)
-
- def test_getSingle_success(self):
- req = ax.FetchRequest()
- self.msg.addValue(self.type_a, self.value_a)
- self.failUnlessEqual(self.value_a, self.msg.getSingle(self.type_a))
-
- def test_getSingle_none(self):
- self.failUnlessEqual(None, self.msg.getSingle(self.type_a))
-
- def test_getSingle_extra(self):
- self.msg.setValues(self.type_a, ['x', 'y'])
- self.failUnlessRaises(ax.AXError, self.msg.getSingle, self.type_a)
-
- def test_get(self):
- self.failUnlessRaises(KeyError, self.msg.get, self.type_a)
-
- def test_fromSuccessResponseWithoutExtension(self):
- """return None for SuccessResponse with no AX paramaters."""
- args = {
- 'mode': 'id_res',
- 'ns': OPENID2_NS,
- }
- sf = ['openid.' + i for i in args.keys()]
- msg = Message.fromOpenIDArgs(args)
- class Endpoint:
- claimed_id = 'http://invalid.'
-
- oreq = SuccessResponse(Endpoint(), msg, signed_fields=sf)
- r = ax.FetchResponse.fromSuccessResponse(oreq)
- self.failUnless(r is None, "%s is not None" % (r,))
-
- def test_fromSuccessResponseWithoutData(self):
- """return something for SuccessResponse with AX paramaters,
- even if it is the empty set."""
- args = {
- 'mode': 'id_res',
- 'ns': OPENID2_NS,
- 'ns.ax': ax.AXMessage.ns_uri,
- 'ax.mode': 'fetch_response',
- }
- sf = ['openid.' + i for i in args.keys()]
- msg = Message.fromOpenIDArgs(args)
- class Endpoint:
- claimed_id = 'http://invalid.'
-
- oreq = SuccessResponse(Endpoint(), msg, signed_fields=sf)
- r = ax.FetchResponse.fromSuccessResponse(oreq)
- self.failUnless(r is not None)
-
- def test_fromSuccessResponseWithData(self):
- name = 'ext0'
- value = 'snozzberry'
- uri = "http://willy.wonka.name/"
- args = {
- 'mode': 'id_res',
- 'ns': OPENID2_NS,
- 'ns.ax': ax.AXMessage.ns_uri,
- 'ax.update_url': 'http://example.com/realm/update_path',
- 'ax.mode': 'fetch_response',
- 'ax.type.'+name: uri,
- 'ax.count.'+name: '1',
- 'ax.value.%s.1'%name: value,
- }
- sf = ['openid.' + i for i in args.keys()]
- msg = Message.fromOpenIDArgs(args)
- class Endpoint:
- claimed_id = 'http://invalid.'
-
- resp = SuccessResponse(Endpoint(), msg, signed_fields=sf)
- ax_resp = ax.FetchResponse.fromSuccessResponse(resp)
- values = ax_resp.get(uri)
- self.failUnlessEqual([value], values)
-
-
-class StoreRequestTest(unittest.TestCase):
- def setUp(self):
- self.msg = ax.StoreRequest()
- self.type_a = 'http://three.count/'
- self.alias_a = 'juggling'
-
- def test_construct(self):
- self.failUnlessEqual({}, self.msg.data)
-
- def test_getExtensionArgs_empty(self):
- args = self.msg.getExtensionArgs()
- expected_args = {
- 'mode':'store_request',
- }
- self.failUnlessEqual(expected_args, args)
-
- def test_getExtensionArgs_nonempty(self):
- aliases = NamespaceMap()
- aliases.addAlias(self.type_a, self.alias_a)
- msg = ax.StoreRequest(aliases=aliases)
- msg.setValues(self.type_a, ['foo', 'bar'])
- args = msg.getExtensionArgs()
- expected_args = {
- 'mode':'store_request',
- 'type.' + self.alias_a: self.type_a,
- 'count.' + self.alias_a: '2',
- 'value.%s.1' % (self.alias_a,):'foo',
- 'value.%s.2' % (self.alias_a,):'bar',
- }
- self.failUnlessEqual(expected_args, args)
-
-class StoreResponseTest(unittest.TestCase):
- def test_success(self):
- msg = ax.StoreResponse()
- self.failUnless(msg.succeeded())
- self.failIf(msg.error_message)
- self.failUnlessEqual({'mode':'store_response_success'},
- msg.getExtensionArgs())
-
- def test_fail_nomsg(self):
- msg = ax.StoreResponse(False)
- self.failIf(msg.succeeded())
- self.failIf(msg.error_message)
- self.failUnlessEqual({'mode':'store_response_failure'},
- msg.getExtensionArgs())
-
- def test_fail_msg(self):
- reason = 'no reason, really'
- msg = ax.StoreResponse(False, reason)
- self.failIf(msg.succeeded())
- self.failUnlessEqual(reason, msg.error_message)
- self.failUnlessEqual({'mode':'store_response_failure',
- 'error':reason}, msg.getExtensionArgs())
diff --git a/askbot/deps/openid/test/test_consumer.py b/askbot/deps/openid/test/test_consumer.py
deleted file mode 100644
index e0bf48c5..00000000
--- a/askbot/deps/openid/test/test_consumer.py
+++ /dev/null
@@ -1,2097 +0,0 @@
-import urlparse
-import cgi
-import time
-import warnings
-
-from askbot.deps.openid.message import Message, OPENID_NS, OPENID2_NS, IDENTIFIER_SELECT, \
- OPENID1_NS, BARE_NS
-from askbot.deps.openid import cryptutil, dh, oidutil, kvform
-from askbot.deps.openid.store.nonce import mkNonce, split as splitNonce
-from askbot.deps.openid.consumer.discover import OpenIDServiceEndpoint, OPENID_2_0_TYPE, \
- OPENID_1_1_TYPE
-from askbot.deps.openid.consumer.consumer import \
- AuthRequest, GenericConsumer, SUCCESS, FAILURE, CANCEL, SETUP_NEEDED, \
- SuccessResponse, FailureResponse, SetupNeededResponse, CancelResponse, \
- DiffieHellmanSHA1ConsumerSession, Consumer, PlainTextConsumerSession, \
- SetupNeededError, DiffieHellmanSHA256ConsumerSession, ServerError, \
- ProtocolError, _httpResponseToMessage
-from askbot.deps.openid import association
-from askbot.deps.openid.server.server import \
- PlainTextServerSession, DiffieHellmanSHA1ServerSession
-from askbot.deps.openid.yadis.manager import Discovery
-from askbot.deps.openid.yadis.discover import DiscoveryFailure
-from askbot.deps.openid.dh import DiffieHellman
-
-from askbot.deps.openid.fetchers import HTTPResponse, HTTPFetchingError
-from askbot.deps.openid import fetchers
-from askbot.deps.openid.store import memstore
-
-from support import CatchLogs
-
-assocs = [
- ('another 20-byte key.', 'Snarky'),
- ('\x00' * 20, 'Zeros'),
- ]
-
-def mkSuccess(endpoint, q):
- """Convenience function to create a SuccessResponse with the given
- arguments, all signed."""
- signed_list = ['openid.' + k for k in q.keys()]
- return SuccessResponse(endpoint, Message.fromOpenIDArgs(q), signed_list)
-
-def parseQuery(qs):
- q = {}
- for (k, v) in cgi.parse_qsl(qs):
- assert not q.has_key(k)
- q[k] = v
- return q
-
-def associate(qs, assoc_secret, assoc_handle):
- """Do the server's half of the associate call, using the given
- secret and handle."""
- q = parseQuery(qs)
- assert q['openid.mode'] == 'associate'
- assert q['openid.assoc_type'] == 'HMAC-SHA1'
- reply_dict = {
- 'assoc_type':'HMAC-SHA1',
- 'assoc_handle':assoc_handle,
- 'expires_in':'600',
- }
-
- if q.get('openid.session_type') == 'DH-SHA1':
- assert len(q) == 6 or len(q) == 4
- message = Message.fromPostArgs(q)
- session = DiffieHellmanSHA1ServerSession.fromMessage(message)
- reply_dict['session_type'] = 'DH-SHA1'
- else:
- assert len(q) == 2
- session = PlainTextServerSession.fromQuery(q)
-
- reply_dict.update(session.answer(assoc_secret))
- return kvform.dictToKV(reply_dict)
-
-
-GOODSIG = "[A Good Signature]"
-
-
-class GoodAssociation:
- expiresIn = 3600
- handle = "-blah-"
-
- def getExpiresIn(self):
- return self.expiresIn
-
- def checkMessageSignature(self, message):
- return message.getArg(OPENID_NS, 'sig') == GOODSIG
-
-
-class GoodAssocStore(memstore.MemoryStore):
- def getAssociation(self, server_url, handle=None):
- return GoodAssociation()
-
-
-class TestFetcher(object):
- def __init__(self, user_url, user_page, (assoc_secret, assoc_handle)):
- self.get_responses = {user_url:self.response(user_url, 200, user_page)}
- self.assoc_secret = assoc_secret
- self.assoc_handle = assoc_handle
- self.num_assocs = 0
-
- def response(self, url, status, body):
- return HTTPResponse(
- final_url=url, status=status, headers={}, body=body)
-
- def fetch(self, url, body=None, headers=None):
- if body is None:
- if url in self.get_responses:
- return self.get_responses[url]
- else:
- try:
- body.index('openid.mode=associate')
- except ValueError:
- pass # fall through
- else:
- assert body.find('DH-SHA1') != -1
- response = associate(
- body, self.assoc_secret, self.assoc_handle)
- self.num_assocs += 1
- return self.response(url, 200, response)
-
- return self.response(url, 404, 'Not found')
-
-def makeFastConsumerSession():
- """
- Create custom DH object so tests run quickly.
- """
- dh = DiffieHellman(100389557, 2)
- return DiffieHellmanSHA1ConsumerSession(dh)
-
-def setConsumerSession(con):
- con.session_types = {'DH-SHA1': makeFastConsumerSession}
-
-def _test_success(server_url, user_url, delegate_url, links, immediate=False):
- store = memstore.MemoryStore()
- if immediate:
- mode = 'checkid_immediate'
- else:
- mode = 'checkid_setup'
-
- endpoint = OpenIDServiceEndpoint()
- endpoint.claimed_id = user_url
- endpoint.server_url = server_url
- endpoint.local_id = delegate_url
- endpoint.type_uris = [OPENID_1_1_TYPE]
-
- fetcher = TestFetcher(None, None, assocs[0])
- fetchers.setDefaultFetcher(fetcher, wrap_exceptions=False)
-
- def run():
- trust_root = consumer_url
-
- consumer = GenericConsumer(store)
- setConsumerSession(consumer)
-
- request = consumer.begin(endpoint)
- return_to = consumer_url
-
- m = request.getMessage(trust_root, return_to, immediate)
-
- redirect_url = request.redirectURL(trust_root, return_to, immediate)
-
- parsed = urlparse.urlparse(redirect_url)
- qs = parsed[4]
- q = parseQuery(qs)
- new_return_to = q['openid.return_to']
- del q['openid.return_to']
- assert q == {
- 'openid.mode':mode,
- 'openid.identity':delegate_url,
- 'openid.trust_root':trust_root,
- 'openid.assoc_handle':fetcher.assoc_handle,
- }, (q, user_url, delegate_url, mode)
-
- assert new_return_to.startswith(return_to)
- assert redirect_url.startswith(server_url)
-
- parsed = urlparse.urlparse(new_return_to)
- query = parseQuery(parsed[4])
- query.update({
- 'openid.mode':'id_res',
- 'openid.return_to':new_return_to,
- 'openid.identity':delegate_url,
- 'openid.assoc_handle':fetcher.assoc_handle,
- })
-
- assoc = store.getAssociation(server_url, fetcher.assoc_handle)
-
- message = Message.fromPostArgs(query)
- message = assoc.signMessage(message)
- info = consumer.complete(message, request.endpoint, new_return_to)
- assert info.status == SUCCESS, info.message
- assert info.identity_url == user_url
-
- assert fetcher.num_assocs == 0
- run()
- assert fetcher.num_assocs == 1
-
- # Test that doing it again uses the existing association
- run()
- assert fetcher.num_assocs == 1
-
- # Another association is created if we remove the existing one
- store.removeAssociation(server_url, fetcher.assoc_handle)
- run()
- assert fetcher.num_assocs == 2
-
- # Test that doing it again uses the existing association
- run()
- assert fetcher.num_assocs == 2
-
-import unittest
-
-http_server_url = 'http://server.example.com/'
-consumer_url = 'http://consumer.example.com/'
-https_server_url = 'https://server.example.com/'
-
-class TestSuccess(unittest.TestCase, CatchLogs):
- server_url = http_server_url
- user_url = 'http://www.example.com/user.html'
- delegate_url = 'http://consumer.example.com/user'
-
- def setUp(self):
- CatchLogs.setUp(self)
- self.links = '<link rel="openid.server" href="%s" />' % (
- self.server_url,)
-
- self.delegate_links = ('<link rel="openid.server" href="%s" />'
- '<link rel="openid.delegate" href="%s" />') % (
- self.server_url, self.delegate_url)
-
- def tearDown(self):
- CatchLogs.tearDown(self)
-
- def test_nodelegate(self):
- _test_success(self.server_url, self.user_url,
- self.user_url, self.links)
-
- def test_nodelegateImmediate(self):
- _test_success(self.server_url, self.user_url,
- self.user_url, self.links, True)
-
- def test_delegate(self):
- _test_success(self.server_url, self.user_url,
- self.delegate_url, self.delegate_links)
-
- def test_delegateImmediate(self):
- _test_success(self.server_url, self.user_url,
- self.delegate_url, self.delegate_links, True)
-
-
-class TestSuccessHTTPS(TestSuccess):
- server_url = https_server_url
-
-
-class TestConstruct(unittest.TestCase):
- def setUp(self):
- self.store_sentinel = object()
-
- def test_construct(self):
- oidc = GenericConsumer(self.store_sentinel)
- self.failUnless(oidc.store is self.store_sentinel)
-
- def test_nostore(self):
- self.failUnlessRaises(TypeError, GenericConsumer)
-
-
-class TestIdRes(unittest.TestCase, CatchLogs):
- consumer_class = GenericConsumer
-
- def setUp(self):
- CatchLogs.setUp(self)
-
- self.store = memstore.MemoryStore()
- self.consumer = self.consumer_class(self.store)
- self.return_to = "nonny"
- self.endpoint = OpenIDServiceEndpoint()
- self.endpoint.claimed_id = self.consumer_id = "consu"
- self.endpoint.server_url = self.server_url = "serlie"
- self.endpoint.local_id = self.server_id = "sirod"
- self.endpoint.type_uris = [OPENID_1_1_TYPE]
-
- def disableDiscoveryVerification(self):
- """Set the discovery verification to a no-op for test cases in
- which we don't care."""
- def dummyVerifyDiscover(_, endpoint):
- return endpoint
- self.consumer._verifyDiscoveryResults = dummyVerifyDiscover
-
- def disableReturnToChecking(self):
- def checkReturnTo(unused1, unused2):
- return True
- self.consumer._checkReturnTo = checkReturnTo
- complete = self.consumer.complete
- def callCompleteWithoutReturnTo(message, endpoint):
- return complete(message, endpoint, None)
- self.consumer.complete = callCompleteWithoutReturnTo
-
-class TestIdResCheckSignature(TestIdRes):
- def setUp(self):
- TestIdRes.setUp(self)
- self.assoc = GoodAssociation()
- self.assoc.handle = "{not_dumb}"
- self.store.storeAssociation(self.endpoint.server_url, self.assoc)
-
- self.message = Message.fromPostArgs({
- 'openid.mode': 'id_res',
- 'openid.identity': '=example',
- 'openid.sig': GOODSIG,
- 'openid.assoc_handle': self.assoc.handle,
- 'openid.signed': 'mode,identity,assoc_handle,signed',
- 'frobboz': 'banzit',
- })
-
-
- def test_sign(self):
- # assoc_handle to assoc with good sig
- self.consumer._idResCheckSignature(self.message,
- self.endpoint.server_url)
-
-
- def test_signFailsWithBadSig(self):
- self.message.setArg(OPENID_NS, 'sig', 'BAD SIGNATURE')
- self.failUnlessRaises(
- ProtocolError, self.consumer._idResCheckSignature,
- self.message, self.endpoint.server_url)
-
-
- def test_stateless(self):
- # assoc_handle missing assoc, consumer._checkAuth returns goodthings
- self.message.setArg(OPENID_NS, "assoc_handle", "dumbHandle")
- self.consumer._processCheckAuthResponse = (
- lambda response, server_url: True)
- self.consumer._makeKVPost = lambda args, server_url: {}
- self.consumer._idResCheckSignature(self.message,
- self.endpoint.server_url)
-
- def test_statelessRaisesError(self):
- # assoc_handle missing assoc, consumer._checkAuth returns goodthings
- self.message.setArg(OPENID_NS, "assoc_handle", "dumbHandle")
- self.consumer._checkAuth = lambda unused1, unused2: False
- self.failUnlessRaises(
- ProtocolError, self.consumer._idResCheckSignature,
- self.message, self.endpoint.server_url)
-
- def test_stateless_noStore(self):
- # assoc_handle missing assoc, consumer._checkAuth returns goodthings
- self.message.setArg(OPENID_NS, "assoc_handle", "dumbHandle")
- self.consumer.store = None
- self.consumer._processCheckAuthResponse = (
- lambda response, server_url: True)
- self.consumer._makeKVPost = lambda args, server_url: {}
- self.consumer._idResCheckSignature(self.message,
- self.endpoint.server_url)
-
- def test_statelessRaisesError_noStore(self):
- # assoc_handle missing assoc, consumer._checkAuth returns goodthings
- self.message.setArg(OPENID_NS, "assoc_handle", "dumbHandle")
- self.consumer._checkAuth = lambda unused1, unused2: False
- self.consumer.store = None
- self.failUnlessRaises(
- ProtocolError, self.consumer._idResCheckSignature,
- self.message, self.endpoint.server_url)
-
-
-class TestQueryFormat(TestIdRes):
- def test_notAList(self):
- # XXX: should be a Message object test, not a consumer test
-
- # Value should be a single string. If it's a list, it should generate
- # an exception.
- query = {'openid.mode': ['cancel']}
- try:
- r = Message.fromPostArgs(query)
- except TypeError, err:
- self.failUnless(str(err).find('values') != -1, err)
- else:
- self.fail("expected TypeError, got this instead: %s" % (r,))
-
-class TestComplete(TestIdRes):
- """Testing GenericConsumer.complete.
-
- Other TestIdRes subclasses test more specific aspects.
- """
-
- def test_setupNeededIdRes(self):
- message = Message.fromOpenIDArgs({'mode': 'id_res'})
- setup_url_sentinel = object()
-
- def raiseSetupNeeded(msg):
- self.failUnless(msg is message)
- raise SetupNeededError(setup_url_sentinel)
-
- self.consumer._checkSetupNeeded = raiseSetupNeeded
-
- response = self.consumer.complete(message, None, None)
- self.failUnlessEqual(SETUP_NEEDED, response.status)
- self.failUnless(setup_url_sentinel is response.setup_url)
-
- def test_cancel(self):
- message = Message.fromPostArgs({'openid.mode': 'cancel'})
- self.disableReturnToChecking()
- r = self.consumer.complete(message, self.endpoint)
- self.failUnlessEqual(r.status, CANCEL)
- self.failUnless(r.identity_url == self.endpoint.claimed_id)
-
- def test_cancel_with_return_to(self):
- message = Message.fromPostArgs({'openid.mode': 'cancel'})
- r = self.consumer.complete(message, self.endpoint, self.return_to)
- self.failUnlessEqual(r.status, CANCEL)
- self.failUnless(r.identity_url == self.endpoint.claimed_id)
-
- def test_error(self):
- msg = 'an error message'
- message = Message.fromPostArgs({'openid.mode': 'error',
- 'openid.error': msg,
- })
- self.disableReturnToChecking()
- r = self.consumer.complete(message, self.endpoint)
- self.failUnlessEqual(r.status, FAILURE)
- self.failUnless(r.identity_url == self.endpoint.claimed_id)
- self.failUnlessEqual(r.message, msg)
-
- def test_errorWithNoOptionalKeys(self):
- msg = 'an error message'
- contact = 'some contact info here'
- message = Message.fromPostArgs({'openid.mode': 'error',
- 'openid.error': msg,
- 'openid.contact': contact,
- })
- self.disableReturnToChecking()
- r = self.consumer.complete(message, self.endpoint)
- self.failUnlessEqual(r.status, FAILURE)
- self.failUnless(r.identity_url == self.endpoint.claimed_id)
- self.failUnless(r.contact == contact)
- self.failUnless(r.reference is None)
- self.failUnlessEqual(r.message, msg)
-
- def test_errorWithOptionalKeys(self):
- msg = 'an error message'
- contact = 'me'
- reference = 'support ticket'
- message = Message.fromPostArgs({'openid.mode': 'error',
- 'openid.error': msg, 'openid.reference': reference,
- 'openid.contact': contact, 'openid.ns': OPENID2_NS,
- })
- r = self.consumer.complete(message, self.endpoint, None)
- self.failUnlessEqual(r.status, FAILURE)
- self.failUnless(r.identity_url == self.endpoint.claimed_id)
- self.failUnless(r.contact == contact)
- self.failUnless(r.reference == reference)
- self.failUnlessEqual(r.message, msg)
-
- def test_noMode(self):
- message = Message.fromPostArgs({})
- r = self.consumer.complete(message, self.endpoint, None)
- self.failUnlessEqual(r.status, FAILURE)
- self.failUnless(r.identity_url == self.endpoint.claimed_id)
-
- def test_idResMissingField(self):
- # XXX - this test is passing, but not necessarily by what it
- # is supposed to test for. status in FAILURE, but it's because
- # *check_auth* failed, not because it's missing an arg, exactly.
- message = Message.fromPostArgs({'openid.mode': 'id_res'})
- self.failUnlessRaises(ProtocolError, self.consumer._doIdRes,
- message, self.endpoint, None)
-
- def test_idResURLMismatch(self):
- class VerifiedError(Exception): pass
-
- def discoverAndVerify(claimed_id, _to_match_endpoints):
- raise VerifiedError
-
- self.consumer._discoverAndVerify = discoverAndVerify
- self.disableReturnToChecking()
-
- message = Message.fromPostArgs(
- {'openid.mode': 'id_res',
- 'openid.return_to': 'return_to (just anything)',
- 'openid.identity': 'something wrong (not self.consumer_id)',
- 'openid.assoc_handle': 'does not matter',
- 'openid.sig': GOODSIG,
- 'openid.signed': 'identity,return_to',
- })
- self.consumer.store = GoodAssocStore()
-
- self.failUnlessRaises(VerifiedError,
- self.consumer.complete,
- message, self.endpoint)
-
- self.failUnlessLogMatches('Error attempting to use stored',
- 'Attempting discovery')
-
-class TestCompleteMissingSig(unittest.TestCase, CatchLogs):
-
- def setUp(self):
- self.store = GoodAssocStore()
- self.consumer = GenericConsumer(self.store)
- self.server_url = "http://idp.unittest/"
- CatchLogs.setUp(self)
-
- claimed_id = 'bogus.claimed'
-
- self.message = Message.fromOpenIDArgs(
- {'mode': 'id_res',
- 'return_to': 'return_to (just anything)',
- 'identity': claimed_id,
- 'assoc_handle': 'does not matter',
- 'sig': GOODSIG,
- 'response_nonce': mkNonce(),
- 'signed': 'identity,return_to,response_nonce,assoc_handle,claimed_id,op_endpoint',
- 'claimed_id': claimed_id,
- 'op_endpoint': self.server_url,
- 'ns':OPENID2_NS,
- })
-
- self.endpoint = OpenIDServiceEndpoint()
- self.endpoint.server_url = self.server_url
- self.endpoint.claimed_id = claimed_id
- self.consumer._checkReturnTo = lambda unused1, unused2 : True
-
- def tearDown(self):
- CatchLogs.tearDown(self)
-
-
- def test_idResMissingNoSigs(self):
- def _vrfy(resp_msg, endpoint=None):
- return endpoint
-
- self.consumer._verifyDiscoveryResults = _vrfy
- r = self.consumer.complete(self.message, self.endpoint, None)
- self.failUnlessSuccess(r)
-
-
- def test_idResNoIdentity(self):
- self.message.delArg(OPENID_NS, 'identity')
- self.message.delArg(OPENID_NS, 'claimed_id')
- self.endpoint.claimed_id = None
- self.message.setArg(OPENID_NS, 'signed', 'return_to,response_nonce,assoc_handle,op_endpoint')
- r = self.consumer.complete(self.message, self.endpoint, None)
- self.failUnlessSuccess(r)
-
-
- def test_idResMissingIdentitySig(self):
- self.message.setArg(OPENID_NS, 'signed', 'return_to,response_nonce,assoc_handle,claimed_id')
- r = self.consumer.complete(self.message, self.endpoint, None)
- self.failUnlessEqual(r.status, FAILURE)
-
-
- def test_idResMissingReturnToSig(self):
- self.message.setArg(OPENID_NS, 'signed', 'identity,response_nonce,assoc_handle,claimed_id')
- r = self.consumer.complete(self.message, self.endpoint, None)
- self.failUnlessEqual(r.status, FAILURE)
-
-
- def test_idResMissingAssocHandleSig(self):
- self.message.setArg(OPENID_NS, 'signed', 'identity,response_nonce,return_to,claimed_id')
- r = self.consumer.complete(self.message, self.endpoint, None)
- self.failUnlessEqual(r.status, FAILURE)
-
-
- def test_idResMissingClaimedIDSig(self):
- self.message.setArg(OPENID_NS, 'signed', 'identity,response_nonce,return_to,assoc_handle')
- r = self.consumer.complete(self.message, self.endpoint, None)
- self.failUnlessEqual(r.status, FAILURE)
-
-
- def failUnlessSuccess(self, response):
- if response.status != SUCCESS:
- self.fail("Non-successful response: %s" % (response,))
-
-
-
-class TestCheckAuthResponse(TestIdRes, CatchLogs):
- def setUp(self):
- CatchLogs.setUp(self)
- TestIdRes.setUp(self)
-
- def tearDown(self):
- CatchLogs.tearDown(self)
-
- def _createAssoc(self):
- issued = time.time()
- lifetime = 1000
- assoc = association.Association(
- 'handle', 'secret', issued, lifetime, 'HMAC-SHA1')
- store = self.consumer.store
- store.storeAssociation(self.server_url, assoc)
- assoc2 = store.getAssociation(self.server_url)
- self.failUnlessEqual(assoc, assoc2)
-
- def test_goodResponse(self):
- """successful response to check_authentication"""
- response = Message.fromOpenIDArgs({'is_valid':'true',})
- r = self.consumer._processCheckAuthResponse(response, self.server_url)
- self.failUnless(r)
-
- def test_missingAnswer(self):
- """check_authentication returns false when the server sends no answer"""
- response = Message.fromOpenIDArgs({})
- r = self.consumer._processCheckAuthResponse(response, self.server_url)
- self.failIf(r)
-
- def test_badResponse(self):
- """check_authentication returns false when is_valid is false"""
- response = Message.fromOpenIDArgs({'is_valid':'false',})
- r = self.consumer._processCheckAuthResponse(response, self.server_url)
- self.failIf(r)
-
- def test_badResponseInvalidate(self):
- """Make sure that the handle is invalidated when is_valid is false
-
- From "Verifying directly with the OpenID Provider"::
-
- If the OP responds with "is_valid" set to "true", and
- "invalidate_handle" is present, the Relying Party SHOULD
- NOT send further authentication requests with that handle.
- """
- self._createAssoc()
- response = Message.fromOpenIDArgs({
- 'is_valid':'false',
- 'invalidate_handle':'handle',
- })
- r = self.consumer._processCheckAuthResponse(response, self.server_url)
- self.failIf(r)
- self.failUnless(
- self.consumer.store.getAssociation(self.server_url) is None)
-
- def test_invalidateMissing(self):
- """invalidate_handle with a handle that is not present"""
- response = Message.fromOpenIDArgs({
- 'is_valid':'true',
- 'invalidate_handle':'missing',
- })
- r = self.consumer._processCheckAuthResponse(response, self.server_url)
- self.failUnless(r)
- self.failUnlessLogMatches(
- 'Received "invalidate_handle"'
- )
-
- def test_invalidateMissing_noStore(self):
- """invalidate_handle with a handle that is not present"""
- response = Message.fromOpenIDArgs({
- 'is_valid':'true',
- 'invalidate_handle':'missing',
- })
- self.consumer.store = None
- r = self.consumer._processCheckAuthResponse(response, self.server_url)
- self.failUnless(r)
- self.failUnlessLogMatches(
- 'Received "invalidate_handle"',
- 'Unexpectedly got invalidate_handle without a store')
-
- def test_invalidatePresent(self):
- """invalidate_handle with a handle that exists
-
- From "Verifying directly with the OpenID Provider"::
-
- If the OP responds with "is_valid" set to "true", and
- "invalidate_handle" is present, the Relying Party SHOULD
- NOT send further authentication requests with that handle.
- """
- self._createAssoc()
- response = Message.fromOpenIDArgs({
- 'is_valid':'true',
- 'invalidate_handle':'handle',
- })
- r = self.consumer._processCheckAuthResponse(response, self.server_url)
- self.failUnless(r)
- self.failUnless(
- self.consumer.store.getAssociation(self.server_url) is None)
-
-class TestSetupNeeded(TestIdRes):
- def failUnlessSetupNeeded(self, expected_setup_url, message):
- try:
- self.consumer._checkSetupNeeded(message)
- except SetupNeededError, why:
- self.failUnlessEqual(expected_setup_url, why.user_setup_url)
- else:
- self.fail("Expected to find an immediate-mode response")
-
- def test_setupNeededOpenID1(self):
- """The minimum conditions necessary to trigger Setup Needed"""
- setup_url = 'http://unittest/setup-here'
- message = Message.fromPostArgs({
- 'openid.mode': 'id_res',
- 'openid.user_setup_url': setup_url,
- })
- self.failUnless(message.isOpenID1())
- self.failUnlessSetupNeeded(setup_url, message)
-
- def test_setupNeededOpenID1_extra(self):
- """Extra stuff along with setup_url still trigger Setup Needed"""
- setup_url = 'http://unittest/setup-here'
- message = Message.fromPostArgs({
- 'openid.mode': 'id_res',
- 'openid.user_setup_url': setup_url,
- 'openid.identity': 'bogus',
- })
- self.failUnless(message.isOpenID1())
- self.failUnlessSetupNeeded(setup_url, message)
-
- def test_noSetupNeededOpenID1(self):
- """When the user_setup_url is missing on an OpenID 1 message,
- we assume that it's not a cancel response to checkid_immediate"""
- message = Message.fromOpenIDArgs({'mode': 'id_res'})
- self.failUnless(message.isOpenID1())
-
- # No SetupNeededError raised
- self.consumer._checkSetupNeeded(message)
-
- def test_setupNeededOpenID2(self):
- message = Message.fromOpenIDArgs({
- 'mode':'setup_needed',
- 'ns':OPENID2_NS,
- })
- self.failUnless(message.isOpenID2())
- response = self.consumer.complete(message, None, None)
- self.failUnlessEqual('setup_needed', response.status)
- self.failUnlessEqual(None, response.setup_url)
-
- def test_setupNeededDoesntWorkForOpenID1(self):
- message = Message.fromOpenIDArgs({
- 'mode':'setup_needed',
- })
-
- # No SetupNeededError raised
- self.consumer._checkSetupNeeded(message)
-
- response = self.consumer.complete(message, None, None)
- self.failUnlessEqual('failure', response.status)
- self.failUnless(response.message.startswith('Invalid openid.mode'))
-
- def test_noSetupNeededOpenID2(self):
- message = Message.fromOpenIDArgs({
- 'mode':'id_res',
- 'game':'puerto_rico',
- 'ns':OPENID2_NS,
- })
- self.failUnless(message.isOpenID2())
-
- # No SetupNeededError raised
- self.consumer._checkSetupNeeded(message)
-
-class IdResCheckForFieldsTest(TestIdRes):
- def setUp(self):
- self.consumer = GenericConsumer(None)
-
- def mkSuccessTest(openid_args, signed_list):
- def test(self):
- message = Message.fromOpenIDArgs(openid_args)
- message.setArg(OPENID_NS, 'signed', ','.join(signed_list))
- self.consumer._idResCheckForFields(message)
- return test
-
- test_openid1Success = mkSuccessTest(
- {'return_to':'return',
- 'assoc_handle':'assoc handle',
- 'sig':'a signature',
- 'identity':'someone',
- },
- ['return_to', 'identity'])
-
- test_openid2Success = mkSuccessTest(
- {'ns':OPENID2_NS,
- 'return_to':'return',
- 'assoc_handle':'assoc handle',
- 'sig':'a signature',
- 'op_endpoint':'my favourite server',
- 'response_nonce':'use only once',
- },
- ['return_to', 'response_nonce', 'assoc_handle', 'op_endpoint'])
-
- test_openid2Success_identifiers = mkSuccessTest(
- {'ns':OPENID2_NS,
- 'return_to':'return',
- 'assoc_handle':'assoc handle',
- 'sig':'a signature',
- 'claimed_id':'i claim to be me',
- 'identity':'my server knows me as me',
- 'op_endpoint':'my favourite server',
- 'response_nonce':'use only once',
- },
- ['return_to', 'response_nonce', 'identity',
- 'claimed_id', 'assoc_handle', 'op_endpoint'])
-
- def mkMissingFieldTest(openid_args):
- def test(self):
- message = Message.fromOpenIDArgs(openid_args)
- try:
- self.consumer._idResCheckForFields(message)
- except ProtocolError, why:
- self.failUnless(why[0].startswith('Missing required'))
- else:
- self.fail('Expected an error, but none occurred')
- return test
-
- def mkMissingSignedTest(openid_args):
- def test(self):
- message = Message.fromOpenIDArgs(openid_args)
- try:
- self.consumer._idResCheckForFields(message)
- except ProtocolError, why:
- self.failUnless(why[0].endswith('not signed'))
- else:
- self.fail('Expected an error, but none occurred')
- return test
-
- test_openid1Missing_returnToSig = mkMissingSignedTest(
- {'return_to':'return',
- 'assoc_handle':'assoc handle',
- 'sig':'a signature',
- 'identity':'someone',
- 'signed':'identity',
- })
-
- test_openid1Missing_identitySig = mkMissingSignedTest(
- {'return_to':'return',
- 'assoc_handle':'assoc handle',
- 'sig':'a signature',
- 'identity':'someone',
- 'signed':'return_to'
- })
-
- test_openid2Missing_opEndpointSig = mkMissingSignedTest(
- {'ns':OPENID2_NS,
- 'return_to':'return',
- 'assoc_handle':'assoc handle',
- 'sig':'a signature',
- 'identity':'someone',
- 'op_endpoint':'the endpoint',
- 'signed':'return_to,identity,assoc_handle'
- })
-
- test_openid1MissingReturnTo = mkMissingFieldTest(
- {'assoc_handle':'assoc handle',
- 'sig':'a signature',
- 'identity':'someone',
- })
-
- test_openid1MissingAssocHandle = mkMissingFieldTest(
- {'return_to':'return',
- 'sig':'a signature',
- 'identity':'someone',
- })
-
- # XXX: I could go on...
-
-class CheckAuthHappened(Exception): pass
-
-class CheckNonceVerifyTest(TestIdRes, CatchLogs):
- def setUp(self):
- CatchLogs.setUp(self)
- TestIdRes.setUp(self)
- self.consumer.openid1_nonce_query_arg_name = 'nonce'
-
- def tearDown(self):
- CatchLogs.tearDown(self)
-
- def test_openid1Success(self):
- """use consumer-generated nonce"""
- nonce_value = mkNonce()
- self.return_to = 'http://rt.unittest/?nonce=%s' % (nonce_value,)
- self.response = Message.fromOpenIDArgs({'return_to': self.return_to})
- self.response.setArg(BARE_NS, 'nonce', nonce_value)
- self.consumer._idResCheckNonce(self.response, self.endpoint)
- self.failUnlessLogEmpty()
-
- def test_openid1Missing(self):
- """use consumer-generated nonce"""
- self.response = Message.fromOpenIDArgs({})
- n = self.consumer._idResGetNonceOpenID1(self.response, self.endpoint)
- self.failUnless(n is None, n)
- self.failUnlessLogEmpty()
-
- def test_consumerNonceOpenID2(self):
- """OpenID 2 does not use consumer-generated nonce"""
- self.return_to = 'http://rt.unittest/?nonce=%s' % (mkNonce(),)
- self.response = Message.fromOpenIDArgs(
- {'return_to': self.return_to, 'ns':OPENID2_NS})
- self.failUnlessRaises(ProtocolError, self.consumer._idResCheckNonce,
- self.response, self.endpoint)
- self.failUnlessLogEmpty()
-
- def test_serverNonce(self):
- """use server-generated nonce"""
- self.response = Message.fromOpenIDArgs(
- {'ns':OPENID2_NS, 'response_nonce': mkNonce(),})
- self.consumer._idResCheckNonce(self.response, self.endpoint)
- self.failUnlessLogEmpty()
-
- def test_serverNonceOpenID1(self):
- """OpenID 1 does not use server-generated nonce"""
- self.response = Message.fromOpenIDArgs(
- {'ns':OPENID1_NS,
- 'return_to': 'http://return.to/',
- 'response_nonce': mkNonce(),})
- self.failUnlessRaises(ProtocolError, self.consumer._idResCheckNonce,
- self.response, self.endpoint)
- self.failUnlessLogEmpty()
-
- def test_badNonce(self):
- """remove the nonce from the store
-
- From "Checking the Nonce"::
-
- When the Relying Party checks the signature on an assertion, the
-
- Relying Party SHOULD ensure that an assertion has not yet
- been accepted with the same value for "openid.response_nonce"
- from the same OP Endpoint URL.
- """
- nonce = mkNonce()
- stamp, salt = splitNonce(nonce)
- self.store.useNonce(self.server_url, stamp, salt)
- self.response = Message.fromOpenIDArgs(
- {'response_nonce': nonce,
- 'ns':OPENID2_NS,
- })
- self.failUnlessRaises(ProtocolError, self.consumer._idResCheckNonce,
- self.response, self.endpoint)
-
- def test_successWithNoStore(self):
- """When there is no store, checking the nonce succeeds"""
- self.consumer.store = None
- self.response = Message.fromOpenIDArgs(
- {'response_nonce': mkNonce(),
- 'ns':OPENID2_NS,
- })
- self.consumer._idResCheckNonce(self.response, self.endpoint)
- self.failUnlessLogEmpty()
-
- def test_tamperedNonce(self):
- """Malformed nonce"""
- self.response = Message.fromOpenIDArgs(
- {'ns':OPENID2_NS,
- 'response_nonce':'malformed'})
- self.failUnlessRaises(ProtocolError, self.consumer._idResCheckNonce,
- self.response, self.endpoint)
-
- def test_missingNonce(self):
- """no nonce parameter on the return_to"""
- self.response = Message.fromOpenIDArgs(
- {'return_to': self.return_to})
- self.failUnlessRaises(ProtocolError, self.consumer._idResCheckNonce,
- self.response, self.endpoint)
-
-class CheckAuthDetectingConsumer(GenericConsumer):
- def _checkAuth(self, *args):
- raise CheckAuthHappened(args)
-
- def _idResCheckNonce(self, *args):
- """We're not testing nonce-checking, so just return success
- when it asks."""
- return True
-
-class TestCheckAuthTriggered(TestIdRes, CatchLogs):
- consumer_class = CheckAuthDetectingConsumer
-
- def setUp(self):
- TestIdRes.setUp(self)
- CatchLogs.setUp(self)
- self.disableDiscoveryVerification()
-
- def test_checkAuthTriggered(self):
- message = Message.fromPostArgs({
- 'openid.return_to':self.return_to,
- 'openid.identity':self.server_id,
- 'openid.assoc_handle':'not_found',
- 'openid.sig': GOODSIG,
- 'openid.signed': 'identity,return_to',
- })
- self.disableReturnToChecking()
- try:
- result = self.consumer._doIdRes(message, self.endpoint, None)
- except CheckAuthHappened:
- pass
- else:
- self.fail('_checkAuth did not happen. Result was: %r %s' %
- (result, self.messages))
-
- def test_checkAuthTriggeredWithAssoc(self):
- # Store an association for this server that does not match the
- # handle that is in the message
- issued = time.time()
- lifetime = 1000
- assoc = association.Association(
- 'handle', 'secret', issued, lifetime, 'HMAC-SHA1')
- self.store.storeAssociation(self.server_url, assoc)
- self.disableReturnToChecking()
- message = Message.fromPostArgs({
- 'openid.return_to':self.return_to,
- 'openid.identity':self.server_id,
- 'openid.assoc_handle':'not_found',
- 'openid.sig': GOODSIG,
- 'openid.signed': 'identity,return_to',
- })
- try:
- result = self.consumer._doIdRes(message, self.endpoint, None)
- except CheckAuthHappened:
- pass
- else:
- self.fail('_checkAuth did not happen. Result was: %r' % (result,))
-
- def test_expiredAssoc(self):
- # Store an expired association for the server with the handle
- # that is in the message
- issued = time.time() - 10
- lifetime = 0
- handle = 'handle'
- assoc = association.Association(
- handle, 'secret', issued, lifetime, 'HMAC-SHA1')
- self.failUnless(assoc.expiresIn <= 0)
- self.store.storeAssociation(self.server_url, assoc)
-
- message = Message.fromPostArgs({
- 'openid.return_to':self.return_to,
- 'openid.identity':self.server_id,
- 'openid.assoc_handle':handle,
- 'openid.sig': GOODSIG,
- 'openid.signed': 'identity,return_to',
- })
- self.disableReturnToChecking()
- self.failUnlessRaises(ProtocolError, self.consumer._doIdRes,
- message, self.endpoint, None)
-
- def test_newerAssoc(self):
- lifetime = 1000
-
- good_issued = time.time() - 10
- good_handle = 'handle'
- good_assoc = association.Association(
- good_handle, 'secret', good_issued, lifetime, 'HMAC-SHA1')
- self.store.storeAssociation(self.server_url, good_assoc)
-
- bad_issued = time.time() - 5
- bad_handle = 'handle2'
- bad_assoc = association.Association(
- bad_handle, 'secret', bad_issued, lifetime, 'HMAC-SHA1')
- self.store.storeAssociation(self.server_url, bad_assoc)
-
- query = {
- 'return_to':self.return_to,
- 'identity':self.server_id,
- 'assoc_handle':good_handle,
- }
-
- message = Message.fromOpenIDArgs(query)
- message = good_assoc.signMessage(message)
- self.disableReturnToChecking()
- info = self.consumer._doIdRes(message, self.endpoint, None)
- self.failUnlessEqual(info.status, SUCCESS, info.message)
- self.failUnlessEqual(self.consumer_id, info.identity_url)
-
-
-
-class TestReturnToArgs(unittest.TestCase):
- """Verifying the Return URL paramaters.
- From the specification "Verifying the Return URL"::
-
- To verify that the "openid.return_to" URL matches the URL that is
- processing this assertion:
-
- - The URL scheme, authority, and path MUST be the same between the
- two URLs.
-
- - Any query parameters that are present in the "openid.return_to"
- URL MUST also be present with the same values in the
- accepting URL.
-
- XXX: So far we have only tested the second item on the list above.
- XXX: _verifyReturnToArgs is not invoked anywhere.
- """
-
- def setUp(self):
- store = object()
- self.consumer = GenericConsumer(store)
-
- def test_returnToArgsOkay(self):
- query = {
- 'openid.mode': 'id_res',
- 'openid.return_to': 'http://example.com/?foo=bar',
- 'foo': 'bar',
- }
- # no return value, success is assumed if there are no exceptions.
- self.consumer._verifyReturnToArgs(query)
-
- def test_returnToArgsUnexpectedArg(self):
- query = {
- 'openid.mode': 'id_res',
- 'openid.return_to': 'http://example.com/',
- 'foo': 'bar',
- }
- # no return value, success is assumed if there are no exceptions.
- self.failUnlessRaises(ProtocolError,
- self.consumer._verifyReturnToArgs, query)
-
- def test_returnToMismatch(self):
- query = {
- 'openid.mode': 'id_res',
- 'openid.return_to': 'http://example.com/?foo=bar',
- }
- # fail, query has no key 'foo'.
- self.failUnlessRaises(ValueError,
- self.consumer._verifyReturnToArgs, query)
-
- query['foo'] = 'baz'
- # fail, values for 'foo' do not match.
- self.failUnlessRaises(ValueError,
- self.consumer._verifyReturnToArgs, query)
-
-
- def test_noReturnTo(self):
- query = {'openid.mode': 'id_res'}
- self.failUnlessRaises(ValueError,
- self.consumer._verifyReturnToArgs, query)
-
- def test_completeBadReturnTo(self):
- """Test GenericConsumer.complete()'s handling of bad return_to
- values.
- """
- return_to = "http://some.url/path?foo=bar"
-
- # Scheme, authority, and path differences are checked by
- # GenericConsumer._checkReturnTo. Query args checked by
- # GenericConsumer._verifyReturnToArgs.
- bad_return_tos = [
- # Scheme only
- "https://some.url/path?foo=bar",
- # Authority only
- "http://some.url.invalid/path?foo=bar",
- # Path only
- "http://some.url/path_extra?foo=bar",
- # Query args differ
- "http://some.url/path?foo=bar2",
- "http://some.url/path?foo2=bar",
- ]
-
- m = Message(OPENID1_NS)
- m.setArg(OPENID_NS, 'mode', 'cancel')
- m.setArg(BARE_NS, 'foo', 'bar')
- endpoint = None
-
- for bad in bad_return_tos:
- m.setArg(OPENID_NS, 'return_to', bad)
- self.failIf(self.consumer._checkReturnTo(m, return_to))
-
- def test_completeGoodReturnTo(self):
- """Test GenericConsumer.complete()'s handling of good
- return_to values.
- """
- return_to = "http://some.url/path"
-
- good_return_tos = [
- (return_to, {}),
- (return_to + "?another=arg", {(BARE_NS, 'another'): 'arg'}),
- (return_to + "?another=arg#fragment", {(BARE_NS, 'another'): 'arg'}),
- ("HTTP"+return_to[4:], {}),
- (return_to.replace('url','URL'), {}),
- ("http://some.url:80/path", {}),
- ("http://some.url/p%61th", {}),
- ("http://some.url/./path", {}),
- ]
-
- endpoint = None
-
- for good, extra in good_return_tos:
- m = Message(OPENID1_NS)
- m.setArg(OPENID_NS, 'mode', 'cancel')
-
- for ns, key in extra:
- m.setArg(ns, key, extra[(ns, key)])
-
- m.setArg(OPENID_NS, 'return_to', good)
- result = self.consumer.complete(m, endpoint, return_to)
- self.failUnless(isinstance(result, CancelResponse), \
- "Expected CancelResponse, got %r for %s" % (result, good,))
-
-class MockFetcher(object):
- def __init__(self, response=None):
- self.response = response or HTTPResponse()
- self.fetches = []
-
- def fetch(self, url, body=None, headers=None):
- self.fetches.append((url, body, headers))
- return self.response
-
-class ExceptionRaisingMockFetcher(object):
- class MyException(Exception):
- pass
-
- def fetch(self, url, body=None, headers=None):
- raise self.MyException('mock fetcher exception')
-
-class BadArgCheckingConsumer(GenericConsumer):
- def _makeKVPost(self, args, _):
- assert args == {
- 'openid.mode':'check_authentication',
- 'openid.signed':'foo',
- 'openid.ns':OPENID1_NS
- }, args
- return None
-
-class TestCheckAuth(unittest.TestCase, CatchLogs):
- consumer_class = GenericConsumer
-
- def setUp(self):
- CatchLogs.setUp(self)
- self.store = memstore.MemoryStore()
-
- self.consumer = self.consumer_class(self.store)
-
- self._orig_fetcher = fetchers.getDefaultFetcher()
- self.fetcher = MockFetcher()
- fetchers.setDefaultFetcher(self.fetcher)
-
- def tearDown(self):
- CatchLogs.tearDown(self)
- fetchers.setDefaultFetcher(self._orig_fetcher, wrap_exceptions=False)
-
- def test_error(self):
- self.fetcher.response = HTTPResponse(
- "http://some_url", 404, {'Hea': 'der'}, 'blah:blah\n')
- query = {'openid.signed': 'stuff',
- 'openid.stuff':'a value'}
- r = self.consumer._checkAuth(Message.fromPostArgs(query),
- http_server_url)
- self.failIf(r)
- self.failUnless(self.messages)
-
- def test_bad_args(self):
- query = {
- 'openid.signed':'foo',
- 'closid.foo':'something',
- }
- consumer = BadArgCheckingConsumer(self.store)
- consumer._checkAuth(Message.fromPostArgs(query), 'does://not.matter')
-
-
- def test_signedList(self):
- query = Message.fromOpenIDArgs({
- 'mode': 'id_res',
- 'sig': 'rabbits',
- 'identity': '=example',
- 'assoc_handle': 'munchkins',
- 'ns.sreg': 'urn:sreg',
- 'sreg.email': 'bogus@example.com',
- 'signed': 'identity,mode,ns.sreg,sreg.email',
- 'foo': 'bar',
- })
- args = self.consumer._createCheckAuthRequest(query)
- self.failUnless(args.isOpenID1())
- for signed_arg in query.getArg(OPENID_NS, 'signed').split(','):
- self.failUnless(args.getAliasedArg(signed_arg), signed_arg)
-
- def test_112(self):
- args = {'openid.assoc_handle': 'fa1f5ff0-cde4-11dc-a183-3714bfd55ca8',
- 'openid.claimed_id': 'http://binkley.lan/user/test01',
- 'openid.identity': 'http://test01.binkley.lan/',
- 'openid.mode': 'id_res',
- 'openid.ns': 'http://specs.openid.net/auth/2.0',
- 'openid.ns.pape': 'http://specs.openid.net/extensions/pape/1.0',
- 'openid.op_endpoint': 'http://binkley.lan/server',
- 'openid.pape.auth_policies': 'none',
- 'openid.pape.auth_time': '2008-01-28T20:42:36Z',
- 'openid.pape.nist_auth_level': '0',
- 'openid.response_nonce': '2008-01-28T21:07:04Z99Q=',
- 'openid.return_to': 'http://binkley.lan:8001/process?janrain_nonce=2008-01-28T21%3A07%3A02Z0tMIKx',
- 'openid.sig': 'YJlWH4U6SroB1HoPkmEKx9AyGGg=',
- 'openid.signed': 'assoc_handle,identity,response_nonce,return_to,claimed_id,op_endpoint,pape.auth_time,ns.pape,pape.nist_auth_level,pape.auth_policies'
- }
- self.failUnlessEqual(OPENID2_NS, args['openid.ns'])
- incoming = Message.fromPostArgs(args)
- self.failUnless(incoming.isOpenID2())
- car = self.consumer._createCheckAuthRequest(incoming)
- expected_args = args.copy()
- expected_args['openid.mode'] = 'check_authentication'
- expected =Message.fromPostArgs(expected_args)
- self.failUnless(expected.isOpenID2())
- self.failUnlessEqual(expected, car)
- self.failUnlessEqual(expected_args, car.toPostArgs())
-
-
-
-class TestFetchAssoc(unittest.TestCase, CatchLogs):
- consumer_class = GenericConsumer
-
- def setUp(self):
- CatchLogs.setUp(self)
- self.store = memstore.MemoryStore()
- self.fetcher = MockFetcher()
- fetchers.setDefaultFetcher(self.fetcher)
- self.consumer = self.consumer_class(self.store)
-
- def test_error_404(self):
- """404 from a kv post raises HTTPFetchingError"""
- self.fetcher.response = HTTPResponse(
- "http://some_url", 404, {'Hea': 'der'}, 'blah:blah\n')
- self.failUnlessRaises(
- fetchers.HTTPFetchingError,
- self.consumer._makeKVPost,
- Message.fromPostArgs({'mode':'associate'}),
- "http://server_url")
-
- def test_error_exception_unwrapped(self):
- """Ensure that exceptions are bubbled through from fetchers
- when making associations
- """
- self.fetcher = ExceptionRaisingMockFetcher()
- fetchers.setDefaultFetcher(self.fetcher, wrap_exceptions=False)
- self.failUnlessRaises(self.fetcher.MyException,
- self.consumer._makeKVPost,
- Message.fromPostArgs({'mode':'associate'}),
- "http://server_url")
-
- # exception fetching returns no association
- e = OpenIDServiceEndpoint()
- e.server_url = 'some://url'
- self.failUnlessRaises(self.fetcher.MyException,
- self.consumer._getAssociation, e)
-
- self.failUnlessRaises(self.fetcher.MyException,
- self.consumer._checkAuth,
- Message.fromPostArgs({'openid.signed':''}),
- 'some://url')
-
- def test_error_exception_wrapped(self):
- """Ensure that openid.fetchers.HTTPFetchingError is caught by
- the association creation stuff.
- """
- self.fetcher = ExceptionRaisingMockFetcher()
- # This will wrap exceptions!
- fetchers.setDefaultFetcher(self.fetcher)
- self.failUnlessRaises(fetchers.HTTPFetchingError,
- self.consumer._makeKVPost,
- Message.fromOpenIDArgs({'mode':'associate'}),
- "http://server_url")
-
- # exception fetching returns no association
- e = OpenIDServiceEndpoint()
- e.server_url = 'some://url'
- self.failUnless(self.consumer._getAssociation(e) is None)
-
- msg = Message.fromPostArgs({'openid.signed':''})
- self.failIf(self.consumer._checkAuth(msg, 'some://url'))
-
-
-class TestSuccessResponse(unittest.TestCase):
- def setUp(self):
- self.endpoint = OpenIDServiceEndpoint()
- self.endpoint.claimed_id = 'identity_url'
-
- def test_extensionResponse(self):
- resp = mkSuccess(self.endpoint, {
- 'ns.sreg':'urn:sreg',
- 'ns.unittest':'urn:unittest',
- 'unittest.one':'1',
- 'unittest.two':'2',
- 'sreg.nickname':'j3h',
- 'return_to':'return_to',
- })
- utargs = resp.extensionResponse('urn:unittest', False)
- self.failUnlessEqual(utargs, {'one':'1', 'two':'2'})
- sregargs = resp.extensionResponse('urn:sreg', False)
- self.failUnlessEqual(sregargs, {'nickname':'j3h'})
-
- def test_extensionResponseSigned(self):
- args = {
- 'ns.sreg':'urn:sreg',
- 'ns.unittest':'urn:unittest',
- 'unittest.one':'1',
- 'unittest.two':'2',
- 'sreg.nickname':'j3h',
- 'sreg.dob':'yesterday',
- 'return_to':'return_to',
- 'signed': 'sreg.nickname,unittest.one,sreg.dob',
- }
-
- signed_list = ['openid.sreg.nickname',
- 'openid.unittest.one',
- 'openid.sreg.dob',]
-
- # Don't use mkSuccess because it creates an all-inclusive
- # signed list.
- msg = Message.fromOpenIDArgs(args)
- resp = SuccessResponse(self.endpoint, msg, signed_list)
-
- # All args in this NS are signed, so expect all.
- sregargs = resp.extensionResponse('urn:sreg', True)
- self.failUnlessEqual(sregargs, {'nickname':'j3h', 'dob': 'yesterday'})
-
- # Not all args in this NS are signed, so expect None when
- # asking for them.
- utargs = resp.extensionResponse('urn:unittest', True)
- self.failUnlessEqual(utargs, None)
-
- def test_noReturnTo(self):
- resp = mkSuccess(self.endpoint, {})
- self.failUnless(resp.getReturnTo() is None)
-
- def test_returnTo(self):
- resp = mkSuccess(self.endpoint, {'return_to':'return_to'})
- self.failUnlessEqual(resp.getReturnTo(), 'return_to')
-
- def test_displayIdentifierClaimedId(self):
- resp = mkSuccess(self.endpoint, {})
- self.failUnlessEqual(resp.getDisplayIdentifier(),
- resp.endpoint.claimed_id)
-
- def test_displayIdentifierOverride(self):
- self.endpoint.display_identifier = "http://input.url/"
- resp = mkSuccess(self.endpoint, {})
- self.failUnlessEqual(resp.getDisplayIdentifier(),
- "http://input.url/")
-
-class StubConsumer(object):
- def __init__(self):
- self.assoc = object()
- self.response = None
- self.endpoint = None
-
- def begin(self, service):
- auth_req = AuthRequest(service, self.assoc)
- self.endpoint = service
- return auth_req
-
- def complete(self, message, endpoint, return_to):
- assert endpoint is self.endpoint
- return self.response
-
-class ConsumerTest(unittest.TestCase):
- """Tests for high-level consumer.Consumer functions.
-
- Its GenericConsumer component is stubbed out with StubConsumer.
- """
- def setUp(self):
- self.endpoint = OpenIDServiceEndpoint()
- self.endpoint.claimed_id = self.identity_url = 'http://identity.url/'
- self.store = None
- self.session = {}
- self.consumer = Consumer(self.session, self.store)
- self.consumer.consumer = StubConsumer()
- self.discovery = Discovery(self.session,
- self.identity_url,
- self.consumer.session_key_prefix)
-
- def test_setAssociationPreference(self):
- self.consumer.setAssociationPreference([])
- self.failUnless(isinstance(self.consumer.consumer.negotiator,
- association.SessionNegotiator))
- self.failUnlessEqual([],
- self.consumer.consumer.negotiator.allowed_types)
- self.consumer.setAssociationPreference([('HMAC-SHA1', 'DH-SHA1')])
- self.failUnlessEqual([('HMAC-SHA1', 'DH-SHA1')],
- self.consumer.consumer.negotiator.allowed_types)
-
- def withDummyDiscovery(self, callable, dummy_getNextService):
- class DummyDisco(object):
- def __init__(self, *ignored):
- pass
-
- getNextService = dummy_getNextService
-
- from askbot.deps.openid.consumer import consumer
- old_discovery = consumer.Discovery
- try:
- consumer.Discovery = DummyDisco
- callable()
- finally:
- consumer.Discovery = old_discovery
-
- def test_beginHTTPError(self):
- """Make sure that the discovery HTTP failure case behaves properly
- """
- def getNextService(self, ignored):
- raise HTTPFetchingError("Unit test")
-
- def test():
- try:
- self.consumer.begin('unused in this test')
- except DiscoveryFailure, why:
- self.failUnless(why[0].startswith('Error fetching'))
- self.failIf(why[0].find('Unit test') == -1)
- else:
- self.fail('Expected DiscoveryFailure')
-
- self.withDummyDiscovery(test, getNextService)
-
- def test_beginNoServices(self):
- def getNextService(self, ignored):
- return None
-
- url = 'http://a.user.url/'
- def test():
- try:
- self.consumer.begin(url)
- except DiscoveryFailure, why:
- self.failUnless(why[0].startswith('No usable OpenID'))
- self.failIf(why[0].find(url) == -1)
- else:
- self.fail('Expected DiscoveryFailure')
-
- self.withDummyDiscovery(test, getNextService)
-
-
- def test_beginWithoutDiscovery(self):
- # Does this really test anything non-trivial?
- result = self.consumer.beginWithoutDiscovery(self.endpoint)
-
- # The result is an auth request
- self.failUnless(isinstance(result, AuthRequest))
-
- # Side-effect of calling beginWithoutDiscovery is setting the
- # session value to the endpoint attribute of the result
- self.failUnless(self.session[self.consumer._token_key] is result.endpoint)
-
- # The endpoint that we passed in is the endpoint on the auth_request
- self.failUnless(result.endpoint is self.endpoint)
-
- def test_completeEmptySession(self):
- text = "failed complete"
-
- def checkEndpoint(message, endpoint, return_to):
- self.failUnless(endpoint is None)
- return FailureResponse(endpoint, text)
-
- self.consumer.consumer.complete = checkEndpoint
-
- response = self.consumer.complete({}, None)
- self.failUnlessEqual(response.status, FAILURE)
- self.failUnlessEqual(response.message, text)
- self.failUnless(response.identity_url is None)
-
- def _doResp(self, auth_req, exp_resp):
- """complete a transaction, using the expected response from
- the generic consumer."""
- # response is an attribute of StubConsumer, returned by
- # StubConsumer.complete.
- self.consumer.consumer.response = exp_resp
-
- # endpoint is stored in the session
- self.failUnless(self.session)
- resp = self.consumer.complete({}, None)
-
- # All responses should have the same identity URL, and the
- # session should be cleaned out
- if self.endpoint.claimed_id != IDENTIFIER_SELECT:
- self.failUnless(resp.identity_url is self.identity_url)
-
- self.failIf(self.consumer._token_key in self.session)
-
- # Expected status response
- self.failUnlessEqual(resp.status, exp_resp.status)
-
- return resp
-
- def _doRespNoDisco(self, exp_resp):
- """Set up a transaction without discovery"""
- auth_req = self.consumer.beginWithoutDiscovery(self.endpoint)
- resp = self._doResp(auth_req, exp_resp)
- # There should be nothing left in the session once we have completed.
- self.failIf(self.session)
- return resp
-
- def test_noDiscoCompleteSuccessWithToken(self):
- self._doRespNoDisco(mkSuccess(self.endpoint, {}))
-
- def test_noDiscoCompleteCancelWithToken(self):
- self._doRespNoDisco(CancelResponse(self.endpoint))
-
- def test_noDiscoCompleteFailure(self):
- msg = 'failed!'
- resp = self._doRespNoDisco(FailureResponse(self.endpoint, msg))
- self.failUnless(resp.message is msg)
-
- def test_noDiscoCompleteSetupNeeded(self):
- setup_url = 'http://setup.url/'
- resp = self._doRespNoDisco(
- SetupNeededResponse(self.endpoint, setup_url))
- self.failUnless(resp.setup_url is setup_url)
-
- # To test that discovery is cleaned up, we need to initialize a
- # Yadis manager, and have it put its values in the session.
- def _doRespDisco(self, is_clean, exp_resp):
- """Set up and execute a transaction, with discovery"""
- self.discovery.createManager([self.endpoint], self.identity_url)
- auth_req = self.consumer.begin(self.identity_url)
- resp = self._doResp(auth_req, exp_resp)
-
- manager = self.discovery.getManager()
- if is_clean:
- self.failUnless(self.discovery.getManager() is None, manager)
- else:
- self.failIf(self.discovery.getManager() is None, manager)
-
- return resp
-
- # Cancel and success DO clean up the discovery process
- def test_completeSuccess(self):
- self._doRespDisco(True, mkSuccess(self.endpoint, {}))
-
- def test_completeCancel(self):
- self._doRespDisco(True, CancelResponse(self.endpoint))
-
- # Failure and setup_needed don't clean up the discovery process
- def test_completeFailure(self):
- msg = 'failed!'
- resp = self._doRespDisco(False, FailureResponse(self.endpoint, msg))
- self.failUnless(resp.message is msg)
-
- def test_completeSetupNeeded(self):
- setup_url = 'http://setup.url/'
- resp = self._doRespDisco(
- False,
- SetupNeededResponse(self.endpoint, setup_url))
- self.failUnless(resp.setup_url is setup_url)
-
- def test_successDifferentURL(self):
- """
- Be sure that the session gets cleaned up when the response is
- successful and has a different URL than the one in the
- request.
- """
- # Set up a request endpoint describing an IDP URL
- self.identity_url = 'http://idp.url/'
- self.endpoint.claimed_id = self.endpoint.local_id = IDENTIFIER_SELECT
-
- # Use a response endpoint with a different URL (asserted by
- # the IDP)
- resp_endpoint = OpenIDServiceEndpoint()
- resp_endpoint.claimed_id = "http://user.url/"
-
- resp = self._doRespDisco(
- True,
- mkSuccess(resp_endpoint, {}))
- self.failUnless(self.discovery.getManager(force=True) is None)
-
- def test_begin(self):
- self.discovery.createManager([self.endpoint], self.identity_url)
- # Should not raise an exception
- auth_req = self.consumer.begin(self.identity_url)
- self.failUnless(isinstance(auth_req, AuthRequest))
- self.failUnless(auth_req.endpoint is self.endpoint)
- self.failUnless(auth_req.endpoint is self.consumer.consumer.endpoint)
- self.failUnless(auth_req.assoc is self.consumer.consumer.assoc)
-
-
-
-class IDPDrivenTest(unittest.TestCase):
-
- def setUp(self):
- self.store = GoodAssocStore()
- self.consumer = GenericConsumer(self.store)
- self.endpoint = OpenIDServiceEndpoint()
- self.endpoint.server_url = "http://idp.unittest/"
-
-
- def test_idpDrivenBegin(self):
- # Testing here that the token-handling doesn't explode...
- self.consumer.begin(self.endpoint)
-
-
- def test_idpDrivenComplete(self):
- identifier = '=directed_identifier'
- message = Message.fromPostArgs({
- 'openid.identity': '=directed_identifier',
- 'openid.return_to': 'x',
- 'openid.assoc_handle': 'z',
- 'openid.signed': 'identity,return_to',
- 'openid.sig': GOODSIG,
- })
-
- discovered_endpoint = OpenIDServiceEndpoint()
- discovered_endpoint.claimed_id = identifier
- discovered_endpoint.server_url = self.endpoint.server_url
- discovered_endpoint.local_id = identifier
- iverified = []
- def verifyDiscoveryResults(identifier, endpoint):
- self.failUnless(endpoint is self.endpoint)
- iverified.append(discovered_endpoint)
- return discovered_endpoint
- self.consumer._verifyDiscoveryResults = verifyDiscoveryResults
- self.consumer._idResCheckNonce = lambda *args: True
- self.consumer._checkReturnTo = lambda unused1, unused2 : True
- response = self.consumer._doIdRes(message, self.endpoint, None)
-
- self.failUnlessSuccess(response)
- self.failUnlessEqual(response.identity_url, "=directed_identifier")
-
- # assert that discovery attempt happens and returns good
- self.failUnlessEqual(iverified, [discovered_endpoint])
-
-
- def test_idpDrivenCompleteFraud(self):
- # crap with an identifier that doesn't match discovery info
- message = Message.fromPostArgs({
- 'openid.identity': '=directed_identifier',
- 'openid.return_to': 'x',
- 'openid.assoc_handle': 'z',
- 'openid.signed': 'identity,return_to',
- 'openid.sig': GOODSIG,
- })
- def verifyDiscoveryResults(identifier, endpoint):
- raise DiscoveryFailure("PHREAK!", None)
- self.consumer._verifyDiscoveryResults = verifyDiscoveryResults
- self.consumer._checkReturnTo = lambda unused1, unused2 : True
- self.failUnlessRaises(DiscoveryFailure, self.consumer._doIdRes,
- message, self.endpoint, None)
-
-
- def failUnlessSuccess(self, response):
- if response.status != SUCCESS:
- self.fail("Non-successful response: %s" % (response,))
-
-
-
-class TestDiscoveryVerification(unittest.TestCase):
- services = []
-
- def setUp(self):
- self.store = GoodAssocStore()
- self.consumer = GenericConsumer(self.store)
-
- self.consumer._discover = self.discoveryFunc
-
- self.identifier = "http://idp.unittest/1337"
- self.server_url = "http://endpoint.unittest/"
-
- self.message = Message.fromPostArgs({
- 'openid.ns': OPENID2_NS,
- 'openid.identity': self.identifier,
- 'openid.claimed_id': self.identifier,
- 'openid.op_endpoint': self.server_url,
- })
-
- self.endpoint = OpenIDServiceEndpoint()
- self.endpoint.server_url = self.server_url
-
- def test_theGoodStuff(self):
- endpoint = OpenIDServiceEndpoint()
- endpoint.type_uris = [OPENID_2_0_TYPE]
- endpoint.claimed_id = self.identifier
- endpoint.server_url = self.server_url
- endpoint.local_id = self.identifier
- self.services = [endpoint]
- r = self.consumer._verifyDiscoveryResults(self.message, endpoint)
-
- self.failUnlessEqual(r, endpoint)
-
-
- def test_otherServer(self):
- text = "verify failed"
-
- def discoverAndVerify(claimed_id, to_match_endpoints):
- self.failUnlessEqual(claimed_id, self.identifier)
- for to_match in to_match_endpoints:
- self.failUnlessEqual(claimed_id, to_match.claimed_id)
- raise ProtocolError(text)
-
- self.consumer._discoverAndVerify = discoverAndVerify
-
- # a set of things without the stuff
- endpoint = OpenIDServiceEndpoint()
- endpoint.type_uris = [OPENID_2_0_TYPE]
- endpoint.claimed_id = self.identifier
- endpoint.server_url = "http://the-MOON.unittest/"
- endpoint.local_id = self.identifier
- self.services = [endpoint]
- try:
- r = self.consumer._verifyDiscoveryResults(self.message, endpoint)
- except ProtocolError, e:
- # Should we make more ProtocolError subclasses?
- self.failUnless(str(e), text)
- else:
- self.fail("expected ProtocolError, %r returned." % (r,))
-
-
- def test_foreignDelegate(self):
- text = "verify failed"
-
- def discoverAndVerify(claimed_id, to_match_endpoints):
- self.failUnlessEqual(claimed_id, self.identifier)
- for to_match in to_match_endpoints:
- self.failUnlessEqual(claimed_id, to_match.claimed_id)
- raise ProtocolError(text)
-
- self.consumer._discoverAndVerify = discoverAndVerify
-
- # a set of things with the server stuff but other delegate
- endpoint = OpenIDServiceEndpoint()
- endpoint.type_uris = [OPENID_2_0_TYPE]
- endpoint.claimed_id = self.identifier
- endpoint.server_url = self.server_url
- endpoint.local_id = "http://unittest/juan-carlos"
-
- try:
- r = self.consumer._verifyDiscoveryResults(self.message, endpoint)
- except ProtocolError, e:
- self.failUnlessEqual(str(e), text)
- else:
- self.fail("Exepected ProtocolError, %r returned" % (r,))
-
- def test_nothingDiscovered(self):
- # a set of no things.
- self.services = []
- self.failUnlessRaises(DiscoveryFailure,
- self.consumer._verifyDiscoveryResults,
- self.message, self.endpoint)
-
-
- def discoveryFunc(self, identifier):
- return identifier, self.services
-
-
-class TestCreateAssociationRequest(unittest.TestCase):
- def setUp(self):
- class DummyEndpoint(object):
- use_compatibility = False
-
- def compatibilityMode(self):
- return self.use_compatibility
-
- self.endpoint = DummyEndpoint()
- self.consumer = GenericConsumer(store=None)
- self.assoc_type = 'HMAC-SHA1'
-
- def test_noEncryptionSendsType(self):
- session_type = 'no-encryption'
- session, args = self.consumer._createAssociateRequest(
- self.endpoint, self.assoc_type, session_type)
-
- self.failUnless(isinstance(session, PlainTextConsumerSession))
- expected = Message.fromOpenIDArgs(
- {'ns':OPENID2_NS,
- 'session_type':session_type,
- 'mode':'associate',
- 'assoc_type':self.assoc_type,
- })
-
- self.failUnlessEqual(expected, args)
-
- def test_noEncryptionCompatibility(self):
- self.endpoint.use_compatibility = True
- session_type = 'no-encryption'
- session, args = self.consumer._createAssociateRequest(
- self.endpoint, self.assoc_type, session_type)
-
- self.failUnless(isinstance(session, PlainTextConsumerSession))
- self.failUnlessEqual(Message.fromOpenIDArgs({'mode':'associate',
- 'assoc_type':self.assoc_type,
- }), args)
-
- def test_dhSHA1Compatibility(self):
- # Set the consumer's session type to a fast session since we
- # need it here.
- setConsumerSession(self.consumer)
-
- self.endpoint.use_compatibility = True
- session_type = 'DH-SHA1'
- session, args = self.consumer._createAssociateRequest(
- self.endpoint, self.assoc_type, session_type)
-
- self.failUnless(isinstance(session, DiffieHellmanSHA1ConsumerSession))
-
- # This is a random base-64 value, so just check that it's
- # present.
- self.failUnless(args.getArg(OPENID1_NS, 'dh_consumer_public'))
- args.delArg(OPENID1_NS, 'dh_consumer_public')
-
- # OK, session_type is set here and not for no-encryption
- # compatibility
- expected = Message.fromOpenIDArgs({'mode':'associate',
- 'session_type':'DH-SHA1',
- 'assoc_type':self.assoc_type,
- 'dh_modulus': 'BfvStQ==',
- 'dh_gen': 'Ag==',
- })
-
- self.failUnlessEqual(expected, args)
-
- # XXX: test the other types
-
-class TestDiffieHellmanResponseParameters(object):
- session_cls = None
- message_namespace = None
-
- def setUp(self):
- # Pre-compute DH with small prime so tests run quickly.
- self.server_dh = DiffieHellman(100389557, 2)
- self.consumer_dh = DiffieHellman(100389557, 2)
-
- # base64(btwoc(g ^ xb mod p))
- self.dh_server_public = cryptutil.longToBase64(self.server_dh.public)
-
- self.secret = cryptutil.randomString(self.session_cls.secret_size)
-
- self.enc_mac_key = oidutil.toBase64(
- self.server_dh.xorSecret(self.consumer_dh.public,
- self.secret,
- self.session_cls.hash_func))
-
- self.consumer_session = self.session_cls(self.consumer_dh)
-
- self.msg = Message(self.message_namespace)
-
- def testExtractSecret(self):
- self.msg.setArg(OPENID_NS, 'dh_server_public', self.dh_server_public)
- self.msg.setArg(OPENID_NS, 'enc_mac_key', self.enc_mac_key)
-
- extracted = self.consumer_session.extractSecret(self.msg)
- self.failUnlessEqual(extracted, self.secret)
-
- def testAbsentServerPublic(self):
- self.msg.setArg(OPENID_NS, 'enc_mac_key', self.enc_mac_key)
-
- self.failUnlessRaises(KeyError, self.consumer_session.extractSecret, self.msg)
-
- def testAbsentMacKey(self):
- self.msg.setArg(OPENID_NS, 'dh_server_public', self.dh_server_public)
-
- self.failUnlessRaises(KeyError, self.consumer_session.extractSecret, self.msg)
-
- def testInvalidBase64Public(self):
- self.msg.setArg(OPENID_NS, 'dh_server_public', 'n o t b a s e 6 4.')
- self.msg.setArg(OPENID_NS, 'enc_mac_key', self.enc_mac_key)
-
- self.failUnlessRaises(ValueError, self.consumer_session.extractSecret, self.msg)
-
- def testInvalidBase64MacKey(self):
- self.msg.setArg(OPENID_NS, 'dh_server_public', self.dh_server_public)
- self.msg.setArg(OPENID_NS, 'enc_mac_key', 'n o t base 64')
-
- self.failUnlessRaises(ValueError, self.consumer_session.extractSecret, self.msg)
-
-class TestOpenID1SHA1(TestDiffieHellmanResponseParameters, unittest.TestCase):
- session_cls = DiffieHellmanSHA1ConsumerSession
- message_namespace = OPENID1_NS
-
-class TestOpenID2SHA1(TestDiffieHellmanResponseParameters, unittest.TestCase):
- session_cls = DiffieHellmanSHA1ConsumerSession
- message_namespace = OPENID2_NS
-
-if cryptutil.SHA256_AVAILABLE:
- class TestOpenID2SHA256(TestDiffieHellmanResponseParameters, unittest.TestCase):
- session_cls = DiffieHellmanSHA256ConsumerSession
- message_namespace = OPENID2_NS
-else:
- warnings.warn("Not running SHA256 association session tests.")
-
-class TestNoStore(unittest.TestCase):
- def setUp(self):
- self.consumer = GenericConsumer(None)
-
- def test_completeNoGetAssoc(self):
- """_getAssociation is never called when the store is None"""
- def notCalled(unused):
- self.fail('This method was unexpectedly called')
-
- endpoint = OpenIDServiceEndpoint()
- endpoint.claimed_id = 'identity_url'
-
- self.consumer._getAssociation = notCalled
- auth_request = self.consumer.begin(endpoint)
- # _getAssociation was not called
-
-
-
-
-class NonAnonymousAuthRequest(object):
- endpoint = 'unused'
-
- def setAnonymous(self, unused):
- raise ValueError('Should trigger ProtocolError')
-
-class TestConsumerAnonymous(unittest.TestCase):
- def test_beginWithoutDiscoveryAnonymousFail(self):
- """Make sure that ValueError for setting an auth request
- anonymous gets converted to a ProtocolError
- """
- sess = {}
- consumer = Consumer(sess, None)
- def bogusBegin(unused):
- return NonAnonymousAuthRequest()
- consumer.consumer.begin = bogusBegin
- self.failUnlessRaises(
- ProtocolError,
- consumer.beginWithoutDiscovery, None)
-
-
-class TestDiscoverAndVerify(unittest.TestCase):
- def setUp(self):
- self.consumer = GenericConsumer(None)
- self.discovery_result = None
- def dummyDiscover(unused_identifier):
- return self.discovery_result
- self.consumer._discover = dummyDiscover
- self.to_match = OpenIDServiceEndpoint()
-
- def failUnlessDiscoveryFailure(self):
- self.failUnlessRaises(
- DiscoveryFailure,
- self.consumer._discoverAndVerify,
- 'http://claimed-id.com/',
- [self.to_match])
-
- def test_noServices(self):
- """Discovery returning no results results in a
- DiscoveryFailure exception"""
- self.discovery_result = (None, [])
- self.failUnlessDiscoveryFailure()
-
- def test_noMatches(self):
- """If no discovered endpoint matches the values from the
- assertion, then we end up raising a ProtocolError
- """
- self.discovery_result = (None, ['unused'])
- def raiseProtocolError(unused1, unused2):
- raise ProtocolError('unit test')
- self.consumer._verifyDiscoverySingle = raiseProtocolError
- self.failUnlessDiscoveryFailure()
-
- def test_matches(self):
- """If an endpoint matches, we return it
- """
- # Discovery returns a single "endpoint" object
- matching_endpoint = 'matching endpoint'
- self.discovery_result = (None, [matching_endpoint])
-
- # Make verifying discovery return True for this endpoint
- def returnTrue(unused1, unused2):
- return True
- self.consumer._verifyDiscoverySingle = returnTrue
-
- # Since _verifyDiscoverySingle returns True, we should get the
- # first endpoint that we passed in as a result.
- result = self.consumer._discoverAndVerify(
- 'http://claimed.id/', [self.to_match])
- self.failUnlessEqual(matching_endpoint, result)
-
-from askbot.deps.openid.extension import Extension
-class SillyExtension(Extension):
- ns_uri = 'http://silly.example.com/'
- ns_alias = 'silly'
-
- def getExtensionArgs(self):
- return {'i_am':'silly'}
-
-class TestAddExtension(unittest.TestCase):
-
- def test_SillyExtension(self):
- ext = SillyExtension()
- ar = AuthRequest(OpenIDServiceEndpoint(), None)
- ar.addExtension(ext)
- ext_args = ar.message.getArgs(ext.ns_uri)
- self.failUnlessEqual(ext.getExtensionArgs(), ext_args)
-
-
-
-class TestKVPost(unittest.TestCase):
- def setUp(self):
- self.server_url = 'http://unittest/%s' % (self.id(),)
-
- def test_200(self):
- from askbot.deps.openid.fetchers import HTTPResponse
- response = HTTPResponse()
- response.status = 200
- response.body = "foo:bar\nbaz:quux\n"
- r = _httpResponseToMessage(response, self.server_url)
- expected_msg = Message.fromOpenIDArgs({'foo':'bar','baz':'quux'})
- self.failUnlessEqual(expected_msg, r)
-
-
- def test_400(self):
- response = HTTPResponse()
- response.status = 400
- response.body = "error:bonk\nerror_code:7\n"
- try:
- r = _httpResponseToMessage(response, self.server_url)
- except ServerError, e:
- self.failUnlessEqual(e.error_text, 'bonk')
- self.failUnlessEqual(e.error_code, '7')
- else:
- self.fail("Expected ServerError, got return %r" % (r,))
-
-
- def test_500(self):
- # 500 as an example of any non-200, non-400 code.
- response = HTTPResponse()
- response.status = 500
- response.body = "foo:bar\nbaz:quux\n"
- self.failUnlessRaises(fetchers.HTTPFetchingError,
- _httpResponseToMessage, response,
- self.server_url)
-
-
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_discover.py b/askbot/deps/openid/test/test_discover.py
deleted file mode 100644
index e985b601..00000000
--- a/askbot/deps/openid/test/test_discover.py
+++ /dev/null
@@ -1,783 +0,0 @@
-import sys
-import unittest
-import datadriven
-import os.path
-from askbot.deps.openid import fetchers
-from askbot.deps.openid.fetchers import HTTPResponse
-from askbot.deps.openid.yadis.discover import DiscoveryFailure
-from askbot.deps.openid.consumer import discover
-from askbot.deps.openid.yadis import xrires
-from askbot.deps.openid.yadis.xri import XRI
-from urlparse import urlsplit
-from askbot.deps.openid import message
-
-### Tests for conditions that trigger DiscoveryFailure
-
-class SimpleMockFetcher(object):
- def __init__(self, responses):
- self.responses = list(responses)
-
- def fetch(self, url, body=None, headers=None):
- response = self.responses.pop(0)
- assert body is None
- assert response.final_url == url
- return response
-
-class TestDiscoveryFailure(datadriven.DataDrivenTestCase):
- cases = [
- [HTTPResponse('http://network.error/', None)],
- [HTTPResponse('http://not.found/', 404)],
- [HTTPResponse('http://bad.request/', 400)],
- [HTTPResponse('http://server.error/', 500)],
- [HTTPResponse('http://header.found/', 200,
- headers={'x-xrds-location':'http://xrds.missing/'}),
- HTTPResponse('http://xrds.missing/', 404)],
- ]
-
- def __init__(self, responses):
- self.url = responses[0].final_url
- datadriven.DataDrivenTestCase.__init__(self, self.url)
- self.responses = responses
-
- def setUp(self):
- fetcher = SimpleMockFetcher(self.responses)
- fetchers.setDefaultFetcher(fetcher)
-
- def tearDown(self):
- fetchers.setDefaultFetcher(None)
-
- def runOneTest(self):
- expected_status = self.responses[-1].status
- try:
- discover.discover(self.url)
- except DiscoveryFailure, why:
- self.failUnlessEqual(why.http_response.status, expected_status)
- else:
- self.fail('Did not raise DiscoveryFailure')
-
-
-### Tests for raising/catching exceptions from the fetcher through the
-### discover function
-
-# Python 2.5 displays a message when running this test, which is
-# testing the behaviour in the presence of string exceptions,
-# deprecated or not, so tell it no to complain when this particular
-# string exception is raised.
-import warnings
-warnings.filterwarnings('ignore', 'raising a string.*', DeprecationWarning,
- r'^openid\.test\.test_discover$', 77)
-
-class ErrorRaisingFetcher(object):
- """Just raise an exception when fetch is called"""
-
- def __init__(self, thing_to_raise):
- self.thing_to_raise = thing_to_raise
-
- def fetch(self, url, body=None, headers=None):
- raise self.thing_to_raise
-
-class DidFetch(Exception):
- """Custom exception just to make sure it's not handled differently"""
-
-class TestFetchException(datadriven.DataDrivenTestCase):
- """Make sure exceptions get passed through discover function from
- fetcher."""
-
- cases = [
- Exception(),
- DidFetch(),
- ValueError(),
- RuntimeError(),
- ]
-
- # String exceptions are finally gone from Python 2.6.
- if sys.version_info[:2] < (2, 6):
- cases.append('oi!')
-
- def __init__(self, exc):
- datadriven.DataDrivenTestCase.__init__(self, repr(exc))
- self.exc = exc
-
- def setUp(self):
- fetcher = ErrorRaisingFetcher(self.exc)
- fetchers.setDefaultFetcher(fetcher, wrap_exceptions=False)
-
- def tearDown(self):
- fetchers.setDefaultFetcher(None)
-
- def runOneTest(self):
- try:
- discover.discover('http://doesnt.matter/')
- except:
- exc = sys.exc_info()[1]
- if exc is None:
- # str exception
- self.failUnless(self.exc is sys.exc_info()[0])
- else:
- self.failUnless(self.exc is exc, exc)
- else:
- self.fail('Expected %r', self.exc)
-
-
-### Tests for openid.consumer.discover.discover
-
-class TestNormalization(unittest.TestCase):
- def testAddingProtocol(self):
- f = ErrorRaisingFetcher(RuntimeError())
- fetchers.setDefaultFetcher(f, wrap_exceptions=False)
-
- try:
- discover.discover('users.stompy.janrain.com:8000/x')
- except DiscoveryFailure, why:
- self.fail('failed to parse url with port correctly')
- except RuntimeError:
- pass #expected
-
- fetchers.setDefaultFetcher(None)
-
-
-class DiscoveryMockFetcher(object):
- redirect = None
-
- def __init__(self, documents):
- self.documents = documents
- self.fetchlog = []
-
- def fetch(self, url, body=None, headers=None):
- self.fetchlog.append((url, body, headers))
- if self.redirect:
- final_url = self.redirect
- else:
- final_url = url
-
- try:
- ctype, body = self.documents[url]
- except KeyError:
- status = 404
- ctype = 'text/plain'
- body = ''
- else:
- status = 200
-
- return HTTPResponse(final_url, status, {'content-type': ctype}, body)
-
-# from twisted.trial import unittest as trialtest
-
-class BaseTestDiscovery(unittest.TestCase):
- id_url = "http://someuser.unittest/"
-
- documents = {}
- fetcherClass = DiscoveryMockFetcher
-
- def _checkService(self, s,
- server_url,
- claimed_id=None,
- local_id=None,
- canonical_id=None,
- types=None,
- used_yadis=False,
- display_identifier=None
- ):
- self.failUnlessEqual(server_url, s.server_url)
- if types == ['2.0 OP']:
- self.failIf(claimed_id)
- self.failIf(local_id)
- self.failIf(s.claimed_id)
- self.failIf(s.local_id)
- self.failIf(s.getLocalID())
- self.failIf(s.compatibilityMode())
- self.failUnless(s.isOPIdentifier())
- self.failUnlessEqual(s.preferredNamespace(),
- discover.OPENID_2_0_MESSAGE_NS)
- else:
- self.failUnlessEqual(claimed_id, s.claimed_id)
- self.failUnlessEqual(local_id, s.getLocalID())
-
- if used_yadis:
- self.failUnless(s.used_yadis, "Expected to use Yadis")
- else:
- self.failIf(s.used_yadis,
- "Expected to use old-style discovery")
-
- openid_types = {
- '1.1': discover.OPENID_1_1_TYPE,
- '1.0': discover.OPENID_1_0_TYPE,
- '2.0': discover.OPENID_2_0_TYPE,
- '2.0 OP': discover.OPENID_IDP_2_0_TYPE,
- }
-
- type_uris = [openid_types[t] for t in types]
- self.failUnlessEqual(type_uris, s.type_uris)
- self.failUnlessEqual(canonical_id, s.canonicalID)
-
- if s.canonicalID:
- self.failUnless(s.getDisplayIdentifier() != claimed_id)
- self.failUnless(s.getDisplayIdentifier() is not None)
- self.failUnlessEqual(display_identifier, s.getDisplayIdentifier())
- self.failUnlessEqual(s.claimed_id, s.canonicalID)
-
- self.failUnlessEqual(s.display_identifier or s.claimed_id, s.getDisplayIdentifier())
-
- def setUp(self):
- self.documents = self.documents.copy()
- self.fetcher = self.fetcherClass(self.documents)
- fetchers.setDefaultFetcher(self.fetcher)
-
- def tearDown(self):
- fetchers.setDefaultFetcher(None)
-
-def readDataFile(filename):
- module_directory = os.path.dirname(os.path.abspath(__file__))
- filename = os.path.join(
- module_directory, 'data', 'test_discover', filename)
- return file(filename).read()
-
-class TestDiscovery(BaseTestDiscovery):
- def _discover(self, content_type, data,
- expected_services, expected_id=None):
- if expected_id is None:
- expected_id = self.id_url
-
- self.documents[self.id_url] = (content_type, data)
- id_url, services = discover.discover(self.id_url)
- self.failUnlessEqual(expected_services, len(services))
- self.failUnlessEqual(expected_id, id_url)
- return services
-
- def test_404(self):
- self.failUnlessRaises(DiscoveryFailure,
- discover.discover, self.id_url + '/404')
-
- def test_noOpenID(self):
- services = self._discover(content_type='text/plain',
- data="junk",
- expected_services=0)
-
- services = self._discover(
- content_type='text/html',
- data=readDataFile('openid_no_delegate.html'),
- expected_services=1,
- )
-
- self._checkService(
- services[0],
- used_yadis=False,
- types=['1.1'],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id=self.id_url,
- )
-
- def test_html1(self):
- services = self._discover(
- content_type='text/html',
- data=readDataFile('openid.html'),
- expected_services=1)
-
-
- self._checkService(
- services[0],
- used_yadis=False,
- types=['1.1'],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id='http://smoker.myopenid.com/',
- display_identifier=self.id_url,
- )
-
- def test_html1Fragment(self):
- """Ensure that the Claimed Identifier does not have a fragment
- if one is supplied in the User Input."""
- content_type = 'text/html'
- data = readDataFile('openid.html')
- expected_services = 1
-
- self.documents[self.id_url] = (content_type, data)
- expected_id = self.id_url
- self.id_url = self.id_url + '#fragment'
- id_url, services = discover.discover(self.id_url)
- self.failUnlessEqual(expected_services, len(services))
- self.failUnlessEqual(expected_id, id_url)
-
- self._checkService(
- services[0],
- used_yadis=False,
- types=['1.1'],
- server_url="http://www.myopenid.com/server",
- claimed_id=expected_id,
- local_id='http://smoker.myopenid.com/',
- display_identifier=expected_id,
- )
-
- def test_html2(self):
- services = self._discover(
- content_type='text/html',
- data=readDataFile('openid2.html'),
- expected_services=1,
- )
-
- self._checkService(
- services[0],
- used_yadis=False,
- types=['2.0'],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id='http://smoker.myopenid.com/',
- display_identifier=self.id_url,
- )
-
- def test_html1And2(self):
- services = self._discover(
- content_type='text/html',
- data=readDataFile('openid_1_and_2.html'),
- expected_services=2,
- )
-
- for t, s in zip(['2.0', '1.1'], services):
- self._checkService(
- s,
- used_yadis=False,
- types=[t],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id='http://smoker.myopenid.com/',
- display_identifier=self.id_url,
- )
-
- def test_yadisEmpty(self):
- services = self._discover(content_type='application/xrds+xml',
- data=readDataFile('yadis_0entries.xml'),
- expected_services=0)
-
- def test_htmlEmptyYadis(self):
- """HTML document has discovery information, but points to an
- empty Yadis document."""
- # The XRDS document pointed to by "openid_and_yadis.html"
- self.documents[self.id_url + 'xrds'] = (
- 'application/xrds+xml', readDataFile('yadis_0entries.xml'))
-
- services = self._discover(content_type='text/html',
- data=readDataFile('openid_and_yadis.html'),
- expected_services=1)
-
- self._checkService(
- services[0],
- used_yadis=False,
- types=['1.1'],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id='http://smoker.myopenid.com/',
- display_identifier=self.id_url,
- )
-
- def test_yadis1NoDelegate(self):
- services = self._discover(content_type='application/xrds+xml',
- data=readDataFile('yadis_no_delegate.xml'),
- expected_services=1)
-
- self._checkService(
- services[0],
- used_yadis=True,
- types=['1.0'],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id=self.id_url,
- display_identifier=self.id_url,
- )
-
- def test_yadis2NoLocalID(self):
- services = self._discover(
- content_type='application/xrds+xml',
- data=readDataFile('openid2_xrds_no_local_id.xml'),
- expected_services=1,
- )
-
- self._checkService(
- services[0],
- used_yadis=True,
- types=['2.0'],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id=self.id_url,
- display_identifier=self.id_url,
- )
-
- def test_yadis2(self):
- services = self._discover(
- content_type='application/xrds+xml',
- data=readDataFile('openid2_xrds.xml'),
- expected_services=1,
- )
-
- self._checkService(
- services[0],
- used_yadis=True,
- types=['2.0'],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id='http://smoker.myopenid.com/',
- display_identifier=self.id_url,
- )
-
- def test_yadis2OP(self):
- services = self._discover(
- content_type='application/xrds+xml',
- data=readDataFile('yadis_idp.xml'),
- expected_services=1,
- )
-
- self._checkService(
- services[0],
- used_yadis=True,
- types=['2.0 OP'],
- server_url="http://www.myopenid.com/server",
- display_identifier=self.id_url,
- )
-
- def test_yadis2OPDelegate(self):
- """The delegate tag isn't meaningful for OP entries."""
- services = self._discover(
- content_type='application/xrds+xml',
- data=readDataFile('yadis_idp_delegate.xml'),
- expected_services=1,
- )
-
- self._checkService(
- services[0],
- used_yadis=True,
- types=['2.0 OP'],
- server_url="http://www.myopenid.com/server",
- display_identifier=self.id_url,
- )
-
- def test_yadis2BadLocalID(self):
- self.failUnlessRaises(DiscoveryFailure, self._discover,
- content_type='application/xrds+xml',
- data=readDataFile('yadis_2_bad_local_id.xml'),
- expected_services=1,
- )
-
- def test_yadis1And2(self):
- services = self._discover(
- content_type='application/xrds+xml',
- data=readDataFile('openid_1_and_2_xrds.xml'),
- expected_services=1,
- )
-
- self._checkService(
- services[0],
- used_yadis=True,
- types=['2.0', '1.1'],
- server_url="http://www.myopenid.com/server",
- claimed_id=self.id_url,
- local_id='http://smoker.myopenid.com/',
- display_identifier=self.id_url,
- )
-
- def test_yadis1And2BadLocalID(self):
- self.failUnlessRaises(DiscoveryFailure, self._discover,
- content_type='application/xrds+xml',
- data=readDataFile('openid_1_and_2_xrds_bad_delegate.xml'),
- expected_services=1,
- )
-
-class MockFetcherForXRIProxy(object):
-
- def __init__(self, documents, proxy_url=xrires.DEFAULT_PROXY):
- self.documents = documents
- self.fetchlog = []
- self.proxy_url = None
-
-
- def fetch(self, url, body=None, headers=None):
- self.fetchlog.append((url, body, headers))
-
- u = urlsplit(url)
- proxy_host = u[1]
- xri = u[2]
- query = u[3]
-
- if not headers and not query:
- raise ValueError("No headers or query; you probably didn't "
- "mean to do that.")
-
- if xri.startswith('/'):
- xri = xri[1:]
-
- try:
- ctype, body = self.documents[xri]
- except KeyError:
- status = 404
- ctype = 'text/plain'
- body = ''
- else:
- status = 200
-
- return HTTPResponse(url, status, {'content-type': ctype}, body)
-
-
-class TestXRIDiscovery(BaseTestDiscovery):
- fetcherClass = MockFetcherForXRIProxy
-
- documents = {'=smoker': ('application/xrds+xml',
- readDataFile('yadis_2entries_delegate.xml')),
- '=smoker*bad': ('application/xrds+xml',
- readDataFile('yadis_another_delegate.xml')) }
-
- def test_xri(self):
- user_xri, services = discover.discoverXRI('=smoker')
-
- self._checkService(
- services[0],
- used_yadis=True,
- types=['1.0'],
- server_url="http://www.myopenid.com/server",
- claimed_id=XRI("=!1000"),
- canonical_id=XRI("=!1000"),
- local_id='http://smoker.myopenid.com/',
- display_identifier='=smoker'
- )
-
- self._checkService(
- services[1],
- used_yadis=True,
- types=['1.0'],
- server_url="http://www.livejournal.com/openid/server.bml",
- claimed_id=XRI("=!1000"),
- canonical_id=XRI("=!1000"),
- local_id='http://frank.livejournal.com/',
- display_identifier='=smoker'
- )
-
- def test_xri_normalize(self):
- user_xri, services = discover.discoverXRI('xri://=smoker')
-
- self._checkService(
- services[0],
- used_yadis=True,
- types=['1.0'],
- server_url="http://www.myopenid.com/server",
- claimed_id=XRI("=!1000"),
- canonical_id=XRI("=!1000"),
- local_id='http://smoker.myopenid.com/',
- display_identifier='=smoker'
- )
-
- self._checkService(
- services[1],
- used_yadis=True,
- types=['1.0'],
- server_url="http://www.livejournal.com/openid/server.bml",
- claimed_id=XRI("=!1000"),
- canonical_id=XRI("=!1000"),
- local_id='http://frank.livejournal.com/',
- display_identifier='=smoker'
- )
-
- def test_xriNoCanonicalID(self):
- user_xri, services = discover.discoverXRI('=smoker*bad')
- self.failIf(services)
-
- def test_useCanonicalID(self):
- """When there is no delegate, the CanonicalID should be used with XRI.
- """
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.claimed_id = XRI("=!1000")
- endpoint.canonicalID = XRI("=!1000")
- self.failUnlessEqual(endpoint.getLocalID(), XRI("=!1000"))
-
-
-class TestXRIDiscoveryIDP(BaseTestDiscovery):
- fetcherClass = MockFetcherForXRIProxy
-
- documents = {'=smoker': ('application/xrds+xml',
- readDataFile('yadis_2entries_idp.xml')) }
-
- def test_xri(self):
- user_xri, services = discover.discoverXRI('=smoker')
- self.failUnless(services, "Expected services, got zero")
- self.failUnlessEqual(services[0].server_url,
- "http://www.livejournal.com/openid/server.bml")
-
-
-class TestPreferredNamespace(datadriven.DataDrivenTestCase):
- def __init__(self, expected_ns, type_uris):
- datadriven.DataDrivenTestCase.__init__(
- self, 'Expecting %s from %s' % (expected_ns, type_uris))
- self.expected_ns = expected_ns
- self.type_uris = type_uris
-
- def runOneTest(self):
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.type_uris = self.type_uris
- actual_ns = endpoint.preferredNamespace()
- self.failUnlessEqual(actual_ns, self.expected_ns)
-
- cases = [
- (message.OPENID1_NS, []),
- (message.OPENID1_NS, ['http://jyte.com/']),
- (message.OPENID1_NS, [discover.OPENID_1_0_TYPE]),
- (message.OPENID1_NS, [discover.OPENID_1_1_TYPE]),
- (message.OPENID2_NS, [discover.OPENID_2_0_TYPE]),
- (message.OPENID2_NS, [discover.OPENID_IDP_2_0_TYPE]),
- (message.OPENID2_NS, [discover.OPENID_2_0_TYPE,
- discover.OPENID_1_0_TYPE]),
- (message.OPENID2_NS, [discover.OPENID_1_0_TYPE,
- discover.OPENID_2_0_TYPE]),
- ]
-
-class TestIsOPIdentifier(unittest.TestCase):
- def setUp(self):
- self.endpoint = discover.OpenIDServiceEndpoint()
-
- def test_none(self):
- self.failIf(self.endpoint.isOPIdentifier())
-
- def test_openid1_0(self):
- self.endpoint.type_uris = [discover.OPENID_1_0_TYPE]
- self.failIf(self.endpoint.isOPIdentifier())
-
- def test_openid1_1(self):
- self.endpoint.type_uris = [discover.OPENID_1_1_TYPE]
- self.failIf(self.endpoint.isOPIdentifier())
-
- def test_openid2(self):
- self.endpoint.type_uris = [discover.OPENID_2_0_TYPE]
- self.failIf(self.endpoint.isOPIdentifier())
-
- def test_openid2OP(self):
- self.endpoint.type_uris = [discover.OPENID_IDP_2_0_TYPE]
- self.failUnless(self.endpoint.isOPIdentifier())
-
- def test_multipleMissing(self):
- self.endpoint.type_uris = [discover.OPENID_2_0_TYPE,
- discover.OPENID_1_0_TYPE]
- self.failIf(self.endpoint.isOPIdentifier())
-
- def test_multiplePresent(self):
- self.endpoint.type_uris = [discover.OPENID_2_0_TYPE,
- discover.OPENID_1_0_TYPE,
- discover.OPENID_IDP_2_0_TYPE]
- self.failUnless(self.endpoint.isOPIdentifier())
-
-class TestFromOPEndpointURL(unittest.TestCase):
- def setUp(self):
- self.op_endpoint_url = 'http://example.com/op/endpoint'
- self.endpoint = discover.OpenIDServiceEndpoint.fromOPEndpointURL(
- self.op_endpoint_url)
-
- def test_isOPEndpoint(self):
- self.failUnless(self.endpoint.isOPIdentifier())
-
- def test_noIdentifiers(self):
- self.failUnlessEqual(self.endpoint.getLocalID(), None)
- self.failUnlessEqual(self.endpoint.claimed_id, None)
-
- def test_compatibility(self):
- self.failIf(self.endpoint.compatibilityMode())
-
- def test_canonicalID(self):
- self.failUnlessEqual(self.endpoint.canonicalID, None)
-
- def test_serverURL(self):
- self.failUnlessEqual(self.endpoint.server_url, self.op_endpoint_url)
-
-class TestDiscoverFunction(unittest.TestCase):
- def setUp(self):
- self._old_discoverURI = discover.discoverURI
- self._old_discoverXRI = discover.discoverXRI
-
- discover.discoverXRI = self.discoverXRI
- discover.discoverURI = self.discoverURI
-
- def tearDown(self):
- discover.discoverURI = self._old_discoverURI
- discover.discoverXRI = self._old_discoverXRI
-
- def discoverXRI(self, identifier):
- return 'XRI'
-
- def discoverURI(self, identifier):
- return 'URI'
-
- def test_uri(self):
- self.failUnlessEqual('URI', discover.discover('http://woo!'))
-
- def test_uriForBogus(self):
- self.failUnlessEqual('URI', discover.discover('not a URL or XRI'))
-
- def test_xri(self):
- self.failUnlessEqual('XRI', discover.discover('xri://=something'))
-
- def test_xriChar(self):
- self.failUnlessEqual('XRI', discover.discover('=something'))
-
-class TestEndpointSupportsType(unittest.TestCase):
- def setUp(self):
- self.endpoint = discover.OpenIDServiceEndpoint()
-
- def failUnlessSupportsOnly(self, *types):
- for t in [
- 'foo',
- discover.OPENID_1_1_TYPE,
- discover.OPENID_1_0_TYPE,
- discover.OPENID_2_0_TYPE,
- discover.OPENID_IDP_2_0_TYPE,
- ]:
- if t in types:
- self.failUnless(self.endpoint.supportsType(t),
- "Must support %r" % (t,))
- else:
- self.failIf(self.endpoint.supportsType(t),
- "Shouldn't support %r" % (t,))
-
- def test_supportsNothing(self):
- self.failUnlessSupportsOnly()
-
- def test_openid2(self):
- self.endpoint.type_uris = [discover.OPENID_2_0_TYPE]
- self.failUnlessSupportsOnly(discover.OPENID_2_0_TYPE)
-
- def test_openid2provider(self):
- self.endpoint.type_uris = [discover.OPENID_IDP_2_0_TYPE]
- self.failUnlessSupportsOnly(discover.OPENID_IDP_2_0_TYPE,
- discover.OPENID_2_0_TYPE)
-
- def test_openid1_0(self):
- self.endpoint.type_uris = [discover.OPENID_1_0_TYPE]
- self.failUnlessSupportsOnly(discover.OPENID_1_0_TYPE)
-
- def test_openid1_1(self):
- self.endpoint.type_uris = [discover.OPENID_1_1_TYPE]
- self.failUnlessSupportsOnly(discover.OPENID_1_1_TYPE)
-
- def test_multiple(self):
- self.endpoint.type_uris = [discover.OPENID_1_1_TYPE,
- discover.OPENID_2_0_TYPE]
- self.failUnlessSupportsOnly(discover.OPENID_1_1_TYPE,
- discover.OPENID_2_0_TYPE)
-
- def test_multipleWithProvider(self):
- self.endpoint.type_uris = [discover.OPENID_1_1_TYPE,
- discover.OPENID_2_0_TYPE,
- discover.OPENID_IDP_2_0_TYPE]
- self.failUnlessSupportsOnly(discover.OPENID_1_1_TYPE,
- discover.OPENID_2_0_TYPE,
- discover.OPENID_IDP_2_0_TYPE,
- )
-
-
-class TestEndpointDisplayIdentifier(unittest.TestCase):
- def test_strip_fragment(self):
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.claimed_id = 'http://recycled.invalid/#123'
- self.failUnlessEqual('http://recycled.invalid/', endpoint.getDisplayIdentifier())
-
-
-def pyUnitTests():
- return datadriven.loadTests(__name__)
-
-if __name__ == '__main__':
- suite = pyUnitTests()
- runner = unittest.TextTestRunner()
- runner.run(suite)
diff --git a/askbot/deps/openid/test/test_etxrd.py b/askbot/deps/openid/test/test_etxrd.py
deleted file mode 100644
index 653ae1fb..00000000
--- a/askbot/deps/openid/test/test_etxrd.py
+++ /dev/null
@@ -1,194 +0,0 @@
-import unittest
-from askbot.deps.openid.yadis import services, etxrd, xri
-import os.path
-
-def datapath(filename):
- module_directory = os.path.dirname(os.path.abspath(__file__))
- return os.path.join(module_directory, 'data', 'test_etxrd', filename)
-
-XRD_FILE = datapath('valid-populated-xrds.xml')
-NOXRDS_FILE = datapath('not-xrds.xml')
-NOXRD_FILE = datapath('no-xrd.xml')
-
-# None of the namespaces or service URIs below are official (or even
-# sanctioned by the owners of that piece of URL-space)
-
-LID_2_0 = "http://lid.netmesh.org/sso/2.0b5"
-TYPEKEY_1_0 = "http://typekey.com/services/1.0"
-
-def simpleOpenIDTransformer(endpoint):
- """Function to extract information from an OpenID service element"""
- if 'http://openid.net/signon/1.0' not in endpoint.type_uris:
- return None
-
- delegates = list(endpoint.service_element.findall(
- '{http://openid.net/xmlns/1.0}Delegate'))
- assert len(delegates) == 1
- delegate = delegates[0].text
- return (endpoint.uri, delegate)
-
-class TestServiceParser(unittest.TestCase):
- def setUp(self):
- self.xmldoc = file(XRD_FILE).read()
- self.yadis_url = 'http://unittest.url/'
-
- def _getServices(self, flt=None):
- return list(services.applyFilter(self.yadis_url, self.xmldoc, flt))
-
- def testParse(self):
- """Make sure that parsing succeeds at all"""
- services = self._getServices()
-
- def testParseOpenID(self):
- """Parse for OpenID services with a transformer function"""
- services = self._getServices(simpleOpenIDTransformer)
-
- expectedServices = [
- ("http://www.myopenid.com/server", "http://josh.myopenid.com/"),
- ("http://www.schtuff.com/openid", "http://users.schtuff.com/josh"),
- ("http://www.livejournal.com/openid/server.bml",
- "http://www.livejournal.com/users/nedthealpaca/"),
- ]
-
- it = iter(services)
- for (server_url, delegate) in expectedServices:
- for (actual_url, actual_delegate) in it:
- self.failUnlessEqual(server_url, actual_url)
- self.failUnlessEqual(delegate, actual_delegate)
- break
- else:
- self.fail('Not enough services found')
-
- def _checkServices(self, expectedServices):
- """Check to make sure that the expected services are found in
- that order in the parsed document."""
- it = iter(self._getServices())
- for (type_uri, uri) in expectedServices:
- for service in it:
- if type_uri in service.type_uris:
- self.failUnlessEqual(service.uri, uri)
- break
- else:
- self.fail('Did not find %r service' % (type_uri,))
-
- def testGetSeveral(self):
- """Get some services in order"""
- expectedServices = [
- # type, URL
- (TYPEKEY_1_0, None),
- (LID_2_0, "http://mylid.net/josh"),
- ]
-
- self._checkServices(expectedServices)
-
- def testGetSeveralForOne(self):
- """Getting services for one Service with several Type elements."""
- types = [ 'http://lid.netmesh.org/sso/2.0b5'
- , 'http://lid.netmesh.org/2.0b5'
- ]
-
- uri = "http://mylid.net/josh"
-
- for service in self._getServices():
- if service.uri == uri:
- found_types = service.matchTypes(types)
- if found_types == types:
- break
- else:
- self.fail('Did not find service with expected types and uris')
-
- def testNoXRDS(self):
- """Make sure that we get an exception when an XRDS element is
- not present"""
- self.xmldoc = file(NOXRDS_FILE).read()
- self.failUnlessRaises(
- etxrd.XRDSError,
- services.applyFilter, self.yadis_url, self.xmldoc, None)
-
- def testEmpty(self):
- """Make sure that we get an exception when an XRDS element is
- not present"""
- self.xmldoc = ''
- self.failUnlessRaises(
- etxrd.XRDSError,
- services.applyFilter, self.yadis_url, self.xmldoc, None)
-
- def testNoXRD(self):
- """Make sure that we get an exception when there is no XRD
- element present."""
- self.xmldoc = file(NOXRD_FILE).read()
- self.failUnlessRaises(
- etxrd.XRDSError,
- services.applyFilter, self.yadis_url, self.xmldoc, None)
-
-
-class TestCanonicalID(unittest.TestCase):
-
- def mkTest(iname, filename, expectedID):
- """This function builds a method that runs the CanonicalID
- test for the given set of inputs"""
-
- filename = datapath(filename)
- def test(self):
- xrds = etxrd.parseXRDS(file(filename).read())
- self._getCanonicalID(iname, xrds, expectedID)
- return test
-
- test_delegated = mkTest(
- "@ootao*test1", "delegated-20060809.xrds",
- "@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01")
-
- test_delegated_r1 = mkTest(
- "@ootao*test1", "delegated-20060809-r1.xrds",
- "@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01")
-
- test_delegated_r2 = mkTest(
- "@ootao*test1", "delegated-20060809-r2.xrds",
- "@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01")
-
- test_sometimesprefix = mkTest(
- "@ootao*test1", "sometimesprefix.xrds",
- "@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01")
-
- test_prefixsometimes = mkTest(
- "@ootao*test1", "prefixsometimes.xrds",
- "@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01")
-
- test_spoof1 = mkTest("=keturn*isDrummond", "spoof1.xrds", etxrd.XRDSFraud)
-
- test_spoof2 = mkTest("=keturn*isDrummond", "spoof2.xrds", etxrd.XRDSFraud)
-
- test_spoof3 = mkTest("@keturn*is*drummond", "spoof3.xrds", etxrd.XRDSFraud)
-
- test_status222 = mkTest("=x", "status222.xrds", None)
-
- test_multisegment_xri = mkTest('xri://=nishitani*masaki',
- 'subsegments.xrds',
- '=!E117.EF2F.454B.C707!0000.0000.3B9A.CA01')
-
- test_iri_auth_not_allowed = mkTest(
- "phreak.example.com", "delegated-20060809-r2.xrds", etxrd.XRDSFraud)
- test_iri_auth_not_allowed.__doc__ = \
- "Don't let IRI authorities be canonical for the GCS."
-
- # TODO: Refs
- # test_ref = mkTest("@ootao*test.ref", "ref.xrds", "@!BAE.A650.823B.2475")
-
- # TODO: Add a IRI authority with an IRI canonicalID.
- # TODO: Add test cases with real examples of multiple CanonicalIDs
- # somewhere in the resolution chain.
-
- def _getCanonicalID(self, iname, xrds, expectedID):
- if isinstance(expectedID, (str, unicode, type(None))):
- cid = etxrd.getCanonicalID(iname, xrds)
- self.failUnlessEqual(cid, expectedID and xri.XRI(expectedID))
- elif issubclass(expectedID, etxrd.XRDSError):
- self.failUnlessRaises(expectedID, etxrd.getCanonicalID,
- iname, xrds)
- else:
- self.fail("Don't know how to test for expected value %r"
- % (expectedID,))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_examples.py b/askbot/deps/openid/test/test_examples.py
deleted file mode 100644
index d2360354..00000000
--- a/askbot/deps/openid/test/test_examples.py
+++ /dev/null
@@ -1,185 +0,0 @@
-"Test some examples."
-
-import socket
-import os.path, unittest, sys, time
-from cStringIO import StringIO
-
-import twill.commands, twill.parse, twill.unit
-
-from askbot.deps.openid.consumer.discover import \
- OpenIDServiceEndpoint, OPENID_1_1_TYPE
-from askbot.deps.openid.consumer.consumer import AuthRequest
-
-class TwillTest(twill.unit.TestInfo):
- """Variant of twill.unit.TestInfo that runs a function as a test script,
- not twill script from a file.
- """
-
- # twill.unit is pretty small to start with, we're overriding
- # run_script and bypassing twill.parse, so it may make sense to
- # rewrite twill.unit altogether.
-
- # Desirable features:
- # * better unittest.TestCase integration.
- # - handle logs on setup and teardown.
- # - treat TwillAssertionError as failed test assertion, make twill
- # assertions more consistant with TestCase.failUnless idioms.
- # - better error reporting on failed assertions.
- # - The amount of functions passed back and forth between TestInfo
- # and TestCase is currently pretty silly.
- # * access to child process's logs.
- # TestInfo.start_server redirects stdout/stderr to StringIO
- # objects which are, afaict, inaccessible to the caller of
- # test.unit.run_child_process.
- # * notice when the child process dies, i.e. if you muck up and
- # your runExampleServer function throws an exception.
-
- def run_script(self):
- time.sleep(self.sleep)
- # twill.commands.go(self.get_url())
- self.script(self)
-
-
-def splitDir(d, count):
- # in python2.4 and above, it's easier to spell this as
- # d.rsplit(os.sep, count)
- for i in xrange(count):
- d = os.path.dirname(d)
- return d
-
-def runExampleServer(host, port, data_path):
- thisfile = os.path.abspath(sys.modules[__name__].__file__)
- topDir = splitDir(thisfile, 3)
- exampleDir = os.path.join(topDir, 'examples')
- serverExample = os.path.join(exampleDir, 'server.py')
- serverModule = {}
- execfile(serverExample, serverModule)
- serverMain = serverModule['main']
-
- serverMain(host, port, data_path)
-
-
-
-class TestServer(unittest.TestCase):
- """Acceptance tests for examples/server.py.
-
- These are more acceptance tests than unit tests as they actually
- start the whole server running and test it on its external HTTP
- interface.
- """
-
- def setUp(self):
- self.twillOutput = StringIO()
- self.twillErr = StringIO()
- twill.set_output(self.twillOutput)
- twill.set_errout(self.twillErr)
- # FIXME: make sure we pick an available port.
- self.server_port = 8080
-
- # We need something to feed the server as a realm, but it needn't
- # be reachable. (Until we test realm verification.)
- self.realm = 'http://127.0.0.1/%s' % (self.id(),)
- self.return_to = self.realm + '/return_to'
-
- twill.commands.reset_browser()
-
-
- def runExampleServer(self):
- """Zero-arg run-the-server function to be passed to TestInfo."""
- # FIXME - make sure sstore starts clean.
- runExampleServer('127.0.0.1', self.server_port, 'sstore')
-
-
- def v1endpoint(self, port):
- """Return an OpenID 1.1 OpenIDServiceEndpoint for the server."""
- base = "http://%s:%s" % (socket.getfqdn('127.0.0.1'), port)
- ep = OpenIDServiceEndpoint()
- ep.claimed_id = base + "/id/bob"
- ep.server_url = base + "/openidserver"
- ep.type_uris = [OPENID_1_1_TYPE]
- return ep
-
-
- # TODO: test discovery
-
- def test_checkidv1(self):
- """OpenID 1.1 checkid_setup request."""
- ti = TwillTest(self.twill_checkidv1, self.runExampleServer,
- self.server_port, sleep=0.2)
- twill.unit.run_test(ti)
-
- if self.twillErr.getvalue():
- self.fail(self.twillErr.getvalue())
-
-
- def test_allowed(self):
- """OpenID 1.1 checkid_setup request."""
- ti = TwillTest(self.twill_allowed, self.runExampleServer,
- self.server_port, sleep=0.2)
- twill.unit.run_test(ti)
-
- if self.twillErr.getvalue():
- self.fail(self.twillErr.getvalue())
-
-
- def twill_checkidv1(self, twillInfo):
- endpoint = self.v1endpoint(self.server_port)
- authreq = AuthRequest(endpoint, assoc=None)
- url = authreq.redirectURL(self.realm, self.return_to)
-
- c = twill.commands
-
- try:
- c.go(url)
- c.get_browser()._browser.set_handle_redirect(False)
- c.submit("yes")
- c.code(302)
- headers = c.get_browser()._browser.response().info()
- finalURL = headers['Location']
- self.failUnless('openid.mode=id_res' in finalURL, finalURL)
- self.failUnless('openid.identity=' in finalURL, finalURL)
- except twill.commands.TwillAssertionError, e:
- msg = '%s\nFinal page:\n%s' % (
- str(e), c.get_browser().get_html())
- self.fail(msg)
-
-
- def twill_allowed(self, twillInfo):
- endpoint = self.v1endpoint(self.server_port)
- authreq = AuthRequest(endpoint, assoc=None)
- url = authreq.redirectURL(self.realm, self.return_to)
-
- c = twill.commands
-
- try:
- c.go(url)
- c.code(200)
- c.get_browser()._browser.set_handle_redirect(False)
- c.formvalue(1, 'remember', 'true')
- c.find('name="login_as" value="bob"')
- c.submit("yes")
- c.code(302)
- # Since we set remember=yes, the second time we shouldn't
- # see that page.
- c.go(url)
- c.code(302)
- headers = c.get_browser()._browser.response().info()
- finalURL = headers['Location']
- self.failUnless(finalURL.startswith(self.return_to))
- except twill.commands.TwillAssertionError, e:
- from traceback import format_exc
- msg = '%s\nTwill output:%s\nTwill errors:%s\nFinal page:\n%s' % (
- format_exc(),
- self.twillOutput.getvalue(),
- self.twillErr.getvalue(),
- c.get_browser().get_html())
- self.fail(msg)
-
-
- def tearDown(self):
- twill.set_output(None)
- twill.set_errout(None)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_extension.py b/askbot/deps/openid/test/test_extension.py
deleted file mode 100644
index 297adfc3..00000000
--- a/askbot/deps/openid/test/test_extension.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from askbot.deps.openid import extension
-from askbot.deps.openid import message
-
-import unittest
-
-class DummyExtension(extension.Extension):
- ns_uri = 'http://an.extension/'
- ns_alias = 'dummy'
-
- def getExtensionArgs(self):
- return {}
-
-class ToMessageTest(unittest.TestCase):
- def test_OpenID1(self):
- oid1_msg = message.Message(message.OPENID1_NS)
- ext = DummyExtension()
- ext.toMessage(oid1_msg)
- namespaces = oid1_msg.namespaces
- self.failUnless(namespaces.isImplicit(DummyExtension.ns_uri))
- self.failUnlessEqual(
- DummyExtension.ns_uri,
- namespaces.getNamespaceURI(DummyExtension.ns_alias))
- self.failUnlessEqual(DummyExtension.ns_alias,
- namespaces.getAlias(DummyExtension.ns_uri))
-
- def test_OpenID2(self):
- oid2_msg = message.Message(message.OPENID2_NS)
- ext = DummyExtension()
- ext.toMessage(oid2_msg)
- namespaces = oid2_msg.namespaces
- self.failIf(namespaces.isImplicit(DummyExtension.ns_uri))
- self.failUnlessEqual(
- DummyExtension.ns_uri,
- namespaces.getNamespaceURI(DummyExtension.ns_alias))
- self.failUnlessEqual(DummyExtension.ns_alias,
- namespaces.getAlias(DummyExtension.ns_uri))
diff --git a/askbot/deps/openid/test/test_fetchers.py b/askbot/deps/openid/test/test_fetchers.py
deleted file mode 100644
index 2a53fea8..00000000
--- a/askbot/deps/openid/test/test_fetchers.py
+++ /dev/null
@@ -1,285 +0,0 @@
-import warnings
-import unittest
-import sys
-import urllib2
-import socket
-
-from askbot.deps.openid import fetchers
-
-# XXX: make these separate test cases
-
-def failUnlessResponseExpected(expected, actual):
- assert expected.final_url == actual.final_url, (
- "%r != %r" % (expected.final_url, actual.final_url))
- assert expected.status == actual.status
- assert expected.body == actual.body
- got_headers = dict(actual.headers)
- del got_headers['date']
- del got_headers['server']
- for k, v in expected.headers.iteritems():
- assert got_headers[k] == v, (k, v, got_headers[k])
-
-def test_fetcher(fetcher, exc, server):
- def geturl(path):
- return 'http://%s:%s%s' % (socket.getfqdn(server.server_name),
- server.socket.getsockname()[1],
- path)
-
- expected_headers = {'content-type':'text/plain'}
-
- def plain(path, code):
- path = '/' + path
- expected = fetchers.HTTPResponse(
- geturl(path), code, expected_headers, path)
- return (path, expected)
-
- expect_success = fetchers.HTTPResponse(
- geturl('/success'), 200, expected_headers, '/success')
- cases = [
- ('/success', expect_success),
- ('/301redirect', expect_success),
- ('/302redirect', expect_success),
- ('/303redirect', expect_success),
- ('/307redirect', expect_success),
- plain('notfound', 404),
- plain('badreq', 400),
- plain('forbidden', 403),
- plain('error', 500),
- plain('server_error', 503),
- ]
-
- for path, expected in cases:
- fetch_url = geturl(path)
- try:
- actual = fetcher.fetch(fetch_url)
- except (SystemExit, KeyboardInterrupt):
- pass
- except:
- print fetcher, fetch_url
- raise
- else:
- failUnlessResponseExpected(expected, actual)
-
- for err_url in [geturl('/closed'),
- 'http://invalid.janrain.com/',
- 'not:a/url',
- 'ftp://janrain.com/pub/']:
- try:
- result = fetcher.fetch(err_url)
- except (KeyboardInterrupt, SystemExit):
- raise
- except fetchers.HTTPError, why:
- # This is raised by the Curl fetcher for bad cases
- # detected by the fetchers module, but it's a subclass of
- # HTTPFetchingError, so we have to catch it explicitly.
- assert exc
- except fetchers.HTTPFetchingError, why:
- assert not exc, (fetcher, exc, server)
- except:
- assert exc
- else:
- assert False, 'An exception was expected for %r (%r)' % (fetcher, result)
-
-def run_fetcher_tests(server):
- exc_fetchers = []
- for klass, library_name in [
- (fetchers.Urllib2Fetcher, 'urllib2'),
- (fetchers.CurlHTTPFetcher, 'pycurl'),
- (fetchers.HTTPLib2Fetcher, 'httplib2'),
- ]:
- try:
- exc_fetchers.append(klass())
- except RuntimeError, why:
- if why[0].startswith('Cannot find %s library' % (library_name,)):
- try:
- __import__(library_name)
- except ImportError:
- warnings.warn(
- 'Skipping tests for %r fetcher because '
- 'the library did not import.' % (library_name,))
- pass
- else:
- assert False, ('%s present but not detected' % (library_name,))
- else:
- raise
-
- non_exc_fetchers = []
- for f in exc_fetchers:
- non_exc_fetchers.append(fetchers.ExceptionWrappingFetcher(f))
-
- for f in exc_fetchers:
- test_fetcher(f, True, server)
-
- for f in non_exc_fetchers:
- test_fetcher(f, False, server)
-
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-
-class FetcherTestHandler(BaseHTTPRequestHandler):
- cases = {
- '/success':(200, None),
- '/301redirect':(301, '/success'),
- '/302redirect':(302, '/success'),
- '/303redirect':(303, '/success'),
- '/307redirect':(307, '/success'),
- '/notfound':(404, None),
- '/badreq':(400, None),
- '/forbidden':(403, None),
- '/error':(500, None),
- '/server_error':(503, None),
- }
-
- def log_request(self, *args):
- pass
-
- def do_GET(self):
- if self.path == '/closed':
- self.wfile.close()
- else:
- try:
- http_code, location = self.cases[self.path]
- except KeyError:
- self.errorResponse('Bad path')
- else:
- extra_headers = [('Content-type', 'text/plain')]
- if location is not None:
- host, port = self.server.server_address
- base = ('http://%s:%s' % (socket.getfqdn(host), port,))
- location = base + location
- extra_headers.append(('Location', location))
- self._respond(http_code, extra_headers, self.path)
-
- def do_POST(self):
- try:
- http_code, extra_headers = self.cases[self.path]
- except KeyError:
- self.errorResponse('Bad path')
- else:
- if http_code in [301, 302, 303, 307]:
- self.errorResponse()
- else:
- content_type = self.headers.get('content-type', 'text/plain')
- extra_headers.append(('Content-type', content_type))
- content_length = int(self.headers.get('Content-length', '-1'))
- body = self.rfile.read(content_length)
- self._respond(http_code, extra_headers, body)
-
- def errorResponse(self, message=None):
- req = [
- ('HTTP method', self.command),
- ('path', self.path),
- ]
- if message:
- req.append(('message', message))
-
- body_parts = ['Bad request:\r\n']
- for k, v in req:
- body_parts.append(' %s: %s\r\n' % (k, v))
- body = ''.join(body_parts)
- self._respond(400, [('Content-type', 'text/plain')], body)
-
- def _respond(self, http_code, extra_headers, body):
- self.send_response(http_code)
- for k, v in extra_headers:
- self.send_header(k, v)
- self.end_headers()
- self.wfile.write(body)
- self.wfile.close()
-
- def finish(self):
- if not self.wfile.closed:
- self.wfile.flush()
- self.wfile.close()
- self.rfile.close()
-
-def test():
- import socket
- host = socket.getfqdn('127.0.0.1')
- # When I use port 0 here, it works for the first fetch and the
- # next one gets connection refused. Bummer. So instead, pick a
- # port that's *probably* not in use.
- import os
- port = (os.getpid() % 31000) + 1024
-
- server = HTTPServer((host, port), FetcherTestHandler)
-
- import threading
- server_thread = threading.Thread(target=server.serve_forever)
- server_thread.setDaemon(True)
- server_thread.start()
-
- run_fetcher_tests(server)
-
-class FakeFetcher(object):
- sentinel = object()
-
- def fetch(self, *args, **kwargs):
- return self.sentinel
-
-class DefaultFetcherTest(unittest.TestCase):
- def setUp(self):
- """reset the default fetcher to None"""
- fetchers.setDefaultFetcher(None)
-
- def tearDown(self):
- """reset the default fetcher to None"""
- fetchers.setDefaultFetcher(None)
-
- def test_getDefaultNotNone(self):
- """Make sure that None is never returned as a default fetcher"""
- self.failUnless(fetchers.getDefaultFetcher() is not None)
- fetchers.setDefaultFetcher(None)
- self.failUnless(fetchers.getDefaultFetcher() is not None)
-
- def test_setDefault(self):
- """Make sure the getDefaultFetcher returns the object set for
- setDefaultFetcher"""
- sentinel = object()
- fetchers.setDefaultFetcher(sentinel, wrap_exceptions=False)
- self.failUnless(fetchers.getDefaultFetcher() is sentinel)
-
- def test_callFetch(self):
- """Make sure that fetchers.fetch() uses the default fetcher
- instance that was set."""
- fetchers.setDefaultFetcher(FakeFetcher())
- actual = fetchers.fetch('bad://url')
- self.failUnless(actual is FakeFetcher.sentinel)
-
- def test_wrappedByDefault(self):
- """Make sure that the default fetcher instance wraps
- exceptions by default"""
- default_fetcher = fetchers.getDefaultFetcher()
- self.failUnless(isinstance(default_fetcher,
- fetchers.ExceptionWrappingFetcher),
- default_fetcher)
-
- self.failUnlessRaises(fetchers.HTTPFetchingError,
- fetchers.fetch, 'http://invalid.janrain.com/')
-
- def test_notWrapped(self):
- """Make sure that if we set a non-wrapped fetcher as default,
- it will not wrap exceptions."""
- # A fetcher that will raise an exception when it encounters a
- # host that will not resolve
- fetcher = fetchers.Urllib2Fetcher()
- fetchers.setDefaultFetcher(fetcher, wrap_exceptions=False)
-
- self.failIf(isinstance(fetchers.getDefaultFetcher(),
- fetchers.ExceptionWrappingFetcher))
-
- try:
- fetchers.fetch('http://invalid.janrain.com/')
- except fetchers.HTTPFetchingError:
- self.fail('Should not be wrapping exception')
- except:
- exc = sys.exc_info()[1]
- self.failUnless(isinstance(exc, urllib2.URLError), exc)
- pass
- else:
- self.fail('Should have raised an exception')
-
-def pyUnitTests():
- case1 = unittest.FunctionTestCase(test)
- loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
- case2 = loadTests(DefaultFetcherTest)
- return unittest.TestSuite([case1, case2])
diff --git a/askbot/deps/openid/test/test_htmldiscover.py b/askbot/deps/openid/test/test_htmldiscover.py
deleted file mode 100644
index c6206bee..00000000
--- a/askbot/deps/openid/test/test_htmldiscover.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from askbot.deps.openid.consumer.discover import OpenIDServiceEndpoint
-import datadriven
-
-class BadLinksTestCase(datadriven.DataDrivenTestCase):
- cases = [
- '',
- "http://not.in.a.link.tag/",
- '<link rel="openid.server" href="not.in.html.or.head" />',
- ]
-
- def __init__(self, data):
- datadriven.DataDrivenTestCase.__init__(self, data)
- self.data = data
-
- def runOneTest(self):
- actual = OpenIDServiceEndpoint.fromHTML('http://unused.url/', self.data)
- expected = []
- self.failUnlessEqual(expected, actual)
-
-def pyUnitTests():
- return datadriven.loadTests(__name__)
diff --git a/askbot/deps/openid/test/test_message.py b/askbot/deps/openid/test/test_message.py
deleted file mode 100644
index 4b363dcd..00000000
--- a/askbot/deps/openid/test/test_message.py
+++ /dev/null
@@ -1,998 +0,0 @@
-from askbot.deps.openid import message
-from askbot.deps.openid import oidutil
-from askbot.deps.openid.extensions import sreg
-
-import urllib
-import cgi
-import unittest
-
-def mkGetArgTest(ns, key, expected=None):
- def test(self):
- a_default = object()
- self.failUnlessEqual(self.msg.getArg(ns, key), expected)
- if expected is None:
- self.failUnlessEqual(
- self.msg.getArg(ns, key, a_default), a_default)
- self.failUnlessRaises(
- KeyError, self.msg.getArg, ns, key, message.no_default)
- else:
- self.failUnlessEqual(
- self.msg.getArg(ns, key, a_default), expected)
- self.failUnlessEqual(
- self.msg.getArg(ns, key, message.no_default), expected)
-
- return test
-
-class EmptyMessageTest(unittest.TestCase):
- def setUp(self):
- self.msg = message.Message()
-
- def test_toPostArgs(self):
- self.failUnlessEqual(self.msg.toPostArgs(), {})
-
- def test_toArgs(self):
- self.failUnlessEqual(self.msg.toArgs(), {})
-
- def test_toKVForm(self):
- self.failUnlessEqual(self.msg.toKVForm(), '')
-
- def test_toURLEncoded(self):
- self.failUnlessEqual(self.msg.toURLEncoded(), '')
-
- def test_toURL(self):
- base_url = 'http://base.url/'
- self.failUnlessEqual(self.msg.toURL(base_url), base_url)
-
- def test_getOpenID(self):
- self.failUnlessEqual(self.msg.getOpenIDNamespace(), None)
-
- def test_getKeyOpenID(self):
- # Could reasonably return None instead of raising an
- # exception. I'm not sure which one is more right, since this
- # case should only happen when you're building a message from
- # scratch and so have no default namespace.
- self.failUnlessRaises(message.UndefinedOpenIDNamespace,
- self.msg.getKey, message.OPENID_NS, 'foo')
-
- def test_getKeyBARE(self):
- self.failUnlessEqual(self.msg.getKey(message.BARE_NS, 'foo'), 'foo')
-
- def test_getKeyNS1(self):
- self.failUnlessEqual(self.msg.getKey(message.OPENID1_NS, 'foo'), None)
-
- def test_getKeyNS2(self):
- self.failUnlessEqual(self.msg.getKey(message.OPENID2_NS, 'foo'), None)
-
- def test_getKeyNS3(self):
- self.failUnlessEqual(self.msg.getKey('urn:nothing-significant', 'foo'),
- None)
-
- def test_hasKey(self):
- # Could reasonably return False instead of raising an
- # exception. I'm not sure which one is more right, since this
- # case should only happen when you're building a message from
- # scratch and so have no default namespace.
- self.failUnlessRaises(message.UndefinedOpenIDNamespace,
- self.msg.hasKey, message.OPENID_NS, 'foo')
-
- def test_hasKeyBARE(self):
- self.failUnlessEqual(self.msg.hasKey(message.BARE_NS, 'foo'), False)
-
- def test_hasKeyNS1(self):
- self.failUnlessEqual(self.msg.hasKey(message.OPENID1_NS, 'foo'), False)
-
- def test_hasKeyNS2(self):
- self.failUnlessEqual(self.msg.hasKey(message.OPENID2_NS, 'foo'), False)
-
- def test_hasKeyNS3(self):
- self.failUnlessEqual(self.msg.hasKey('urn:nothing-significant', 'foo'),
- False)
-
- def test_getAliasedArgSuccess(self):
- msg = message.Message.fromPostArgs({'openid.ns.test': 'urn://foo',
- 'openid.test.flub': 'bogus'})
- actual_uri = msg.getAliasedArg('ns.test', message.no_default)
- self.assertEquals("urn://foo", actual_uri)
-
- def test_getAliasedArgFailure(self):
- msg = message.Message.fromPostArgs({'openid.test.flub': 'bogus'})
- self.assertRaises(KeyError,
- msg.getAliasedArg, 'ns.test', message.no_default)
-
- def test_getArg(self):
- # Could reasonably return None instead of raising an
- # exception. I'm not sure which one is more right, since this
- # case should only happen when you're building a message from
- # scratch and so have no default namespace.
- self.failUnlessRaises(message.UndefinedOpenIDNamespace,
- self.msg.getArg, message.OPENID_NS, 'foo')
-
- test_getArgBARE = mkGetArgTest(message.BARE_NS, 'foo')
- test_getArgNS1 = mkGetArgTest(message.OPENID1_NS, 'foo')
- test_getArgNS2 = mkGetArgTest(message.OPENID2_NS, 'foo')
- test_getArgNS3 = mkGetArgTest('urn:nothing-significant', 'foo')
-
- def test_getArgs(self):
- # Could reasonably return {} instead of raising an
- # exception. I'm not sure which one is more right, since this
- # case should only happen when you're building a message from
- # scratch and so have no default namespace.
- self.failUnlessRaises(message.UndefinedOpenIDNamespace,
- self.msg.getArgs, message.OPENID_NS)
-
- def test_getArgsBARE(self):
- self.failUnlessEqual(self.msg.getArgs(message.BARE_NS), {})
-
- def test_getArgsNS1(self):
- self.failUnlessEqual(self.msg.getArgs(message.OPENID1_NS), {})
-
- def test_getArgsNS2(self):
- self.failUnlessEqual(self.msg.getArgs(message.OPENID2_NS), {})
-
- def test_getArgsNS3(self):
- self.failUnlessEqual(self.msg.getArgs('urn:nothing-significant'), {})
-
- def test_updateArgs(self):
- self.failUnlessRaises(message.UndefinedOpenIDNamespace,
- self.msg.updateArgs, message.OPENID_NS,
- {'does not':'matter'})
-
- def _test_updateArgsNS(self, ns):
- update_args = {
- 'Camper van Beethoven':'David Lowery',
- 'Magnolia Electric Co.':'Jason Molina',
- }
-
- self.failUnlessEqual(self.msg.getArgs(ns), {})
- self.msg.updateArgs(ns, update_args)
- self.failUnlessEqual(self.msg.getArgs(ns), update_args)
-
- def test_updateArgsBARE(self):
- self._test_updateArgsNS(message.BARE_NS)
-
- def test_updateArgsNS1(self):
- self._test_updateArgsNS(message.OPENID1_NS)
-
- def test_updateArgsNS2(self):
- self._test_updateArgsNS(message.OPENID2_NS)
-
- def test_updateArgsNS3(self):
- self._test_updateArgsNS('urn:nothing-significant')
-
- def test_setArg(self):
- self.failUnlessRaises(message.UndefinedOpenIDNamespace,
- self.msg.setArg, message.OPENID_NS,
- 'does not', 'matter')
-
- def _test_setArgNS(self, ns):
- key = 'Camper van Beethoven'
- value = 'David Lowery'
- self.failUnlessEqual(self.msg.getArg(ns, key), None)
- self.msg.setArg(ns, key, value)
- self.failUnlessEqual(self.msg.getArg(ns, key), value)
-
- def test_setArgBARE(self):
- self._test_setArgNS(message.BARE_NS)
-
- def test_setArgNS1(self):
- self._test_setArgNS(message.OPENID1_NS)
-
- def test_setArgNS2(self):
- self._test_setArgNS(message.OPENID2_NS)
-
- def test_setArgNS3(self):
- self._test_setArgNS('urn:nothing-significant')
-
- def test_setArgToNone(self):
- self.failUnlessRaises(AssertionError, self.msg.setArg,
- message.OPENID1_NS, 'op_endpoint', None)
-
- def test_delArg(self):
- # Could reasonably raise KeyError instead of raising
- # UndefinedOpenIDNamespace. I'm not sure which one is more
- # right, since this case should only happen when you're
- # building a message from scratch and so have no default
- # namespace.
- self.failUnlessRaises(message.UndefinedOpenIDNamespace,
- self.msg.delArg, message.OPENID_NS, 'key')
-
- def _test_delArgNS(self, ns):
- key = 'Camper van Beethoven'
- self.failUnlessRaises(KeyError, self.msg.delArg, ns, key)
-
- def test_delArgBARE(self):
- self._test_delArgNS(message.BARE_NS)
-
- def test_delArgNS1(self):
- self._test_delArgNS(message.OPENID1_NS)
-
- def test_delArgNS2(self):
- self._test_delArgNS(message.OPENID2_NS)
-
- def test_delArgNS3(self):
- self._test_delArgNS('urn:nothing-significant')
-
- def test_isOpenID1(self):
- self.failIf(self.msg.isOpenID1())
-
- def test_isOpenID2(self):
- self.failIf(self.msg.isOpenID2())
-
-class OpenID1MessageTest(unittest.TestCase):
- def setUp(self):
- self.msg = message.Message.fromPostArgs({'openid.mode':'error',
- 'openid.error':'unit test'})
-
- def test_toPostArgs(self):
- self.failUnlessEqual(self.msg.toPostArgs(),
- {'openid.mode':'error',
- 'openid.error':'unit test'})
-
- def test_toArgs(self):
- self.failUnlessEqual(self.msg.toArgs(), {'mode':'error',
- 'error':'unit test'})
-
- def test_toKVForm(self):
- self.failUnlessEqual(self.msg.toKVForm(),
- 'error:unit test\nmode:error\n')
-
- def test_toURLEncoded(self):
- self.failUnlessEqual(self.msg.toURLEncoded(),
- 'openid.error=unit+test&openid.mode=error')
-
- def test_toURL(self):
- base_url = 'http://base.url/'
- actual = self.msg.toURL(base_url)
- actual_base = actual[:len(base_url)]
- self.failUnlessEqual(actual_base, base_url)
- self.failUnlessEqual(actual[len(base_url)], '?')
- query = actual[len(base_url) + 1:]
- parsed = cgi.parse_qs(query)
- self.failUnlessEqual(parsed, {'openid.mode':['error'],
- 'openid.error':['unit test']})
-
- def test_getOpenID(self):
- self.failUnlessEqual(self.msg.getOpenIDNamespace(), message.OPENID1_NS)
-
- def test_getKeyOpenID(self):
- self.failUnlessEqual(self.msg.getKey(message.OPENID_NS, 'mode'),
- 'openid.mode')
-
- def test_getKeyBARE(self):
- self.failUnlessEqual(self.msg.getKey(message.BARE_NS, 'mode'), 'mode')
-
- def test_getKeyNS1(self):
- self.failUnlessEqual(
- self.msg.getKey(message.OPENID1_NS, 'mode'), 'openid.mode')
-
- def test_getKeyNS2(self):
- self.failUnlessEqual(self.msg.getKey(message.OPENID2_NS, 'mode'), None)
-
- def test_getKeyNS3(self):
- self.failUnlessEqual(
- self.msg.getKey('urn:nothing-significant', 'mode'), None)
-
- def test_hasKey(self):
- self.failUnlessEqual(self.msg.hasKey(message.OPENID_NS, 'mode'), True)
-
- def test_hasKeyBARE(self):
- self.failUnlessEqual(self.msg.hasKey(message.BARE_NS, 'mode'), False)
-
- def test_hasKeyNS1(self):
- self.failUnlessEqual(self.msg.hasKey(message.OPENID1_NS, 'mode'), True)
-
- def test_hasKeyNS2(self):
- self.failUnlessEqual(
- self.msg.hasKey(message.OPENID2_NS, 'mode'), False)
-
- def test_hasKeyNS3(self):
- self.failUnlessEqual(
- self.msg.hasKey('urn:nothing-significant', 'mode'), False)
-
- test_getArgBARE = mkGetArgTest(message.BARE_NS, 'mode')
- test_getArgNS = mkGetArgTest(message.OPENID_NS, 'mode', 'error')
- test_getArgNS1 = mkGetArgTest(message.OPENID1_NS, 'mode', 'error')
- test_getArgNS2 = mkGetArgTest(message.OPENID2_NS, 'mode')
- test_getArgNS3 = mkGetArgTest('urn:nothing-significant', 'mode')
-
- def test_getArgs(self):
- self.failUnlessEqual(self.msg.getArgs(message.OPENID_NS),
- {'mode':'error',
- 'error':'unit test',
- })
-
- def test_getArgsBARE(self):
- self.failUnlessEqual(self.msg.getArgs(message.BARE_NS), {})
-
- def test_getArgsNS1(self):
- self.failUnlessEqual(self.msg.getArgs(message.OPENID1_NS),
- {'mode':'error',
- 'error':'unit test',
- })
-
- def test_getArgsNS2(self):
- self.failUnlessEqual(self.msg.getArgs(message.OPENID2_NS), {})
-
- def test_getArgsNS3(self):
- self.failUnlessEqual(self.msg.getArgs('urn:nothing-significant'), {})
-
- def _test_updateArgsNS(self, ns, before=None):
- if before is None:
- before = {}
- update_args = {
- 'Camper van Beethoven':'David Lowery',
- 'Magnolia Electric Co.':'Jason Molina',
- }
-
- self.failUnlessEqual(self.msg.getArgs(ns), before)
- self.msg.updateArgs(ns, update_args)
- after = dict(before)
- after.update(update_args)
- self.failUnlessEqual(self.msg.getArgs(ns), after)
-
- def test_updateArgs(self):
- self._test_updateArgsNS(message.OPENID_NS,
- before={'mode':'error', 'error':'unit test'})
-
- def test_updateArgsBARE(self):
- self._test_updateArgsNS(message.BARE_NS)
-
- def test_updateArgsNS1(self):
- self._test_updateArgsNS(message.OPENID1_NS,
- before={'mode':'error', 'error':'unit test'})
-
- def test_updateArgsNS2(self):
- self._test_updateArgsNS(message.OPENID2_NS)
-
- def test_updateArgsNS3(self):
- self._test_updateArgsNS('urn:nothing-significant')
-
- def _test_setArgNS(self, ns):
- key = 'Camper van Beethoven'
- value = 'David Lowery'
- self.failUnlessEqual(self.msg.getArg(ns, key), None)
- self.msg.setArg(ns, key, value)
- self.failUnlessEqual(self.msg.getArg(ns, key), value)
-
- def test_setArg(self):
- self._test_setArgNS(message.OPENID_NS)
-
- def test_setArgBARE(self):
- self._test_setArgNS(message.BARE_NS)
-
- def test_setArgNS1(self):
- self._test_setArgNS(message.OPENID1_NS)
-
- def test_setArgNS2(self):
- self._test_setArgNS(message.OPENID2_NS)
-
- def test_setArgNS3(self):
- self._test_setArgNS('urn:nothing-significant')
-
- def _test_delArgNS(self, ns):
- key = 'Camper van Beethoven'
- value = 'David Lowery'
-
- self.failUnlessRaises(KeyError, self.msg.delArg, ns, key)
- self.msg.setArg(ns, key, value)
- self.failUnlessEqual(self.msg.getArg(ns, key), value)
- self.msg.delArg(ns, key)
- self.failUnlessEqual(self.msg.getArg(ns, key), None)
-
- def test_delArg(self):
- self._test_delArgNS(message.OPENID_NS)
-
- def test_delArgBARE(self):
- self._test_delArgNS(message.BARE_NS)
-
- def test_delArgNS1(self):
- self._test_delArgNS(message.OPENID1_NS)
-
- def test_delArgNS2(self):
- self._test_delArgNS(message.OPENID2_NS)
-
- def test_delArgNS3(self):
- self._test_delArgNS('urn:nothing-significant')
-
-
- def test_isOpenID1(self):
- self.failUnless(self.msg.isOpenID1())
-
- def test_isOpenID2(self):
- self.failIf(self.msg.isOpenID2())
-
-class OpenID1ExplicitMessageTest(unittest.TestCase):
- def setUp(self):
- self.msg = message.Message.fromPostArgs({'openid.mode':'error',
- 'openid.error':'unit test',
- 'openid.ns':message.OPENID1_NS
- })
-
- def test_toPostArgs(self):
- self.failUnlessEqual(self.msg.toPostArgs(),
- {'openid.mode':'error',
- 'openid.error':'unit test',
- 'openid.ns':message.OPENID1_NS
- })
-
- def test_toArgs(self):
- self.failUnlessEqual(self.msg.toArgs(), {'mode':'error',
- 'error':'unit test',
- 'ns':message.OPENID1_NS})
-
- def test_toKVForm(self):
- self.failUnlessEqual(self.msg.toKVForm(),
- 'error:unit test\nmode:error\nns:%s\n'
- %message.OPENID1_NS)
-
- def test_toURLEncoded(self):
- self.failUnlessEqual(self.msg.toURLEncoded(),
- 'openid.error=unit+test&openid.mode=error&openid.ns=http%3A%2F%2Fopenid.net%2Fsignon%2F1.0')
-
- def test_toURL(self):
- base_url = 'http://base.url/'
- actual = self.msg.toURL(base_url)
- actual_base = actual[:len(base_url)]
- self.failUnlessEqual(actual_base, base_url)
- self.failUnlessEqual(actual[len(base_url)], '?')
- query = actual[len(base_url) + 1:]
- parsed = cgi.parse_qs(query)
- self.failUnlessEqual(parsed, {'openid.mode':['error'],
- 'openid.error':['unit test'],
- 'openid.ns':[message.OPENID1_NS]
- })
-
- def test_isOpenID1(self):
- self.failUnless(self.msg.isOpenID1())
-
-
-class OpenID2MessageTest(unittest.TestCase):
- def setUp(self):
- self.msg = message.Message.fromPostArgs({'openid.mode':'error',
- 'openid.error':'unit test',
- 'openid.ns':message.OPENID2_NS
- })
- self.msg.setArg(message.BARE_NS, "xey", "value")
-
- def test_toPostArgs(self):
- self.failUnlessEqual(self.msg.toPostArgs(),
- {'openid.mode':'error',
- 'openid.error':'unit test',
- 'openid.ns':message.OPENID2_NS,
- 'xey': 'value',
- })
-
- def test_toArgs(self):
- # This method can't tolerate BARE_NS.
- self.msg.delArg(message.BARE_NS, "xey")
- self.failUnlessEqual(self.msg.toArgs(), {'mode':'error',
- 'error':'unit test',
- 'ns':message.OPENID2_NS,
- })
-
- def test_toKVForm(self):
- # Can't tolerate BARE_NS in kvform
- self.msg.delArg(message.BARE_NS, "xey")
- self.failUnlessEqual(self.msg.toKVForm(),
- 'error:unit test\nmode:error\nns:%s\n' %
- (message.OPENID2_NS,))
-
- def _test_urlencoded(self, s):
- expected = ('openid.error=unit+test&openid.mode=error&'
- 'openid.ns=%s&xey=value' % (
- urllib.quote(message.OPENID2_NS, ''),))
- self.failUnlessEqual(s, expected)
-
-
- def test_toURLEncoded(self):
- self._test_urlencoded(self.msg.toURLEncoded())
-
- def test_toURL(self):
- base_url = 'http://base.url/'
- actual = self.msg.toURL(base_url)
- actual_base = actual[:len(base_url)]
- self.failUnlessEqual(actual_base, base_url)
- self.failUnlessEqual(actual[len(base_url)], '?')
- query = actual[len(base_url) + 1:]
- self._test_urlencoded(query)
-
- def test_getOpenID(self):
- self.failUnlessEqual(self.msg.getOpenIDNamespace(), message.OPENID2_NS)
-
- def test_getKeyOpenID(self):
- self.failUnlessEqual(self.msg.getKey(message.OPENID_NS, 'mode'),
- 'openid.mode')
-
- def test_getKeyBARE(self):
- self.failUnlessEqual(self.msg.getKey(message.BARE_NS, 'mode'), 'mode')
-
- def test_getKeyNS1(self):
- self.failUnlessEqual(
- self.msg.getKey(message.OPENID1_NS, 'mode'), None)
-
- def test_getKeyNS2(self):
- self.failUnlessEqual(
- self.msg.getKey(message.OPENID2_NS, 'mode'), 'openid.mode')
-
- def test_getKeyNS3(self):
- self.failUnlessEqual(
- self.msg.getKey('urn:nothing-significant', 'mode'), None)
-
- def test_hasKeyOpenID(self):
- self.failUnlessEqual(self.msg.hasKey(message.OPENID_NS, 'mode'), True)
-
- def test_hasKeyBARE(self):
- self.failUnlessEqual(self.msg.hasKey(message.BARE_NS, 'mode'), False)
-
- def test_hasKeyNS1(self):
- self.failUnlessEqual(
- self.msg.hasKey(message.OPENID1_NS, 'mode'), False)
-
- def test_hasKeyNS2(self):
- self.failUnlessEqual(
- self.msg.hasKey(message.OPENID2_NS, 'mode'), True)
-
- def test_hasKeyNS3(self):
- self.failUnlessEqual(
- self.msg.hasKey('urn:nothing-significant', 'mode'), False)
-
- test_getArgBARE = mkGetArgTest(message.BARE_NS, 'mode')
- test_getArgNS = mkGetArgTest(message.OPENID_NS, 'mode', 'error')
- test_getArgNS1 = mkGetArgTest(message.OPENID1_NS, 'mode')
- test_getArgNS2 = mkGetArgTest(message.OPENID2_NS, 'mode', 'error')
- test_getArgNS3 = mkGetArgTest('urn:nothing-significant', 'mode')
-
- def test_getArgsOpenID(self):
- self.failUnlessEqual(self.msg.getArgs(message.OPENID_NS),
- {'mode':'error',
- 'error':'unit test',
- })
-
- def test_getArgsBARE(self):
- self.failUnlessEqual(self.msg.getArgs(message.BARE_NS),
- {'xey': 'value'})
-
- def test_getArgsNS1(self):
- self.failUnlessEqual(self.msg.getArgs(message.OPENID1_NS), {})
-
- def test_getArgsNS2(self):
- self.failUnlessEqual(self.msg.getArgs(message.OPENID2_NS),
- {'mode':'error',
- 'error':'unit test',
- })
-
- def test_getArgsNS3(self):
- self.failUnlessEqual(self.msg.getArgs('urn:nothing-significant'), {})
-
- def _test_updateArgsNS(self, ns, before=None):
- if before is None:
- before = {}
- update_args = {
- 'Camper van Beethoven':'David Lowery',
- 'Magnolia Electric Co.':'Jason Molina',
- }
-
- self.failUnlessEqual(self.msg.getArgs(ns), before)
- self.msg.updateArgs(ns, update_args)
- after = dict(before)
- after.update(update_args)
- self.failUnlessEqual(self.msg.getArgs(ns), after)
-
- def test_updateArgsOpenID(self):
- self._test_updateArgsNS(message.OPENID_NS,
- before={'mode':'error', 'error':'unit test'})
-
- def test_updateArgsBARE(self):
- self._test_updateArgsNS(message.BARE_NS,
- before={'xey':'value'})
-
- def test_updateArgsNS1(self):
- self._test_updateArgsNS(message.OPENID1_NS)
-
- def test_updateArgsNS2(self):
- self._test_updateArgsNS(message.OPENID2_NS,
- before={'mode':'error', 'error':'unit test'})
-
- def test_updateArgsNS3(self):
- self._test_updateArgsNS('urn:nothing-significant')
-
- def _test_setArgNS(self, ns):
- key = 'Camper van Beethoven'
- value = 'David Lowery'
- self.failUnlessEqual(self.msg.getArg(ns, key), None)
- self.msg.setArg(ns, key, value)
- self.failUnlessEqual(self.msg.getArg(ns, key), value)
-
- def test_setArgOpenID(self):
- self._test_setArgNS(message.OPENID_NS)
-
- def test_setArgBARE(self):
- self._test_setArgNS(message.BARE_NS)
-
- def test_setArgNS1(self):
- self._test_setArgNS(message.OPENID1_NS)
-
- def test_setArgNS2(self):
- self._test_setArgNS(message.OPENID2_NS)
-
- def test_setArgNS3(self):
- self._test_setArgNS('urn:nothing-significant')
-
- def test_badAlias(self):
- """Make sure dotted aliases and OpenID protocol fields are not
- allowed as namespace aliases."""
-
- for f in message.OPENID_PROTOCOL_FIELDS + ['dotted.alias']:
- args = {'openid.ns.%s' % f: 'blah',
- 'openid.%s.foo' % f: 'test'}
-
- # .fromPostArgs covers .fromPostArgs, .fromOpenIDArgs,
- # ._fromOpenIDArgs, and .fromOpenIDArgs (since it calls
- # .fromPostArgs).
- self.failUnlessRaises(AssertionError, self.msg.fromPostArgs,
- args)
-
- def test_mysterious_missing_namespace_bug(self):
- """A failing test for bug #112"""
- openid_args = {
- 'assoc_handle': '{{HMAC-SHA256}{1211477242.29743}{v5cadg==}',
- 'claimed_id': 'http://nerdbank.org/OPAffirmative/AffirmativeIdentityWithSregNoAssoc.aspx',
- 'ns.sreg': 'http://openid.net/extensions/sreg/1.1',
- 'response_nonce': '2008-05-22T17:27:22ZUoW5.\\NV',
- 'signed': 'return_to,identity,claimed_id,op_endpoint,response_nonce,ns.sreg,sreg.email,sreg.nickname,assoc_handle',
- 'sig': 'e3eGZ10+TNRZitgq5kQlk5KmTKzFaCRI8OrRoXyoFa4=',
- 'mode': 'check_authentication',
- 'op_endpoint': 'http://nerdbank.org/OPAffirmative/ProviderNoAssoc.aspx',
- 'sreg.nickname': 'Andy',
- 'return_to': 'http://localhost.localdomain:8001/process?janrain_nonce=2008-05-22T17%3A27%3A21ZnxHULd',
- 'invalidate_handle': '{{HMAC-SHA1}{1211477241.92242}{H0akXw==}',
- 'identity': 'http://nerdbank.org/OPAffirmative/AffirmativeIdentityWithSregNoAssoc.aspx',
- 'sreg.email': 'a@b.com'
- }
- m = message.Message.fromOpenIDArgs(openid_args)
-
- self.failUnless(('http://openid.net/extensions/sreg/1.1', 'sreg') in
- list(m.namespaces.iteritems()))
- missing = []
- for k in openid_args['signed'].split(','):
- if not ("openid."+k) in m.toPostArgs().keys():
- missing.append(k)
- self.assertEqual([], missing, missing)
- self.assertEqual(openid_args, m.toArgs())
- self.failUnless(m.isOpenID1())
-
- def test_112B(self):
- args = {'openid.assoc_handle': 'fa1f5ff0-cde4-11dc-a183-3714bfd55ca8',
- 'openid.claimed_id': 'http://binkley.lan/user/test01',
- 'openid.identity': 'http://test01.binkley.lan/',
- 'openid.mode': 'id_res',
- 'openid.ns': 'http://specs.openid.net/auth/2.0',
- 'openid.ns.pape': 'http://specs.openid.net/extensions/pape/1.0',
- 'openid.op_endpoint': 'http://binkley.lan/server',
- 'openid.pape.auth_policies': 'none',
- 'openid.pape.auth_time': '2008-01-28T20:42:36Z',
- 'openid.pape.nist_auth_level': '0',
- 'openid.response_nonce': '2008-01-28T21:07:04Z99Q=',
- 'openid.return_to': 'http://binkley.lan:8001/process?janrain_nonce=2008-01-28T21%3A07%3A02Z0tMIKx',
- 'openid.sig': 'YJlWH4U6SroB1HoPkmEKx9AyGGg=',
- 'openid.signed': 'assoc_handle,identity,response_nonce,return_to,claimed_id,op_endpoint,pape.auth_time,ns.pape,pape.nist_auth_level,pape.auth_policies'
- }
- m = message.Message.fromPostArgs(args)
- missing = []
- for k in args['openid.signed'].split(','):
- if not ("openid."+k) in m.toPostArgs().keys():
- missing.append(k)
- self.assertEqual([], missing, missing)
- self.assertEqual(args, m.toPostArgs())
- self.failUnless(m.isOpenID2())
-
- def test_implicit_sreg_ns(self):
- openid_args = {
- 'sreg.email': 'a@b.com'
- }
- m = message.Message.fromOpenIDArgs(openid_args)
- self.failUnless((sreg.ns_uri, 'sreg') in
- list(m.namespaces.iteritems()))
- self.assertEqual('a@b.com', m.getArg(sreg.ns_uri, 'email'))
- self.assertEqual(openid_args, m.toArgs())
- self.failUnless(m.isOpenID1())
-
- def _test_delArgNS(self, ns):
- key = 'Camper van Beethoven'
- value = 'David Lowery'
-
- self.failUnlessRaises(KeyError, self.msg.delArg, ns, key)
- self.msg.setArg(ns, key, value)
- self.failUnlessEqual(self.msg.getArg(ns, key), value)
- self.msg.delArg(ns, key)
- self.failUnlessEqual(self.msg.getArg(ns, key), None)
-
- def test_delArgOpenID(self):
- self._test_delArgNS(message.OPENID_NS)
-
- def test_delArgBARE(self):
- self._test_delArgNS(message.BARE_NS)
-
- def test_delArgNS1(self):
- self._test_delArgNS(message.OPENID1_NS)
-
- def test_delArgNS2(self):
- self._test_delArgNS(message.OPENID2_NS)
-
- def test_delArgNS3(self):
- self._test_delArgNS('urn:nothing-significant')
-
- def test_overwriteExtensionArg(self):
- ns = 'urn:unittest_extension'
- key = 'mykey'
- value_1 = 'value_1'
- value_2 = 'value_2'
-
- self.msg.setArg(ns, key, value_1)
- self.failUnless(self.msg.getArg(ns, key) == value_1)
- self.msg.setArg(ns, key, value_2)
- self.failUnless(self.msg.getArg(ns, key) == value_2)
-
- def test_argList(self):
- self.failUnlessRaises(TypeError, self.msg.fromPostArgs,
- {'arg': [1, 2, 3]})
-
- def test_isOpenID1(self):
- self.failIf(self.msg.isOpenID1())
-
- def test_isOpenID2(self):
- self.failUnless(self.msg.isOpenID2())
-
-class MessageTest(unittest.TestCase):
- def setUp(self):
- self.postargs = {
- 'openid.ns': message.OPENID2_NS,
- 'openid.mode': 'checkid_setup',
- 'openid.identity': 'http://bogus.example.invalid:port/',
- 'openid.assoc_handle': 'FLUB',
- 'openid.return_to': 'Neverland',
- }
-
- self.action_url = 'scheme://host:port/path?query'
-
- self.form_tag_attrs = {
- 'company': 'janrain',
- 'class': 'fancyCSS',
- }
-
- self.submit_text = 'GO!'
-
- ### Expected data regardless of input
-
- self.required_form_attrs = {
- 'accept-charset':'UTF-8',
- 'enctype':'application/x-www-form-urlencoded',
- 'method': 'post',
- }
-
- def _checkForm(self, html, message_, action_url,
- form_tag_attrs, submit_text):
- E = oidutil.importElementTree()
-
- # Build element tree from HTML source
- input_tree = E.ElementTree(E.fromstring(html))
-
- # Get root element
- form = input_tree.getroot()
-
- # Check required form attributes
- for k, v in self.required_form_attrs.iteritems():
- assert form.attrib[k] == v, \
- "Expected '%s' for required form attribute '%s', got '%s'" % \
- (v, k, form.attrib[k])
-
- # Check extra form attributes
- for k, v in form_tag_attrs.iteritems():
-
- # Skip attributes that already passed the required
- # attribute check, since they should be ignored by the
- # form generation code.
- if k in self.required_form_attrs:
- continue
-
- assert form.attrib[k] == v, \
- "Form attribute '%s' should be '%s', found '%s'" % \
- (k, v, form.attrib[k])
-
- # Check hidden fields against post args
- hiddens = [e for e in form \
- if e.tag.upper() == 'INPUT' and \
- e.attrib['type'].upper() == 'HIDDEN']
-
- # For each post arg, make sure there is a hidden with that
- # value. Make sure there are no other hiddens.
- for name, value in message_.toPostArgs().iteritems():
- for e in hiddens:
- if e.attrib['name'] == name:
- assert e.attrib['value'] == value, \
- "Expected value of hidden input '%s' to be '%s', got '%s'" % \
- (e.attrib['name'], value, e.attrib['value'])
- break
- else:
- self.fail("Post arg '%s' not found in form" % (name,))
-
- for e in hiddens:
- assert e.attrib['name'] in message_.toPostArgs().keys(), \
- "Form element for '%s' not in " + \
- "original message" % (e.attrib['name'])
-
- # Check action URL
- assert form.attrib['action'] == action_url, \
- "Expected form 'action' to be '%s', got '%s'" % \
- (action_url, form.attrib['action'])
-
- # Check submit text
- submits = [e for e in form \
- if e.tag.upper() == 'INPUT' and \
- e.attrib['type'].upper() == 'SUBMIT']
-
- assert len(submits) == 1, \
- "Expected only one 'input' with type = 'submit', got %d" % \
- (len(submits),)
-
- assert submits[0].attrib['value'] == submit_text, \
- "Expected submit value to be '%s', got '%s'" % \
- (submit_text, submits[0].attrib['value'])
-
- def test_toFormMarkup(self):
- m = message.Message.fromPostArgs(self.postargs)
- html = m.toFormMarkup(self.action_url, self.form_tag_attrs,
- self.submit_text)
- self._checkForm(html, m, self.action_url,
- self.form_tag_attrs, self.submit_text)
-
- def test_overrideMethod(self):
- """Be sure that caller cannot change form method to GET."""
- m = message.Message.fromPostArgs(self.postargs)
-
- tag_attrs = dict(self.form_tag_attrs)
- tag_attrs['method'] = 'GET'
-
- html = m.toFormMarkup(self.action_url, self.form_tag_attrs,
- self.submit_text)
- self._checkForm(html, m, self.action_url,
- self.form_tag_attrs, self.submit_text)
-
- def test_overrideRequired(self):
- """Be sure that caller CANNOT change the form charset for
- encoding type."""
- m = message.Message.fromPostArgs(self.postargs)
-
- tag_attrs = dict(self.form_tag_attrs)
- tag_attrs['accept-charset'] = 'UCS4'
- tag_attrs['enctype'] = 'invalid/x-broken'
-
- html = m.toFormMarkup(self.action_url, tag_attrs,
- self.submit_text)
- self._checkForm(html, m, self.action_url,
- tag_attrs, self.submit_text)
-
-
- def test_setOpenIDNamespace_invalid(self):
- m = message.Message()
- invalid_things = [
- # Empty string is not okay here.
- '',
- # Good guess! But wrong.
- 'http://openid.net/signon/2.0',
- # What?
- u'http://specs%\\\r2Eopenid.net/auth/2.0',
- # Too much escapings!
- 'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0',
- # This is a Type URI, not a openid.ns value.
- 'http://specs.openid.net/auth/2.0/signon',
- ]
-
- for x in invalid_things:
- self.failUnlessRaises(message.InvalidOpenIDNamespace,
- m.setOpenIDNamespace, x, False)
-
-
- def test_isOpenID1(self):
- v1_namespaces = [
- # Yes, there are two of them.
- 'http://openid.net/signon/1.1',
- 'http://openid.net/signon/1.0',
- ]
-
- for ns in v1_namespaces:
- m = message.Message(ns)
- self.failUnless(m.isOpenID1(), "%r not recognized as OpenID 1" %
- (ns,))
- self.failUnlessEqual(ns, m.getOpenIDNamespace())
- self.failUnless(m.namespaces.isImplicit(ns),
- m.namespaces.getNamespaceURI(message.NULL_NAMESPACE))
-
- def test_isOpenID2(self):
- ns = 'http://specs.openid.net/auth/2.0'
- m = message.Message(ns)
- self.failUnless(m.isOpenID2())
- self.failIf(m.namespaces.isImplicit(message.NULL_NAMESPACE))
- self.failUnlessEqual(ns, m.getOpenIDNamespace())
-
- def test_setOpenIDNamespace_explicit(self):
- m = message.Message()
- m.setOpenIDNamespace(message.THE_OTHER_OPENID1_NS, False)
- self.failIf(m.namespaces.isImplicit(message.THE_OTHER_OPENID1_NS))
-
- def test_setOpenIDNamespace_implicit(self):
- m = message.Message()
- m.setOpenIDNamespace(message.THE_OTHER_OPENID1_NS, True)
- self.failUnless(m.namespaces.isImplicit(message.THE_OTHER_OPENID1_NS))
-
-
- def test_explicitOpenID11NSSerialzation(self):
- m = message.Message()
- m.setOpenIDNamespace(message.THE_OTHER_OPENID1_NS, implicit=False)
-
- post_args = m.toPostArgs()
- self.failUnlessEqual(post_args,
- {'openid.ns':message.THE_OTHER_OPENID1_NS})
-
- def test_fromPostArgs_ns11(self):
- # An example of the stuff that some Drupal installations send us,
- # which includes openid.ns but is 1.1.
- query = {
- u'openid.assoc_handle': u'',
- u'openid.claimed_id': u'http://foobar.invalid/',
- u'openid.identity': u'http://foobar.myopenid.com',
- u'openid.mode': u'checkid_setup',
- u'openid.ns': u'http://openid.net/signon/1.1',
- u'openid.ns.sreg': u'http://openid.net/extensions/sreg/1.1',
- u'openid.return_to': u'http://drupal.invalid/return_to',
- u'openid.sreg.required': u'nickname,email',
- u'openid.trust_root': u'http://drupal.invalid',
- }
- m = message.Message.fromPostArgs(query)
- self.failUnless(m.isOpenID1())
-
-
-
-class NamespaceMapTest(unittest.TestCase):
- def test_onealias(self):
- nsm = message.NamespaceMap()
- uri = 'http://example.com/foo'
- alias = "foo"
- nsm.addAlias(uri, alias)
- self.failUnless(nsm.getNamespaceURI(alias) == uri)
- self.failUnless(nsm.getAlias(uri) == alias)
-
- def test_iteration(self):
- nsm = message.NamespaceMap()
- uripat = 'http://example.com/foo%r'
-
- nsm.add(uripat%0)
- for n in range(1,23):
- self.failUnless(uripat%(n-1) in nsm)
- self.failUnless(nsm.isDefined(uripat%(n-1)))
- nsm.add(uripat%n)
-
- for (uri, alias) in nsm.iteritems():
- self.failUnless(uri[22:]==alias[3:])
-
- i=0
- it = nsm.iterAliases()
- try:
- while True:
- it.next()
- i += 1
- except StopIteration:
- self.failUnless(i == 23)
-
- i=0
- it = nsm.iterNamespaceURIs()
- try:
- while True:
- it.next()
- i += 1
- except StopIteration:
- self.failUnless(i == 23)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_negotiation.py b/askbot/deps/openid/test/test_negotiation.py
deleted file mode 100644
index c572f9ec..00000000
--- a/askbot/deps/openid/test/test_negotiation.py
+++ /dev/null
@@ -1,271 +0,0 @@
-
-import unittest
-from support import CatchLogs
-
-from askbot.deps.openid.message import Message, OPENID2_NS, OPENID1_NS, OPENID_NS
-from askbot.deps.openid import association
-from askbot.deps.openid.consumer.consumer import GenericConsumer, ServerError
-from askbot.deps.openid.consumer.discover import OpenIDServiceEndpoint, OPENID_2_0_TYPE
-
-class ErrorRaisingConsumer(GenericConsumer):
- """
- A consumer whose _requestAssocation will return predefined results
- instead of trying to actually perform association requests.
- """
-
- # The list of objects to be returned by successive calls to
- # _requestAssocation. Each call will pop the first element from
- # this list and return it to _negotiateAssociation. If the
- # element is a Message object, it will be wrapped in a ServerError
- # exception. Otherwise it will be returned as-is.
- return_messages = []
-
- def _requestAssociation(self, endpoint, assoc_type, session_type):
- m = self.return_messages.pop(0)
- if isinstance(m, Message):
- raise ServerError.fromMessage(m)
- else:
- return m
-
-class TestOpenID2SessionNegotiation(unittest.TestCase, CatchLogs):
- """
- Test the session type negotiation behavior of an OpenID 2
- consumer.
- """
- def setUp(self):
- CatchLogs.setUp(self)
- self.consumer = ErrorRaisingConsumer(store=None)
-
- self.endpoint = OpenIDServiceEndpoint()
- self.endpoint.type_uris = [OPENID_2_0_TYPE]
- self.endpoint.server_url = 'bogus'
-
- def testBadResponse(self):
- """
- Test the case where the response to an associate request is a
- server error or is otherwise undecipherable.
- """
- self.consumer.return_messages = [Message(self.endpoint.preferredNamespace())]
- self.assertEqual(self.consumer._negotiateAssociation(self.endpoint), None)
- self.failUnlessLogMatches('Server error when requesting an association')
-
- def testEmptyAssocType(self):
- """
- Test the case where the association type (assoc_type) returned
- in an unsupported-type response is absent.
- """
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- # not set: msg.delArg(OPENID_NS, 'assoc_type')
- msg.setArg(OPENID_NS, 'session_type', 'new-session-type')
-
- self.consumer.return_messages = [msg]
- self.assertEqual(self.consumer._negotiateAssociation(self.endpoint), None)
-
- self.failUnlessLogMatches('Unsupported association type',
- 'Server responded with unsupported association ' +
- 'session but did not supply a fallback.')
-
- def testEmptySessionType(self):
- """
- Test the case where the session type (session_type) returned
- in an unsupported-type response is absent.
- """
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- msg.setArg(OPENID_NS, 'assoc_type', 'new-assoc-type')
- # not set: msg.setArg(OPENID_NS, 'session_type', None)
-
- self.consumer.return_messages = [msg]
- self.assertEqual(self.consumer._negotiateAssociation(self.endpoint), None)
-
- self.failUnlessLogMatches('Unsupported association type',
- 'Server responded with unsupported association ' +
- 'session but did not supply a fallback.')
-
- def testNotAllowed(self):
- """
- Test the case where an unsupported-type response specifies a
- preferred (assoc_type, session_type) combination that is not
- allowed by the consumer's SessionNegotiator.
- """
- allowed_types = []
-
- negotiator = association.SessionNegotiator(allowed_types)
- self.consumer.negotiator = negotiator
-
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- msg.setArg(OPENID_NS, 'assoc_type', 'not-allowed')
- msg.setArg(OPENID_NS, 'session_type', 'not-allowed')
-
- self.consumer.return_messages = [msg]
- self.assertEqual(self.consumer._negotiateAssociation(self.endpoint), None)
-
- self.failUnlessLogMatches('Unsupported association type',
- 'Server sent unsupported session/association type:')
-
- def testUnsupportedWithRetry(self):
- """
- Test the case where an unsupported-type response triggers a
- retry to get an association with the new preferred type.
- """
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- msg.setArg(OPENID_NS, 'assoc_type', 'HMAC-SHA1')
- msg.setArg(OPENID_NS, 'session_type', 'DH-SHA1')
-
- assoc = association.Association(
- 'handle', 'secret', 'issued', 10000, 'HMAC-SHA1')
-
- self.consumer.return_messages = [msg, assoc]
- self.failUnless(self.consumer._negotiateAssociation(self.endpoint) is assoc)
-
- self.failUnlessLogMatches('Unsupported association type')
-
- def testUnsupportedWithRetryAndFail(self):
- """
- Test the case where an unsupported-typ response triggers a
- retry, but the retry fails and None is returned instead.
- """
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- msg.setArg(OPENID_NS, 'assoc_type', 'HMAC-SHA1')
- msg.setArg(OPENID_NS, 'session_type', 'DH-SHA1')
-
- self.consumer.return_messages = [msg,
- Message(self.endpoint.preferredNamespace())]
-
- self.failUnlessEqual(self.consumer._negotiateAssociation(self.endpoint), None)
-
- self.failUnlessLogMatches('Unsupported association type',
- 'Server %s refused' % (self.endpoint.server_url))
-
- def testValid(self):
- """
- Test the valid case, wherein an association is returned on the
- first attempt to get one.
- """
- assoc = association.Association(
- 'handle', 'secret', 'issued', 10000, 'HMAC-SHA1')
-
- self.consumer.return_messages = [assoc]
- self.failUnless(self.consumer._negotiateAssociation(self.endpoint) is assoc)
- self.failUnlessLogEmpty()
-
-class TestOpenID1SessionNegotiation(unittest.TestCase, CatchLogs):
- """
- Tests for the OpenID 1 consumer association session behavior. See
- the docs for TestOpenID2SessionNegotiation. Notice that this
- class is not a subclass of the OpenID 2 tests. Instead, it uses
- many of the same inputs but inspects the log messages logged with
- oidutil.log. See the calls to self.failUnlessLogMatches. Some of
- these tests pass openid2-style messages to the openid 1
- association processing logic to be sure it ignores the extra data.
- """
- def setUp(self):
- CatchLogs.setUp(self)
- self.consumer = ErrorRaisingConsumer(store=None)
-
- self.endpoint = OpenIDServiceEndpoint()
- self.endpoint.type_uris = [OPENID1_NS]
- self.endpoint.server_url = 'bogus'
-
- def testBadResponse(self):
- self.consumer.return_messages = [Message(self.endpoint.preferredNamespace())]
- self.assertEqual(self.consumer._negotiateAssociation(self.endpoint), None)
- self.failUnlessLogMatches('Server error when requesting an association')
-
- def testEmptyAssocType(self):
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- # not set: msg.setArg(OPENID_NS, 'assoc_type', None)
- msg.setArg(OPENID_NS, 'session_type', 'new-session-type')
-
- self.consumer.return_messages = [msg]
- self.assertEqual(self.consumer._negotiateAssociation(self.endpoint), None)
-
- self.failUnlessLogMatches('Server error when requesting an association')
-
- def testEmptySessionType(self):
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- msg.setArg(OPENID_NS, 'assoc_type', 'new-assoc-type')
- # not set: msg.setArg(OPENID_NS, 'session_type', None)
-
- self.consumer.return_messages = [msg]
- self.assertEqual(self.consumer._negotiateAssociation(self.endpoint), None)
-
- self.failUnlessLogMatches('Server error when requesting an association')
-
- def testNotAllowed(self):
- allowed_types = []
-
- negotiator = association.SessionNegotiator(allowed_types)
- self.consumer.negotiator = negotiator
-
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- msg.setArg(OPENID_NS, 'assoc_type', 'not-allowed')
- msg.setArg(OPENID_NS, 'session_type', 'not-allowed')
-
- self.consumer.return_messages = [msg]
- self.assertEqual(self.consumer._negotiateAssociation(self.endpoint), None)
-
- self.failUnlessLogMatches('Server error when requesting an association')
-
- def testUnsupportedWithRetry(self):
- msg = Message(self.endpoint.preferredNamespace())
- msg.setArg(OPENID_NS, 'error', 'Unsupported type')
- msg.setArg(OPENID_NS, 'error_code', 'unsupported-type')
- msg.setArg(OPENID_NS, 'assoc_type', 'HMAC-SHA1')
- msg.setArg(OPENID_NS, 'session_type', 'DH-SHA1')
-
- assoc = association.Association(
- 'handle', 'secret', 'issued', 10000, 'HMAC-SHA1')
-
- self.consumer.return_messages = [msg, assoc]
- self.failUnless(self.consumer._negotiateAssociation(self.endpoint) is None)
-
- self.failUnlessLogMatches('Server error when requesting an association')
-
- def testValid(self):
- assoc = association.Association(
- 'handle', 'secret', 'issued', 10000, 'HMAC-SHA1')
-
- self.consumer.return_messages = [assoc]
- self.failUnless(self.consumer._negotiateAssociation(self.endpoint) is assoc)
- self.failUnlessLogEmpty()
-
-class TestNegotiatorBehaviors(unittest.TestCase, CatchLogs):
- def setUp(self):
- self.allowed_types = [
- ('HMAC-SHA1', 'no-encryption'),
- ('HMAC-SHA256', 'no-encryption'),
- ]
-
- self.n = association.SessionNegotiator(self.allowed_types)
-
- def testAddAllowedTypeNoSessionTypes(self):
- self.assertRaises(ValueError, self.n.addAllowedType, 'invalid')
-
- def testAddAllowedTypeBadSessionType(self):
- self.assertRaises(ValueError, self.n.addAllowedType, 'assoc1', 'invalid')
-
- def testAddAllowedTypeContents(self):
- assoc_type = 'HMAC-SHA1'
- self.failUnless(self.n.addAllowedType(assoc_type) is None)
-
- for typ in association.getSessionTypes(assoc_type):
- self.failUnless((assoc_type, typ) in self.n.allowed_types)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_nonce.py b/askbot/deps/openid/test/test_nonce.py
deleted file mode 100644
index 5e5a13be..00000000
--- a/askbot/deps/openid/test/test_nonce.py
+++ /dev/null
@@ -1,104 +0,0 @@
-from askbot.deps.openid.test import datadriven
-import time
-import unittest
-import re
-
-from askbot.deps.openid.store.nonce import \
- mkNonce, \
- split as splitNonce, \
- checkTimestamp
-
-nonce_re = re.compile(r'\A\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ')
-
-class NonceTest(unittest.TestCase):
- def test_mkNonce(self):
- nonce = mkNonce()
- self.failUnless(nonce_re.match(nonce))
- self.failUnless(len(nonce) == 26)
-
- def test_mkNonce_when(self):
- nonce = mkNonce(0)
- self.failUnless(nonce_re.match(nonce))
- self.failUnless(nonce.startswith('1970-01-01T00:00:00Z'))
- self.failUnless(len(nonce) == 26)
-
- def test_splitNonce(self):
- s = '1970-01-01T00:00:00Z'
- expected_t = 0
- expected_salt = ''
- actual_t, actual_salt = splitNonce(s)
- self.failUnlessEqual(expected_t, actual_t)
- self.failUnlessEqual(expected_salt, actual_salt)
-
- def test_mkSplit(self):
- t = 42
- nonce_str = mkNonce(t)
- self.failUnless(nonce_re.match(nonce_str))
- et, salt = splitNonce(nonce_str)
- self.failUnlessEqual(len(salt), 6)
- self.failUnlessEqual(et, t)
-
-class BadSplitTest(datadriven.DataDrivenTestCase):
- cases = [
- '',
- '1970-01-01T00:00:00+1:00',
- '1969-01-01T00:00:00Z',
- '1970-00-01T00:00:00Z',
- '1970.01-01T00:00:00Z',
- 'Thu Sep 7 13:29:31 PDT 2006',
- 'monkeys',
- ]
-
- def __init__(self, nonce_str):
- datadriven.DataDrivenTestCase.__init__(self, nonce_str)
- self.nonce_str = nonce_str
-
- def runOneTest(self):
- self.failUnlessRaises(ValueError, splitNonce, self.nonce_str)
-
-class CheckTimestampTest(datadriven.DataDrivenTestCase):
- cases = [
- # exact, no allowed skew
- ('1970-01-01T00:00:00Z', 0, 0, True),
-
- # exact, large skew
- ('1970-01-01T00:00:00Z', 1000, 0, True),
-
- # no allowed skew, one second old
- ('1970-01-01T00:00:00Z', 0, 1, False),
-
- # many seconds old, outside of skew
- ('1970-01-01T00:00:00Z', 10, 50, False),
-
- # one second old, one second skew allowed
- ('1970-01-01T00:00:00Z', 1, 1, True),
-
- # One second in the future, one second skew allowed
- ('1970-01-01T00:00:02Z', 1, 1, True),
-
- # two seconds in the future, one second skew allowed
- ('1970-01-01T00:00:02Z', 1, 0, False),
-
- # malformed nonce string
- ('monkeys', 0, 0, False),
- ]
-
- def __init__(self, nonce_string, allowed_skew, now, expected):
- datadriven.DataDrivenTestCase.__init__(
- self, repr((nonce_string, allowed_skew, now)))
- self.nonce_string = nonce_string
- self.allowed_skew = allowed_skew
- self.now = now
- self.expected = expected
-
- def runOneTest(self):
- actual = checkTimestamp(self.nonce_string, self.allowed_skew, self.now)
- self.failUnlessEqual(bool(self.expected), bool(actual))
-
-def pyUnitTests():
- return datadriven.loadTests(__name__)
-
-if __name__ == '__main__':
- suite = pyUnitTests()
- runner = unittest.TextTestRunner()
- runner.run(suite)
diff --git a/askbot/deps/openid/test/test_openidyadis.py b/askbot/deps/openid/test/test_openidyadis.py
deleted file mode 100644
index dcebf186..00000000
--- a/askbot/deps/openid/test/test_openidyadis.py
+++ /dev/null
@@ -1,164 +0,0 @@
-import unittest
-from askbot.deps.openid.consumer.discover import \
- OpenIDServiceEndpoint, OPENID_1_1_TYPE, OPENID_1_0_TYPE
-
-from askbot.deps.openid.yadis.services import applyFilter
-
-
-XRDS_BOILERPLATE = '''\
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- xmlns:openid="http://openid.net/xmlns/1.0">
- <XRD>
-%s\
- </XRD>
-</xrds:XRDS>
-'''
-
-def mkXRDS(services):
- return XRDS_BOILERPLATE % (services,)
-
-def mkService(uris=None, type_uris=None, local_id=None, dent=' '):
- chunks = [dent, '<Service>\n']
- dent2 = dent + ' '
- if type_uris:
- for type_uri in type_uris:
- chunks.extend([dent2 + '<Type>', type_uri, '</Type>\n'])
-
- if uris:
- for uri in uris:
- if type(uri) is tuple:
- uri, prio = uri
- else:
- prio = None
-
- chunks.extend([dent2, '<URI'])
- if prio is not None:
- chunks.extend([' priority="', str(prio), '"'])
- chunks.extend(['>', uri, '</URI>\n'])
-
- if local_id:
- chunks.extend(
- [dent2, '<openid:Delegate>', local_id, '</openid:Delegate>\n'])
-
- chunks.extend([dent, '</Service>\n'])
-
- return ''.join(chunks)
-
-# Different sets of server URLs for use in the URI tag
-server_url_options = [
- [], # This case should not generate an endpoint object
- ['http://server.url/'],
- ['https://server.url/'],
- ['https://server.url/', 'http://server.url/'],
- ['https://server.url/',
- 'http://server.url/',
- 'http://example.server.url/'],
- ]
-
-# Used for generating test data
-def subsets(l):
- """Generate all non-empty sublists of a list"""
- subsets_list = [[]]
- for x in l:
- subsets_list += [[x] + t for t in subsets_list]
- return subsets_list
-
-# A couple of example extension type URIs. These are not at all
-# official, but are just here for testing.
-ext_types = [
- 'http://janrain.com/extension/blah',
- 'http://openid.net/sreg/1.0',
- ]
-
-# All valid combinations of Type tags that should produce an OpenID endpoint
-type_uri_options = [
- exts + ts
-
- # All non-empty sublists of the valid OpenID type URIs
- for ts in subsets([OPENID_1_0_TYPE, OPENID_1_1_TYPE])
- if ts
-
- # All combinations of extension types (including empty extenstion list)
- for exts in subsets(ext_types)
- ]
-
-# Range of valid Delegate tag values for generating test data
-local_id_options = [
- None,
- 'http://vanity.domain/',
- 'https://somewhere/yadis/',
- ]
-
-# All combinations of valid URIs, Type URIs and Delegate tags
-data = [
- (uris, type_uris, local_id)
- for uris in server_url_options
- for type_uris in type_uri_options
- for local_id in local_id_options
- ]
-
-class OpenIDYadisTest(unittest.TestCase):
- def __init__(self, uris, type_uris, local_id):
- unittest.TestCase.__init__(self)
- self.uris = uris
- self.type_uris = type_uris
- self.local_id = local_id
-
- def shortDescription(self):
- # XXX:
- return 'Successful OpenID Yadis parsing case'
-
- def setUp(self):
- self.yadis_url = 'http://unit.test/'
-
- # Create an XRDS document to parse
- services = mkService(uris=self.uris,
- type_uris=self.type_uris,
- local_id=self.local_id)
- self.xrds = mkXRDS(services)
-
- def runTest(self):
- # Parse into endpoint objects that we will check
- endpoints = applyFilter(
- self.yadis_url, self.xrds, OpenIDServiceEndpoint)
-
- # make sure there are the same number of endpoints as
- # URIs. This assumes that the type_uris contains at least one
- # OpenID type.
- self.failUnlessEqual(len(self.uris), len(endpoints))
-
- # So that we can check equality on the endpoint types
- type_uris = list(self.type_uris)
- type_uris.sort()
-
- seen_uris = []
- for endpoint in endpoints:
- seen_uris.append(endpoint.server_url)
-
- # All endpoints will have same yadis_url
- self.failUnlessEqual(self.yadis_url, endpoint.claimed_id)
-
- # and local_id
- self.failUnlessEqual(self.local_id, endpoint.local_id)
-
- # and types
- actual_types = list(endpoint.type_uris)
- actual_types.sort()
- self.failUnlessEqual(actual_types, type_uris)
-
- # So that they will compare equal, because we don't care what
- # order they are in
- seen_uris.sort()
- uris = list(self.uris)
- uris.sort()
-
- # Make sure we saw all URIs, and saw each one once
- self.failUnlessEqual(uris, seen_uris)
-
-def pyUnitTests():
- cases = []
- for args in data:
- cases.append(OpenIDYadisTest(*args))
- return unittest.TestSuite(cases)
diff --git a/askbot/deps/openid/test/test_pape.py b/askbot/deps/openid/test/test_pape.py
deleted file mode 100644
index c54fb485..00000000
--- a/askbot/deps/openid/test/test_pape.py
+++ /dev/null
@@ -1,9 +0,0 @@
-
-from askbot.deps.openid.extensions import pape
-
-import unittest
-
-class PapeImportTestCase(unittest.TestCase):
- def test_version(self):
- from askbot.deps.openid.extensions.draft import pape5
- self.assert_(pape is pape5)
diff --git a/askbot/deps/openid/test/test_pape_draft2.py b/askbot/deps/openid/test/test_pape_draft2.py
deleted file mode 100644
index 7458a775..00000000
--- a/askbot/deps/openid/test/test_pape_draft2.py
+++ /dev/null
@@ -1,217 +0,0 @@
-
-from askbot.deps.openid.extensions.draft import pape2 as pape
-from askbot.deps.openid.message import *
-from askbot.deps.openid.server import server
-
-import unittest
-
-class PapeRequestTestCase(unittest.TestCase):
- def setUp(self):
- self.req = pape.Request()
-
- def test_construct(self):
- self.failUnlessEqual([], self.req.preferred_auth_policies)
- self.failUnlessEqual(None, self.req.max_auth_age)
- self.failUnlessEqual('pape', self.req.ns_alias)
-
- req2 = pape.Request([pape.AUTH_MULTI_FACTOR], 1000)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], req2.preferred_auth_policies)
- self.failUnlessEqual(1000, req2.max_auth_age)
-
- def test_add_policy_uri(self):
- self.failUnlessEqual([], self.req.preferred_auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], self.req.preferred_auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], self.req.preferred_auth_policies)
- self.req.addPolicyURI(pape.AUTH_PHISHING_RESISTANT)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT],
- self.req.preferred_auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT],
- self.req.preferred_auth_policies)
-
- def test_getExtensionArgs(self):
- self.failUnlessEqual({'preferred_auth_policies': ''}, self.req.getExtensionArgs())
- self.req.addPolicyURI('http://uri')
- self.failUnlessEqual({'preferred_auth_policies': 'http://uri'}, self.req.getExtensionArgs())
- self.req.addPolicyURI('http://zig')
- self.failUnlessEqual({'preferred_auth_policies': 'http://uri http://zig'}, self.req.getExtensionArgs())
- self.req.max_auth_age = 789
- self.failUnlessEqual({'preferred_auth_policies': 'http://uri http://zig', 'max_auth_age': '789'}, self.req.getExtensionArgs())
-
- def test_parseExtensionArgs(self):
- args = {'preferred_auth_policies': 'http://foo http://bar',
- 'max_auth_age': '9'}
- self.req.parseExtensionArgs(args)
- self.failUnlessEqual(9, self.req.max_auth_age)
- self.failUnlessEqual(['http://foo','http://bar'], self.req.preferred_auth_policies)
-
- def test_parseExtensionArgs_empty(self):
- self.req.parseExtensionArgs({})
- self.failUnlessEqual(None, self.req.max_auth_age)
- self.failUnlessEqual([], self.req.preferred_auth_policies)
-
- def test_fromOpenIDRequest(self):
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'checkid_setup',
- 'ns': OPENID2_NS,
- 'ns.pape': pape.ns_uri,
- 'pape.preferred_auth_policies': ' '.join([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT]),
- 'pape.max_auth_age': '5476'
- })
- oid_req = server.OpenIDRequest()
- oid_req.message = openid_req_msg
- req = pape.Request.fromOpenIDRequest(oid_req)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT], req.preferred_auth_policies)
- self.failUnlessEqual(5476, req.max_auth_age)
-
- def test_fromOpenIDRequest_no_pape(self):
- message = Message()
- openid_req = server.OpenIDRequest()
- openid_req.message = message
- pape_req = pape.Request.fromOpenIDRequest(openid_req)
- assert(pape_req is None)
-
- def test_preferred_types(self):
- self.req.addPolicyURI(pape.AUTH_PHISHING_RESISTANT)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- pt = self.req.preferredTypes([pape.AUTH_MULTI_FACTOR,
- pape.AUTH_MULTI_FACTOR_PHYSICAL])
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], pt)
-
-class DummySuccessResponse:
- def __init__(self, message, signed_stuff):
- self.message = message
- self.signed_stuff = signed_stuff
-
- def getSignedNS(self, ns_uri):
- return self.signed_stuff
-
-class PapeResponseTestCase(unittest.TestCase):
- def setUp(self):
- self.req = pape.Response()
-
- def test_construct(self):
- self.failUnlessEqual([], self.req.auth_policies)
- self.failUnlessEqual(None, self.req.auth_time)
- self.failUnlessEqual('pape', self.req.ns_alias)
- self.failUnlessEqual(None, self.req.nist_auth_level)
-
- req2 = pape.Response([pape.AUTH_MULTI_FACTOR], "2004-12-11T10:30:44Z", 3)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], req2.auth_policies)
- self.failUnlessEqual("2004-12-11T10:30:44Z", req2.auth_time)
- self.failUnlessEqual(3, req2.nist_auth_level)
-
- def test_add_policy_uri(self):
- self.failUnlessEqual([], self.req.auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], self.req.auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], self.req.auth_policies)
- self.req.addPolicyURI(pape.AUTH_PHISHING_RESISTANT)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT], self.req.auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT], self.req.auth_policies)
-
- def test_getExtensionArgs(self):
- self.failUnlessEqual({'auth_policies': 'none'}, self.req.getExtensionArgs())
- self.req.addPolicyURI('http://uri')
- self.failUnlessEqual({'auth_policies': 'http://uri'}, self.req.getExtensionArgs())
- self.req.addPolicyURI('http://zig')
- self.failUnlessEqual({'auth_policies': 'http://uri http://zig'}, self.req.getExtensionArgs())
- self.req.auth_time = "1776-07-04T14:43:12Z"
- self.failUnlessEqual({'auth_policies': 'http://uri http://zig', 'auth_time': "1776-07-04T14:43:12Z"}, self.req.getExtensionArgs())
- self.req.nist_auth_level = 3
- self.failUnlessEqual({'auth_policies': 'http://uri http://zig', 'auth_time': "1776-07-04T14:43:12Z", 'nist_auth_level': '3'}, self.req.getExtensionArgs())
-
- def test_getExtensionArgs_error_auth_age(self):
- self.req.auth_time = "long ago"
- self.failUnlessRaises(ValueError, self.req.getExtensionArgs)
-
- def test_getExtensionArgs_error_nist_auth_level(self):
- self.req.nist_auth_level = "high as a kite"
- self.failUnlessRaises(ValueError, self.req.getExtensionArgs)
- self.req.nist_auth_level = 5
- self.failUnlessRaises(ValueError, self.req.getExtensionArgs)
- self.req.nist_auth_level = -1
- self.failUnlessRaises(ValueError, self.req.getExtensionArgs)
-
- def test_parseExtensionArgs(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': '1970-01-01T00:00:00Z'}
- self.req.parseExtensionArgs(args)
- self.failUnlessEqual('1970-01-01T00:00:00Z', self.req.auth_time)
- self.failUnlessEqual(['http://foo','http://bar'], self.req.auth_policies)
-
- def test_parseExtensionArgs_empty(self):
- self.req.parseExtensionArgs({})
- self.failUnlessEqual(None, self.req.auth_time)
- self.failUnlessEqual([], self.req.auth_policies)
-
- def test_parseExtensionArgs_strict_bogus1(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': 'yesterday'}
- self.failUnlessRaises(ValueError, self.req.parseExtensionArgs,
- args, True)
-
- def test_parseExtensionArgs_strict_bogus2(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': '1970-01-01T00:00:00Z',
- 'nist_auth_level': 'some'}
- self.failUnlessRaises(ValueError, self.req.parseExtensionArgs,
- args, True)
-
- def test_parseExtensionArgs_strict_good(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': '1970-01-01T00:00:00Z',
- 'nist_auth_level': '0'}
- self.req.parseExtensionArgs(args, True)
- self.failUnlessEqual(['http://foo','http://bar'], self.req.auth_policies)
- self.failUnlessEqual('1970-01-01T00:00:00Z', self.req.auth_time)
- self.failUnlessEqual(0, self.req.nist_auth_level)
-
- def test_parseExtensionArgs_nostrict_bogus(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': 'when the cows come home',
- 'nist_auth_level': 'some'}
- self.req.parseExtensionArgs(args)
- self.failUnlessEqual(['http://foo','http://bar'], self.req.auth_policies)
- self.failUnlessEqual(None, self.req.auth_time)
- self.failUnlessEqual(None, self.req.nist_auth_level)
-
- def test_fromSuccessResponse(self):
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'id_res',
- 'ns': OPENID2_NS,
- 'ns.pape': pape.ns_uri,
- 'pape.auth_policies': ' '.join([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT]),
- 'pape.auth_time': '1970-01-01T00:00:00Z'
- })
- signed_stuff = {
- 'auth_policies': ' '.join([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT]),
- 'auth_time': '1970-01-01T00:00:00Z'
- }
- oid_req = DummySuccessResponse(openid_req_msg, signed_stuff)
- req = pape.Response.fromSuccessResponse(oid_req)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT], req.auth_policies)
- self.failUnlessEqual('1970-01-01T00:00:00Z', req.auth_time)
-
- def test_fromSuccessResponseNoSignedArgs(self):
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'id_res',
- 'ns': OPENID2_NS,
- 'ns.pape': pape.ns_uri,
- 'pape.auth_policies': ' '.join([pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT]),
- 'pape.auth_time': '1970-01-01T00:00:00Z'
- })
-
- signed_stuff = {}
-
- class NoSigningDummyResponse(DummySuccessResponse):
- def getSignedNS(self, ns_uri):
- return None
-
- oid_req = NoSigningDummyResponse(openid_req_msg, signed_stuff)
- resp = pape.Response.fromSuccessResponse(oid_req)
- self.failUnless(resp is None)
diff --git a/askbot/deps/openid/test/test_pape_draft5.py b/askbot/deps/openid/test/test_pape_draft5.py
deleted file mode 100644
index 35b1a316..00000000
--- a/askbot/deps/openid/test/test_pape_draft5.py
+++ /dev/null
@@ -1,441 +0,0 @@
-
-from askbot.deps.openid.extensions.draft import pape5 as pape
-from askbot.deps.openid.message import *
-from askbot.deps.openid.server import server
-
-import warnings
-warnings.filterwarnings('ignore', module=__name__,
- message='"none" used as a policy URI')
-
-import unittest
-
-class PapeRequestTestCase(unittest.TestCase):
- def setUp(self):
- self.req = pape.Request()
-
- def test_construct(self):
- self.failUnlessEqual([], self.req.preferred_auth_policies)
- self.failUnlessEqual(None, self.req.max_auth_age)
- self.failUnlessEqual('pape', self.req.ns_alias)
- self.failIf(self.req.preferred_auth_level_types)
-
- bogus_levels = ['http://janrain.com/our_levels']
- req2 = pape.Request(
- [pape.AUTH_MULTI_FACTOR], 1000, bogus_levels)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR],
- req2.preferred_auth_policies)
- self.failUnlessEqual(1000, req2.max_auth_age)
- self.failUnlessEqual(bogus_levels, req2.preferred_auth_level_types)
-
- def test_addAuthLevel(self):
- self.req.addAuthLevel('http://example.com/', 'example')
- self.failUnlessEqual(['http://example.com/'],
- self.req.preferred_auth_level_types)
- self.failUnlessEqual('http://example.com/',
- self.req.auth_level_aliases['example'])
-
- self.req.addAuthLevel('http://example.com/1', 'example1')
- self.failUnlessEqual(['http://example.com/', 'http://example.com/1'],
- self.req.preferred_auth_level_types)
-
- self.req.addAuthLevel('http://example.com/', 'exmpl')
- self.failUnlessEqual(['http://example.com/', 'http://example.com/1'],
- self.req.preferred_auth_level_types)
-
- self.req.addAuthLevel('http://example.com/', 'example')
- self.failUnlessEqual(['http://example.com/', 'http://example.com/1'],
- self.req.preferred_auth_level_types)
-
- self.failUnlessRaises(KeyError,
- self.req.addAuthLevel,
- 'http://example.com/2', 'example')
-
- # alias is None; we expect a new one to be generated.
- uri = 'http://another.example.com/'
- self.req.addAuthLevel(uri)
- self.assert_(uri in self.req.auth_level_aliases.values())
-
- # We don't expect a new alias to be generated if one already
- # exists.
- before_aliases = self.req.auth_level_aliases.keys()
- self.req.addAuthLevel(uri)
- after_aliases = self.req.auth_level_aliases.keys()
- self.assertEqual(before_aliases, after_aliases)
-
- def test_add_policy_uri(self):
- self.failUnlessEqual([], self.req.preferred_auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR],
- self.req.preferred_auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR],
- self.req.preferred_auth_policies)
- self.req.addPolicyURI(pape.AUTH_PHISHING_RESISTANT)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR,
- pape.AUTH_PHISHING_RESISTANT],
- self.req.preferred_auth_policies)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR,
- pape.AUTH_PHISHING_RESISTANT],
- self.req.preferred_auth_policies)
-
- def test_getExtensionArgs(self):
- self.failUnlessEqual({'preferred_auth_policies': ''},
- self.req.getExtensionArgs())
- self.req.addPolicyURI('http://uri')
- self.failUnlessEqual(
- {'preferred_auth_policies': 'http://uri'},
- self.req.getExtensionArgs())
- self.req.addPolicyURI('http://zig')
- self.failUnlessEqual(
- {'preferred_auth_policies': 'http://uri http://zig'},
- self.req.getExtensionArgs())
- self.req.max_auth_age = 789
- self.failUnlessEqual(
- {'preferred_auth_policies': 'http://uri http://zig',
- 'max_auth_age': '789'},
- self.req.getExtensionArgs())
-
- def test_getExtensionArgsWithAuthLevels(self):
- uri = 'http://example.com/auth_level'
- alias = 'my_level'
- self.req.addAuthLevel(uri, alias)
-
- uri2 = 'http://example.com/auth_level_2'
- alias2 = 'my_level_2'
- self.req.addAuthLevel(uri2, alias2)
-
- expected_args = {
- ('auth_level.ns.%s' % alias): uri,
- ('auth_level.ns.%s' % alias2): uri2,
- 'preferred_auth_level_types': ' '.join([alias, alias2]),
- 'preferred_auth_policies': '',
- }
-
- self.failUnlessEqual(expected_args, self.req.getExtensionArgs())
-
- def test_parseExtensionArgsWithAuthLevels(self):
- uri = 'http://example.com/auth_level'
- alias = 'my_level'
-
- uri2 = 'http://example.com/auth_level_2'
- alias2 = 'my_level_2'
-
- request_args = {
- ('auth_level.ns.%s' % alias): uri,
- ('auth_level.ns.%s' % alias2): uri2,
- 'preferred_auth_level_types': ' '.join([alias, alias2]),
- 'preferred_auth_policies': '',
- }
-
- # Check request object state
- self.req.parseExtensionArgs(request_args, is_openid1=False, strict=False)
-
- expected_auth_levels = [uri, uri2]
-
- self.assertEqual(expected_auth_levels,
- self.req.preferred_auth_level_types)
- self.assertEqual(uri, self.req.auth_level_aliases[alias])
- self.assertEqual(uri2, self.req.auth_level_aliases[alias2])
-
- def test_parseExtensionArgsWithAuthLevels_openID1(self):
- request_args = {
- 'preferred_auth_level_types':'nist jisa',
- }
- expected_auth_levels = [pape.LEVELS_NIST, pape.LEVELS_JISA]
- self.req.parseExtensionArgs(request_args, is_openid1=True)
- self.assertEqual(expected_auth_levels,
- self.req.preferred_auth_level_types)
-
- self.req = pape.Request()
- self.req.parseExtensionArgs(request_args, is_openid1=False)
- self.assertEqual([],
- self.req.preferred_auth_level_types)
-
- self.req = pape.Request()
- self.failUnlessRaises(ValueError,
- self.req.parseExtensionArgs,
- request_args, is_openid1=False, strict=True)
-
- def test_parseExtensionArgs_ignoreBadAuthLevels(self):
- request_args = {'preferred_auth_level_types':'monkeys'}
- self.req.parseExtensionArgs(request_args, False)
- self.assertEqual([], self.req.preferred_auth_level_types)
-
- def test_parseExtensionArgs_strictBadAuthLevels(self):
- request_args = {'preferred_auth_level_types':'monkeys'}
- self.failUnlessRaises(ValueError, self.req.parseExtensionArgs,
- request_args, is_openid1=False, strict=True)
-
- def test_parseExtensionArgs(self):
- args = {'preferred_auth_policies': 'http://foo http://bar',
- 'max_auth_age': '9'}
- self.req.parseExtensionArgs(args, False)
- self.failUnlessEqual(9, self.req.max_auth_age)
- self.failUnlessEqual(['http://foo','http://bar'],
- self.req.preferred_auth_policies)
- self.failUnlessEqual([], self.req.preferred_auth_level_types)
-
- def test_parseExtensionArgs_strict_bad_auth_age(self):
- args = {'max_auth_age': 'not an int'}
- self.assertRaises(ValueError, self.req.parseExtensionArgs, args,
- is_openid1=False, strict=True)
-
- def test_parseExtensionArgs_empty(self):
- self.req.parseExtensionArgs({}, False)
- self.failUnlessEqual(None, self.req.max_auth_age)
- self.failUnlessEqual([], self.req.preferred_auth_policies)
- self.failUnlessEqual([], self.req.preferred_auth_level_types)
-
- def test_fromOpenIDRequest(self):
- policy_uris = [pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT]
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'checkid_setup',
- 'ns': OPENID2_NS,
- 'ns.pape': pape.ns_uri,
- 'pape.preferred_auth_policies': ' '.join(policy_uris),
- 'pape.max_auth_age': '5476'
- })
- oid_req = server.OpenIDRequest()
- oid_req.message = openid_req_msg
- req = pape.Request.fromOpenIDRequest(oid_req)
- self.failUnlessEqual(policy_uris, req.preferred_auth_policies)
- self.failUnlessEqual(5476, req.max_auth_age)
-
- def test_fromOpenIDRequest_no_pape(self):
- message = Message()
- openid_req = server.OpenIDRequest()
- openid_req.message = message
- pape_req = pape.Request.fromOpenIDRequest(openid_req)
- assert(pape_req is None)
-
- def test_preferred_types(self):
- self.req.addPolicyURI(pape.AUTH_PHISHING_RESISTANT)
- self.req.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- pt = self.req.preferredTypes([pape.AUTH_MULTI_FACTOR,
- pape.AUTH_MULTI_FACTOR_PHYSICAL])
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], pt)
-
-class DummySuccessResponse:
- def __init__(self, message, signed_stuff):
- self.message = message
- self.signed_stuff = signed_stuff
-
- def isOpenID1(self):
- return False
-
- def getSignedNS(self, ns_uri):
- return self.signed_stuff
-
-class PapeResponseTestCase(unittest.TestCase):
- def setUp(self):
- self.resp = pape.Response()
-
- def test_construct(self):
- self.failUnlessEqual([], self.resp.auth_policies)
- self.failUnlessEqual(None, self.resp.auth_time)
- self.failUnlessEqual('pape', self.resp.ns_alias)
- self.failUnlessEqual(None, self.resp.nist_auth_level)
-
- req2 = pape.Response([pape.AUTH_MULTI_FACTOR],
- "2004-12-11T10:30:44Z", {pape.LEVELS_NIST: 3})
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], req2.auth_policies)
- self.failUnlessEqual("2004-12-11T10:30:44Z", req2.auth_time)
- self.failUnlessEqual(3, req2.nist_auth_level)
-
- def test_add_policy_uri(self):
- self.failUnlessEqual([], self.resp.auth_policies)
- self.resp.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], self.resp.auth_policies)
- self.resp.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR], self.resp.auth_policies)
- self.resp.addPolicyURI(pape.AUTH_PHISHING_RESISTANT)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR,
- pape.AUTH_PHISHING_RESISTANT],
- self.resp.auth_policies)
- self.resp.addPolicyURI(pape.AUTH_MULTI_FACTOR)
- self.failUnlessEqual([pape.AUTH_MULTI_FACTOR,
- pape.AUTH_PHISHING_RESISTANT],
- self.resp.auth_policies)
-
- self.failUnlessRaises(RuntimeError, self.resp.addPolicyURI,
- pape.AUTH_NONE)
-
- def test_getExtensionArgs(self):
- self.failUnlessEqual({'auth_policies': pape.AUTH_NONE},
- self.resp.getExtensionArgs())
- self.resp.addPolicyURI('http://uri')
- self.failUnlessEqual({'auth_policies': 'http://uri'},
- self.resp.getExtensionArgs())
- self.resp.addPolicyURI('http://zig')
- self.failUnlessEqual({'auth_policies': 'http://uri http://zig'},
- self.resp.getExtensionArgs())
- self.resp.auth_time = "1776-07-04T14:43:12Z"
- self.failUnlessEqual(
- {'auth_policies': 'http://uri http://zig',
- 'auth_time': "1776-07-04T14:43:12Z"},
- self.resp.getExtensionArgs())
- self.resp.setAuthLevel(pape.LEVELS_NIST, '3')
- self.failUnlessEqual(
- {'auth_policies': 'http://uri http://zig',
- 'auth_time': "1776-07-04T14:43:12Z",
- 'auth_level.nist': '3',
- 'auth_level.ns.nist': pape.LEVELS_NIST},
- self.resp.getExtensionArgs())
-
- def test_getExtensionArgs_error_auth_age(self):
- self.resp.auth_time = "long ago"
- self.failUnlessRaises(ValueError, self.resp.getExtensionArgs)
-
- def test_parseExtensionArgs(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': '1970-01-01T00:00:00Z'}
- self.resp.parseExtensionArgs(args, is_openid1=False)
- self.failUnlessEqual('1970-01-01T00:00:00Z', self.resp.auth_time)
- self.failUnlessEqual(['http://foo','http://bar'],
- self.resp.auth_policies)
-
- def test_parseExtensionArgs_valid_none(self):
- args = {'auth_policies': pape.AUTH_NONE}
- self.resp.parseExtensionArgs(args, is_openid1=False)
- self.failUnlessEqual([], self.resp.auth_policies)
-
- def test_parseExtensionArgs_old_none(self):
- args = {'auth_policies': 'none'}
- self.resp.parseExtensionArgs(args, is_openid1=False)
- self.failUnlessEqual([], self.resp.auth_policies)
-
- def test_parseExtensionArgs_old_none_strict(self):
- args = {'auth_policies': 'none'}
- self.failUnlessRaises(
- ValueError,
- self.resp.parseExtensionArgs, args, is_openid1=False, strict=True)
-
- def test_parseExtensionArgs_empty(self):
- self.resp.parseExtensionArgs({}, is_openid1=False)
- self.failUnlessEqual(None, self.resp.auth_time)
- self.failUnlessEqual([], self.resp.auth_policies)
-
- def test_parseExtensionArgs_empty_strict(self):
- self.failUnlessRaises(
- ValueError,
- self.resp.parseExtensionArgs, {}, is_openid1=False, strict=True)
-
- def test_parseExtensionArgs_ignore_superfluous_none(self):
- policies = [pape.AUTH_NONE, pape.AUTH_MULTI_FACTOR_PHYSICAL]
-
- args = {
- 'auth_policies': ' '.join(policies),
- }
-
- self.resp.parseExtensionArgs(args, is_openid1=False, strict=False)
-
- self.assertEqual([pape.AUTH_MULTI_FACTOR_PHYSICAL],
- self.resp.auth_policies)
-
- def test_parseExtensionArgs_none_strict(self):
- policies = [pape.AUTH_NONE, pape.AUTH_MULTI_FACTOR_PHYSICAL]
-
- args = {
- 'auth_policies': ' '.join(policies),
- }
-
- self.failUnlessRaises(ValueError, self.resp.parseExtensionArgs,
- args, is_openid1=False, strict=True)
-
- def test_parseExtensionArgs_strict_bogus1(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': 'yesterday'}
- self.failUnlessRaises(ValueError, self.resp.parseExtensionArgs,
- args, is_openid1=False, strict=True)
-
- def test_parseExtensionArgs_openid1_strict(self):
- args = {'auth_level.nist': '0',
- 'auth_policies': pape.AUTH_NONE,
- }
- self.resp.parseExtensionArgs(args, strict=True, is_openid1=True)
- self.failUnlessEqual('0', self.resp.getAuthLevel(pape.LEVELS_NIST))
- self.failUnlessEqual([], self.resp.auth_policies)
-
- def test_parseExtensionArgs_strict_no_namespace_decl_openid2(self):
- # Test the case where the namespace is not declared for an
- # auth level.
- args = {'auth_policies': pape.AUTH_NONE,
- 'auth_level.nist': '0',
- }
- self.failUnlessRaises(ValueError, self.resp.parseExtensionArgs,
- args, is_openid1=False, strict=True)
-
- def test_parseExtensionArgs_nostrict_no_namespace_decl_openid2(self):
- # Test the case where the namespace is not declared for an
- # auth level.
- args = {'auth_policies': pape.AUTH_NONE,
- 'auth_level.nist': '0',
- }
- self.resp.parseExtensionArgs(args, is_openid1=False, strict=False)
-
- # There is no namespace declaration for this auth level.
- self.failUnlessRaises(KeyError, self.resp.getAuthLevel,
- pape.LEVELS_NIST)
-
- def test_parseExtensionArgs_strict_good(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': '1970-01-01T00:00:00Z',
- 'auth_level.nist': '0',
- 'auth_level.ns.nist': pape.LEVELS_NIST}
- self.resp.parseExtensionArgs(args, is_openid1=False, strict=True)
- self.failUnlessEqual(['http://foo','http://bar'],
- self.resp.auth_policies)
- self.failUnlessEqual('1970-01-01T00:00:00Z', self.resp.auth_time)
- self.failUnlessEqual(0, self.resp.nist_auth_level)
-
- def test_parseExtensionArgs_nostrict_bogus(self):
- args = {'auth_policies': 'http://foo http://bar',
- 'auth_time': 'when the cows come home',
- 'nist_auth_level': 'some'}
- self.resp.parseExtensionArgs(args, is_openid1=False)
- self.failUnlessEqual(['http://foo','http://bar'],
- self.resp.auth_policies)
- self.failUnlessEqual(None, self.resp.auth_time)
- self.failUnlessEqual(None, self.resp.nist_auth_level)
-
- def test_fromSuccessResponse(self):
- policy_uris = [pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT]
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'id_res',
- 'ns': OPENID2_NS,
- 'ns.pape': pape.ns_uri,
- 'pape.auth_policies': ' '.join(policy_uris),
- 'pape.auth_time': '1970-01-01T00:00:00Z'
- })
- signed_stuff = {
- 'auth_policies': ' '.join(policy_uris),
- 'auth_time': '1970-01-01T00:00:00Z'
- }
- oid_req = DummySuccessResponse(openid_req_msg, signed_stuff)
- req = pape.Response.fromSuccessResponse(oid_req)
- self.failUnlessEqual(policy_uris, req.auth_policies)
- self.failUnlessEqual('1970-01-01T00:00:00Z', req.auth_time)
-
- def test_fromSuccessResponseNoSignedArgs(self):
- policy_uris = [pape.AUTH_MULTI_FACTOR, pape.AUTH_PHISHING_RESISTANT]
- openid_req_msg = Message.fromOpenIDArgs({
- 'mode': 'id_res',
- 'ns': OPENID2_NS,
- 'ns.pape': pape.ns_uri,
- 'pape.auth_policies': ' '.join(policy_uris),
- 'pape.auth_time': '1970-01-01T00:00:00Z'
- })
-
- signed_stuff = {}
-
- class NoSigningDummyResponse(DummySuccessResponse):
- def getSignedNS(self, ns_uri):
- return None
-
- oid_req = NoSigningDummyResponse(openid_req_msg, signed_stuff)
- resp = pape.Response.fromSuccessResponse(oid_req)
- self.failUnless(resp is None)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_parsehtml.py b/askbot/deps/openid/test/test_parsehtml.py
deleted file mode 100644
index bd1b35c6..00000000
--- a/askbot/deps/openid/test/test_parsehtml.py
+++ /dev/null
@@ -1,82 +0,0 @@
-from askbot.deps.openid.yadis.parsehtml import YadisHTMLParser, ParseDone
-from HTMLParser import HTMLParseError
-
-import os.path, unittest, sys
-
-class _TestCase(unittest.TestCase):
- reserved_values = ['None', 'EOF']
-
- def __init__(self, filename, testname, expected, case):
- self.filename = filename
- self.testname = testname
- self.expected = expected
- self.case = case
- unittest.TestCase.__init__(self)
-
- def runTest(self):
- p = YadisHTMLParser()
- try:
- p.feed(self.case)
- except ParseDone, why:
- found = why[0]
-
- # make sure we protect outselves against accidental bogus
- # test cases
- assert found not in self.reserved_values
-
- # convert to a string
- if found is None:
- found = 'None'
-
- msg = "%r != %r for case %s" % (found, self.expected, self.case)
- self.failUnlessEqual(found, self.expected, msg)
- except HTMLParseError:
- self.failUnless(self.expected == 'None', (self.case, self.expected))
- else:
- self.failUnless(self.expected == 'EOF', (self.case, self.expected))
-
- def shortDescription(self):
- return "%s (%s<%s>)" % (
- self.testname,
- self.__class__.__module__,
- os.path.basename(self.filename))
-
-def parseCases(data):
- cases = []
- for chunk in data.split('\f\n'):
- expected, case = chunk.split('\n', 1)
- cases.append((expected, case))
- return cases
-
-def pyUnitTests():
- """Make a pyunit TestSuite from a file defining test cases."""
- s = unittest.TestSuite()
- for (filename, test_num, expected, case) in getCases():
- s.addTest(_TestCase(filename, str(test_num), expected, case))
- return s
-
-def test():
- runner = unittest.TextTestRunner()
- return runner.run(loadTests())
-
-filenames = ['data/test1-parsehtml.txt']
-
-default_test_files = []
-base = os.path.dirname(__file__)
-for filename in filenames:
- full_name = os.path.join(base, filename)
- default_test_files.append(full_name)
-
-def getCases(test_files=default_test_files):
- cases = []
- for filename in test_files:
- test_num = 0
- data = file(filename).read()
- for expected, case in parseCases(data):
- test_num += 1
- cases.append((filename, test_num, expected, case))
- return cases
-
-
-if __name__ == '__main__':
- sys.exit(not test().wasSuccessful())
diff --git a/askbot/deps/openid/test/test_rpverify.py b/askbot/deps/openid/test/test_rpverify.py
deleted file mode 100644
index 2837cb8d..00000000
--- a/askbot/deps/openid/test/test_rpverify.py
+++ /dev/null
@@ -1,246 +0,0 @@
-"""Unit tests for verification of return_to URLs for a realm
-"""
-
-__all__ = ['TestBuildDiscoveryURL']
-
-from askbot.deps.openid.yadis.discover import DiscoveryResult, DiscoveryFailure
-from askbot.deps.openid.yadis import services
-from askbot.deps.openid.server import trustroot
-from askbot.deps.openid.test.support import CatchLogs
-import unittest
-
-# Too many methods does not apply to unit test objects
-#pylint:disable-msg=R0904
-class TestBuildDiscoveryURL(unittest.TestCase):
- """Tests for building the discovery URL from a realm and a
- return_to URL
- """
-
- def failUnlessDiscoURL(self, realm, expected_discovery_url):
- """Build a discovery URL out of the realm and a return_to and
- make sure that it matches the expected discovery URL
- """
- realm_obj = trustroot.TrustRoot.parse(realm)
- actual_discovery_url = realm_obj.buildDiscoveryURL()
- self.failUnlessEqual(expected_discovery_url, actual_discovery_url)
-
- def test_trivial(self):
- """There is no wildcard and the realm is the same as the return_to URL
- """
- self.failUnlessDiscoURL('http://example.com/foo',
- 'http://example.com/foo')
-
- def test_wildcard(self):
- """There is a wildcard
- """
- self.failUnlessDiscoURL('http://*.example.com/foo',
- 'http://www.example.com/foo')
-
-class TestExtractReturnToURLs(unittest.TestCase):
- disco_url = 'http://example.com/'
-
- def setUp(self):
- self.original_discover = services.discover
- services.discover = self.mockDiscover
- self.data = None
-
- def tearDown(self):
- services.discover = self.original_discover
-
- def mockDiscover(self, uri):
- result = DiscoveryResult(uri)
- result.response_text = self.data
- result.normalized_uri = uri
- return result
-
- def failUnlessFileHasReturnURLs(self, filename, expected_return_urls):
- self.failUnlessXRDSHasReturnURLs(file(filename).read(),
- expected_return_urls)
-
- def failUnlessXRDSHasReturnURLs(self, data, expected_return_urls):
- self.data = data
- actual_return_urls = list(trustroot.getAllowedReturnURLs(
- self.disco_url))
-
- self.failUnlessEqual(expected_return_urls, actual_return_urls)
-
- def failUnlessDiscoveryFailure(self, text):
- self.data = text
- self.failUnlessRaises(
- DiscoveryFailure, trustroot.getAllowedReturnURLs, self.disco_url)
-
- def test_empty(self):
- self.failUnlessDiscoveryFailure('')
-
- def test_badXML(self):
- self.failUnlessDiscoveryFailure('>')
-
- def test_noEntries(self):
- self.failUnlessXRDSHasReturnURLs('''\
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- >
- <XRD>
- </XRD>
-</xrds:XRDS>
-''', [])
-
- def test_noReturnToEntries(self):
- self.failUnlessXRDSHasReturnURLs('''\
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- >
- <XRD>
- <Service priority="10">
- <Type>http://specs.openid.net/auth/2.0/server</Type>
- <URI>http://www.myopenid.com/server</URI>
- </Service>
- </XRD>
-</xrds:XRDS>
-''', [])
-
- def test_oneEntry(self):
- self.failUnlessXRDSHasReturnURLs('''\
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- >
- <XRD>
- <Service>
- <Type>http://specs.openid.net/auth/2.0/return_to</Type>
- <URI>http://rp.example.com/return</URI>
- </Service>
- </XRD>
-</xrds:XRDS>
-''', ['http://rp.example.com/return'])
-
- def test_twoEntries(self):
- self.failUnlessXRDSHasReturnURLs('''\
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- >
- <XRD>
- <Service priority="0">
- <Type>http://specs.openid.net/auth/2.0/return_to</Type>
- <URI>http://rp.example.com/return</URI>
- </Service>
- <Service priority="1">
- <Type>http://specs.openid.net/auth/2.0/return_to</Type>
- <URI>http://other.rp.example.com/return</URI>
- </Service>
- </XRD>
-</xrds:XRDS>
-''', ['http://rp.example.com/return',
- 'http://other.rp.example.com/return'])
-
- def test_twoEntries_withOther(self):
- self.failUnlessXRDSHasReturnURLs('''\
-<?xml version="1.0" encoding="UTF-8"?>
-<xrds:XRDS xmlns:xrds="xri://$xrds"
- xmlns="xri://$xrd*($v*2.0)"
- >
- <XRD>
- <Service priority="0">
- <Type>http://specs.openid.net/auth/2.0/return_to</Type>
- <URI>http://rp.example.com/return</URI>
- </Service>
- <Service priority="1">
- <Type>http://specs.openid.net/auth/2.0/return_to</Type>
- <URI>http://other.rp.example.com/return</URI>
- </Service>
- <Service priority="0">
- <Type>http://example.com/LOLCATS</Type>
- <URI>http://example.com/invisible+uri</URI>
- </Service>
- </XRD>
-</xrds:XRDS>
-''', ['http://rp.example.com/return',
- 'http://other.rp.example.com/return'])
-
-
-
-class TestReturnToMatches(unittest.TestCase):
- def test_noEntries(self):
- self.failIf(trustroot.returnToMatches([], 'anything'))
-
- def test_exactMatch(self):
- r = 'http://example.com/return.to'
- self.failUnless(trustroot.returnToMatches([r], r))
-
- def test_garbageMatch(self):
- r = 'http://example.com/return.to'
- self.failUnless(trustroot.returnToMatches(
- ['This is not a URL at all. In fact, it has characters, '
- 'like "<" that are not allowed in URLs',
- r],
- r))
-
- def test_descendant(self):
- r = 'http://example.com/return.to'
- self.failUnless(trustroot.returnToMatches(
- [r],
- 'http://example.com/return.to/user:joe'))
-
- def test_wildcard(self):
- self.failIf(trustroot.returnToMatches(
- ['http://*.example.com/return.to'],
- 'http://example.com/return.to'))
-
- def test_noMatch(self):
- r = 'http://example.com/return.to'
- self.failIf(trustroot.returnToMatches(
- [r],
- 'http://example.com/xss_exploit'))
-
-class TestVerifyReturnTo(unittest.TestCase, CatchLogs):
-
- def setUp(self):
- CatchLogs.setUp(self)
-
- def tearDown(self):
- CatchLogs.tearDown(self)
-
- def test_bogusRealm(self):
- self.failIf(trustroot.verifyReturnTo('', 'http://example.com/'))
-
- def test_verifyWithDiscoveryCalled(self):
- realm = 'http://*.example.com/'
- return_to = 'http://www.example.com/foo'
-
- def vrfy(disco_url):
- self.failUnlessEqual('http://www.example.com/', disco_url)
- return [return_to]
-
- self.failUnless(
- trustroot.verifyReturnTo(realm, return_to, _vrfy=vrfy))
- self.failUnlessLogEmpty()
-
- def test_verifyFailWithDiscoveryCalled(self):
- realm = 'http://*.example.com/'
- return_to = 'http://www.example.com/foo'
-
- def vrfy(disco_url):
- self.failUnlessEqual('http://www.example.com/', disco_url)
- return ['http://something-else.invalid/']
-
- self.failIf(
- trustroot.verifyReturnTo(realm, return_to, _vrfy=vrfy))
- self.failUnlessLogMatches("Failed to validate return_to")
-
- def test_verifyFailIfDiscoveryRedirects(self):
- realm = 'http://*.example.com/'
- return_to = 'http://www.example.com/foo'
-
- def vrfy(disco_url):
- raise trustroot.RealmVerificationRedirected(
- disco_url, "http://redirected.invalid")
-
- self.failIf(
- trustroot.verifyReturnTo(realm, return_to, _vrfy=vrfy))
- self.failUnlessLogMatches("Attempting to verify")
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_server.py b/askbot/deps/openid/test/test_server.py
deleted file mode 100644
index c843f762..00000000
--- a/askbot/deps/openid/test/test_server.py
+++ /dev/null
@@ -1,2064 +0,0 @@
-"""Tests for openid.server.
-"""
-from askbot.deps.openid.server import server
-from askbot.deps.openid import association, cryptutil, oidutil
-from askbot.deps.openid.message import Message, OPENID_NS, OPENID2_NS, OPENID1_NS, \
- IDENTIFIER_SELECT, no_default, OPENID1_URL_LIMIT
-from askbot.deps.openid.store import memstore
-import cgi
-
-import unittest
-import warnings
-
-from urlparse import urlparse
-
-# In general, if you edit or add tests here, try to move in the direction
-# of testing smaller units. For testing the external interfaces, we'll be
-# developing an implementation-agnostic testing suite.
-
-# for more, see /etc/ssh/moduli
-
-ALT_MODULUS = 0xCAADDDEC1667FC68B5FA15D53C4E1532DD24561A1A2D47A12C01ABEA1E00731F6921AAC40742311FDF9E634BB7131BEE1AF240261554389A910425E044E88C8359B010F5AD2B80E29CB1A5B027B19D9E01A6F63A6F45E5D7ED2FF6A2A0085050A7D0CF307C3DB51D2490355907B4427C23A98DF1EB8ABEF2BA209BB7AFFE86A7
-ALT_GEN = 5
-
-class CatchLogs(object):
- def setUp(self):
- self.old_logger = oidutil.log
- oidutil.log = self.gotLogMessage
- self.messages = []
-
- def gotLogMessage(self, message):
- self.messages.append(message)
-
- def tearDown(self):
- oidutil.log = self.old_logger
-
-class TestProtocolError(unittest.TestCase):
- def test_browserWithReturnTo(self):
- return_to = "http://rp.unittest/consumer"
- # will be a ProtocolError raised by Decode or CheckIDRequest.answer
- args = Message.fromPostArgs({
- 'openid.mode': 'monkeydance',
- 'openid.identity': 'http://wagu.unittest/',
- 'openid.return_to': return_to,
- })
- e = server.ProtocolError(args, "plucky")
- self.failUnless(e.hasReturnTo())
- expected_args = {
- 'openid.mode': ['error'],
- 'openid.error': ['plucky'],
- }
-
- rt_base, result_args = e.encodeToURL().split('?', 1)
- result_args = cgi.parse_qs(result_args)
- self.failUnlessEqual(result_args, expected_args)
-
- def test_browserWithReturnTo_OpenID2_GET(self):
- return_to = "http://rp.unittest/consumer"
- # will be a ProtocolError raised by Decode or CheckIDRequest.answer
- args = Message.fromPostArgs({
- 'openid.ns': OPENID2_NS,
- 'openid.mode': 'monkeydance',
- 'openid.identity': 'http://wagu.unittest/',
- 'openid.claimed_id': 'http://wagu.unittest/',
- 'openid.return_to': return_to,
- })
- e = server.ProtocolError(args, "plucky")
- self.failUnless(e.hasReturnTo())
- expected_args = {
- 'openid.ns': [OPENID2_NS],
- 'openid.mode': ['error'],
- 'openid.error': ['plucky'],
- }
-
- rt_base, result_args = e.encodeToURL().split('?', 1)
- result_args = cgi.parse_qs(result_args)
- self.failUnlessEqual(result_args, expected_args)
-
- def test_browserWithReturnTo_OpenID2_POST(self):
- return_to = "http://rp.unittest/consumer" + ('x' * OPENID1_URL_LIMIT)
- # will be a ProtocolError raised by Decode or CheckIDRequest.answer
- args = Message.fromPostArgs({
- 'openid.ns': OPENID2_NS,
- 'openid.mode': 'monkeydance',
- 'openid.identity': 'http://wagu.unittest/',
- 'openid.claimed_id': 'http://wagu.unittest/',
- 'openid.return_to': return_to,
- })
- e = server.ProtocolError(args, "plucky")
- self.failUnless(e.hasReturnTo())
- expected_args = {
- 'openid.ns': [OPENID2_NS],
- 'openid.mode': ['error'],
- 'openid.error': ['plucky'],
- }
-
- self.failUnless(e.whichEncoding() == server.ENCODE_HTML_FORM)
- self.failUnless(e.toFormMarkup() == e.toMessage().toFormMarkup(
- args.getArg(OPENID_NS, 'return_to')))
-
- def test_browserWithReturnTo_OpenID1_exceeds_limit(self):
- return_to = "http://rp.unittest/consumer" + ('x' * OPENID1_URL_LIMIT)
- # will be a ProtocolError raised by Decode or CheckIDRequest.answer
- args = Message.fromPostArgs({
- 'openid.mode': 'monkeydance',
- 'openid.identity': 'http://wagu.unittest/',
- 'openid.return_to': return_to,
- })
- e = server.ProtocolError(args, "plucky")
- self.failUnless(e.hasReturnTo())
- expected_args = {
- 'openid.mode': ['error'],
- 'openid.error': ['plucky'],
- }
-
- self.failUnless(e.whichEncoding() == server.ENCODE_URL)
-
- rt_base, result_args = e.encodeToURL().split('?', 1)
- result_args = cgi.parse_qs(result_args)
- self.failUnlessEqual(result_args, expected_args)
-
- def test_noReturnTo(self):
- # will be a ProtocolError raised by Decode or CheckIDRequest.answer
- args = Message.fromPostArgs({
- 'openid.mode': 'zebradance',
- 'openid.identity': 'http://wagu.unittest/',
- })
- e = server.ProtocolError(args, "waffles")
- self.failIf(e.hasReturnTo())
- expected = """error:waffles
-mode:error
-"""
- self.failUnlessEqual(e.encodeToKVForm(), expected)
-
-
- def test_noMessage(self):
- e = server.ProtocolError(None, "no moar pancakes")
- self.failIf(e.hasReturnTo())
- self.failUnlessEqual(e.whichEncoding(), None)
-
-
-class TestDecode(unittest.TestCase):
- def setUp(self):
- self.claimed_id = 'http://de.legating.de.coder.unittest/'
- self.id_url = "http://decoder.am.unittest/"
- self.rt_url = "http://rp.unittest/foobot/?qux=zam"
- self.tr_url = "http://rp.unittest/"
- self.assoc_handle = "{assoc}{handle}"
- self.op_endpoint = 'http://endpoint.unittest/encode'
- self.store = memstore.MemoryStore()
- self.server = server.Server(self.store, self.op_endpoint)
- self.decode = self.server.decoder.decode
- self.decode = server.Decoder(self.server).decode
-
- def test_none(self):
- args = {}
- r = self.decode(args)
- self.failUnlessEqual(r, None)
-
- def test_irrelevant(self):
- args = {
- 'pony': 'spotted',
- 'sreg.mutant_power': 'decaffinator',
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
- def test_bad(self):
- args = {
- 'openid.mode': 'twos-compliment',
- 'openid.pants': 'zippered',
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
- def test_dictOfLists(self):
- args = {
- 'openid.mode': ['checkid_setup'],
- 'openid.identity': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.return_to': self.rt_url,
- 'openid.trust_root': self.tr_url,
- }
- try:
- result = self.decode(args)
- except TypeError, err:
- self.failUnless(str(err).find('values') != -1, err)
- else:
- self.fail("Expected TypeError, but got result %s" % (result,))
-
- def test_checkidImmediate(self):
- args = {
- 'openid.mode': 'checkid_immediate',
- 'openid.identity': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.return_to': self.rt_url,
- 'openid.trust_root': self.tr_url,
- # should be ignored
- 'openid.some.extension': 'junk',
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.CheckIDRequest))
- self.failUnlessEqual(r.mode, "checkid_immediate")
- self.failUnlessEqual(r.immediate, True)
- self.failUnlessEqual(r.identity, self.id_url)
- self.failUnlessEqual(r.trust_root, self.tr_url)
- self.failUnlessEqual(r.return_to, self.rt_url)
- self.failUnlessEqual(r.assoc_handle, self.assoc_handle)
-
- def test_checkidSetup(self):
- args = {
- 'openid.mode': 'checkid_setup',
- 'openid.identity': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.return_to': self.rt_url,
- 'openid.trust_root': self.tr_url,
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.CheckIDRequest))
- self.failUnlessEqual(r.mode, "checkid_setup")
- self.failUnlessEqual(r.immediate, False)
- self.failUnlessEqual(r.identity, self.id_url)
- self.failUnlessEqual(r.trust_root, self.tr_url)
- self.failUnlessEqual(r.return_to, self.rt_url)
-
- def test_checkidSetupOpenID2(self):
- args = {
- 'openid.ns': OPENID2_NS,
- 'openid.mode': 'checkid_setup',
- 'openid.identity': self.id_url,
- 'openid.claimed_id': self.claimed_id,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.return_to': self.rt_url,
- 'openid.realm': self.tr_url,
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.CheckIDRequest))
- self.failUnlessEqual(r.mode, "checkid_setup")
- self.failUnlessEqual(r.immediate, False)
- self.failUnlessEqual(r.identity, self.id_url)
- self.failUnlessEqual(r.claimed_id, self.claimed_id)
- self.failUnlessEqual(r.trust_root, self.tr_url)
- self.failUnlessEqual(r.return_to, self.rt_url)
-
- def test_checkidSetupNoClaimedIDOpenID2(self):
- args = {
- 'openid.ns': OPENID2_NS,
- 'openid.mode': 'checkid_setup',
- 'openid.identity': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.return_to': self.rt_url,
- 'openid.realm': self.tr_url,
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
- def test_checkidSetupNoIdentityOpenID2(self):
- args = {
- 'openid.ns': OPENID2_NS,
- 'openid.mode': 'checkid_setup',
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.return_to': self.rt_url,
- 'openid.realm': self.tr_url,
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.CheckIDRequest))
- self.failUnlessEqual(r.mode, "checkid_setup")
- self.failUnlessEqual(r.immediate, False)
- self.failUnlessEqual(r.identity, None)
- self.failUnlessEqual(r.trust_root, self.tr_url)
- self.failUnlessEqual(r.return_to, self.rt_url)
-
- def test_checkidSetupNoReturnOpenID1(self):
- """Make sure an OpenID 1 request cannot be decoded if it lacks
- a return_to.
- """
- args = {
- 'openid.mode': 'checkid_setup',
- 'openid.identity': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.trust_root': self.tr_url,
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
- def test_checkidSetupNoReturnOpenID2(self):
- """Make sure an OpenID 2 request with no return_to can be
- decoded, and make sure a response to such a request raises
- NoReturnToError.
- """
- args = {
- 'openid.ns': OPENID2_NS,
- 'openid.mode': 'checkid_setup',
- 'openid.identity': self.id_url,
- 'openid.claimed_id': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.realm': self.tr_url,
- }
- self.failUnless(isinstance(self.decode(args), server.CheckIDRequest))
-
- req = self.decode(args)
- self.assertRaises(server.NoReturnToError, req.answer, False)
- self.assertRaises(server.NoReturnToError, req.encodeToURL, 'bogus')
- self.assertRaises(server.NoReturnToError, req.getCancelURL)
-
- def test_checkidSetupRealmRequiredOpenID2(self):
- """Make sure that an OpenID 2 request which lacks return_to
- cannot be decoded if it lacks a realm. Spec: This value
- (openid.realm) MUST be sent if openid.return_to is omitted.
- """
- args = {
- 'openid.ns': OPENID2_NS,
- 'openid.mode': 'checkid_setup',
- 'openid.identity': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
- def test_checkidSetupBadReturn(self):
- args = {
- 'openid.mode': 'checkid_setup',
- 'openid.identity': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.return_to': 'not a url',
- }
- try:
- result = self.decode(args)
- except server.ProtocolError, err:
- self.failUnless(err.openid_message)
- else:
- self.fail("Expected ProtocolError, instead returned with %s" %
- (result,))
-
- def test_checkidSetupUntrustedReturn(self):
- args = {
- 'openid.mode': 'checkid_setup',
- 'openid.identity': self.id_url,
- 'openid.assoc_handle': self.assoc_handle,
- 'openid.return_to': self.rt_url,
- 'openid.trust_root': 'http://not-the-return-place.unittest/',
- }
- try:
- result = self.decode(args)
- except server.UntrustedReturnURL, err:
- self.failUnless(err.openid_message)
- else:
- self.fail("Expected UntrustedReturnURL, instead returned with %s" %
- (result,))
-
- def test_checkAuth(self):
- args = {
- 'openid.mode': 'check_authentication',
- 'openid.assoc_handle': '{dumb}{handle}',
- 'openid.sig': 'sigblob',
- 'openid.signed': 'identity,return_to,response_nonce,mode',
- 'openid.identity': 'signedval1',
- 'openid.return_to': 'signedval2',
- 'openid.response_nonce': 'signedval3',
- 'openid.baz': 'unsigned',
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.CheckAuthRequest))
- self.failUnlessEqual(r.mode, 'check_authentication')
- self.failUnlessEqual(r.sig, 'sigblob')
-
-
- def test_checkAuthMissingSignature(self):
- args = {
- 'openid.mode': 'check_authentication',
- 'openid.assoc_handle': '{dumb}{handle}',
- 'openid.signed': 'foo,bar,mode',
- 'openid.foo': 'signedval1',
- 'openid.bar': 'signedval2',
- 'openid.baz': 'unsigned',
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
-
- def test_checkAuthAndInvalidate(self):
- args = {
- 'openid.mode': 'check_authentication',
- 'openid.assoc_handle': '{dumb}{handle}',
- 'openid.invalidate_handle': '[[SMART_handle]]',
- 'openid.sig': 'sigblob',
- 'openid.signed': 'identity,return_to,response_nonce,mode',
- 'openid.identity': 'signedval1',
- 'openid.return_to': 'signedval2',
- 'openid.response_nonce': 'signedval3',
- 'openid.baz': 'unsigned',
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.CheckAuthRequest))
- self.failUnlessEqual(r.invalidate_handle, '[[SMART_handle]]')
-
-
- def test_associateDH(self):
- args = {
- 'openid.mode': 'associate',
- 'openid.session_type': 'DH-SHA1',
- 'openid.dh_consumer_public': "Rzup9265tw==",
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.AssociateRequest))
- self.failUnlessEqual(r.mode, "associate")
- self.failUnlessEqual(r.session.session_type, "DH-SHA1")
- self.failUnlessEqual(r.assoc_type, "HMAC-SHA1")
- self.failUnless(r.session.consumer_pubkey)
-
- def test_associateDHMissingKey(self):
- """Trying DH assoc w/o public key"""
- args = {
- 'openid.mode': 'associate',
- 'openid.session_type': 'DH-SHA1',
- }
- # Using DH-SHA1 without supplying dh_consumer_public is an error.
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
-
- def test_associateDHpubKeyNotB64(self):
- args = {
- 'openid.mode': 'associate',
- 'openid.session_type': 'DH-SHA1',
- 'openid.dh_consumer_public': "donkeydonkeydonkey",
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
-
- def test_associateDHModGen(self):
- # test dh with non-default but valid values for dh_modulus and dh_gen
- args = {
- 'openid.mode': 'associate',
- 'openid.session_type': 'DH-SHA1',
- 'openid.dh_consumer_public': "Rzup9265tw==",
- 'openid.dh_modulus': cryptutil.longToBase64(ALT_MODULUS),
- 'openid.dh_gen': cryptutil.longToBase64(ALT_GEN) ,
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.AssociateRequest))
- self.failUnlessEqual(r.mode, "associate")
- self.failUnlessEqual(r.session.session_type, "DH-SHA1")
- self.failUnlessEqual(r.assoc_type, "HMAC-SHA1")
- self.failUnlessEqual(r.session.dh.modulus, ALT_MODULUS)
- self.failUnlessEqual(r.session.dh.generator, ALT_GEN)
- self.failUnless(r.session.consumer_pubkey)
-
-
- def test_associateDHCorruptModGen(self):
- # test dh with non-default but valid values for dh_modulus and dh_gen
- args = {
- 'openid.mode': 'associate',
- 'openid.session_type': 'DH-SHA1',
- 'openid.dh_consumer_public': "Rzup9265tw==",
- 'openid.dh_modulus': 'pizza',
- 'openid.dh_gen': 'gnocchi',
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
-
- def test_associateDHMissingModGen(self):
- # test dh with non-default but valid values for dh_modulus and dh_gen
- args = {
- 'openid.mode': 'associate',
- 'openid.session_type': 'DH-SHA1',
- 'openid.dh_consumer_public': "Rzup9265tw==",
- 'openid.dh_modulus': 'pizza',
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
-
-# def test_associateDHInvalidModGen(self):
-# # test dh with properly encoded values that are not a valid
-# # modulus/generator combination.
-# args = {
-# 'openid.mode': 'associate',
-# 'openid.session_type': 'DH-SHA1',
-# 'openid.dh_consumer_public': "Rzup9265tw==",
-# 'openid.dh_modulus': cryptutil.longToBase64(9),
-# 'openid.dh_gen': cryptutil.longToBase64(27) ,
-# }
-# self.failUnlessRaises(server.ProtocolError, self.decode, args)
-# test_associateDHInvalidModGen.todo = "low-priority feature"
-
-
- def test_associateWeirdSession(self):
- args = {
- 'openid.mode': 'associate',
- 'openid.session_type': 'FLCL6',
- 'openid.dh_consumer_public': "YQ==\n",
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
-
- def test_associatePlain(self):
- args = {
- 'openid.mode': 'associate',
- }
- r = self.decode(args)
- self.failUnless(isinstance(r, server.AssociateRequest))
- self.failUnlessEqual(r.mode, "associate")
- self.failUnlessEqual(r.session.session_type, "no-encryption")
- self.failUnlessEqual(r.assoc_type, "HMAC-SHA1")
-
- def test_nomode(self):
- args = {
- 'openid.session_type': 'DH-SHA1',
- 'openid.dh_consumer_public': "my public keeey",
- }
- self.failUnlessRaises(server.ProtocolError, self.decode, args)
-
- def test_invalidns(self):
- args = {'openid.ns': 'Tuesday',
- 'openid.mode': 'associate'}
-
- try:
- r = self.decode(args)
- except server.ProtocolError, err:
- # Assert that the ProtocolError does have a Message attached
- # to it, even though the request wasn't a well-formed Message.
- self.failUnless(err.openid_message)
- # The error message contains the bad openid.ns.
- self.failUnless('Tuesday' in str(err), str(err))
- else:
- self.fail("Expected ProtocolError but returned with %r" % (r,))
-
-
-class TestEncode(unittest.TestCase):
- def setUp(self):
- self.encoder = server.Encoder()
- self.encode = self.encoder.encode
- self.op_endpoint = 'http://endpoint.unittest/encode'
- self.store = memstore.MemoryStore()
- self.server = server.Server(self.store, self.op_endpoint)
-
- def test_id_res_OpenID2_GET(self):
- """
- Check that when an OpenID 2 response does not exceed the
- OpenID 1 message size, a GET response (i.e., redirect) is
- issued.
- """
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'ns': OPENID2_NS,
- 'mode': 'id_res',
- 'identity': request.identity,
- 'claimed_id': request.identity,
- 'return_to': request.return_to,
- })
-
- self.failIf(response.renderAsForm())
- self.failUnless(response.whichEncoding() == server.ENCODE_URL)
- webresponse = self.encode(response)
- self.failUnless(webresponse.headers.has_key('location'))
-
- def test_id_res_OpenID2_POST(self):
- """
- Check that when an OpenID 2 response exceeds the OpenID 1
- message size, a POST response (i.e., an HTML form) is
- returned.
- """
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'ns': OPENID2_NS,
- 'mode': 'id_res',
- 'identity': request.identity,
- 'claimed_id': request.identity,
- 'return_to': 'x' * OPENID1_URL_LIMIT,
- })
-
- self.failUnless(response.renderAsForm())
- self.failUnless(len(response.encodeToURL()) > OPENID1_URL_LIMIT)
- self.failUnless(response.whichEncoding() == server.ENCODE_HTML_FORM)
- webresponse = self.encode(response)
- self.failUnlessEqual(webresponse.body, response.toFormMarkup())
-
- def test_toFormMarkup(self):
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'ns': OPENID2_NS,
- 'mode': 'id_res',
- 'identity': request.identity,
- 'claimed_id': request.identity,
- 'return_to': 'x' * OPENID1_URL_LIMIT,
- })
-
- form_markup = response.toFormMarkup({'foo':'bar'})
- self.failUnless(' foo="bar"' in form_markup)
-
- def test_toHTML(self):
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'ns': OPENID2_NS,
- 'mode': 'id_res',
- 'identity': request.identity,
- 'claimed_id': request.identity,
- 'return_to': 'x' * OPENID1_URL_LIMIT,
- })
- html = response.toHTML()
- self.failUnless('<html>' in html)
- self.failUnless('</html>' in html)
- self.failUnless('<body onload=' in html)
- self.failUnless('<form' in html)
- self.failUnless('http://bombom.unittest/' in html)
-
- def test_id_res_OpenID1_exceeds_limit(self):
- """
- Check that when an OpenID 1 response exceeds the OpenID 1
- message size, a GET response is issued. Technically, this
- shouldn't be permitted by the library, but this test is in
- place to preserve the status quo for OpenID 1.
- """
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'mode': 'id_res',
- 'identity': request.identity,
- 'return_to': 'x' * OPENID1_URL_LIMIT,
- })
-
- self.failIf(response.renderAsForm())
- self.failUnless(len(response.encodeToURL()) > OPENID1_URL_LIMIT)
- self.failUnless(response.whichEncoding() == server.ENCODE_URL)
- webresponse = self.encode(response)
- self.failUnlessEqual(webresponse.headers['location'], response.encodeToURL())
-
- def test_id_res(self):
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'mode': 'id_res',
- 'identity': request.identity,
- 'return_to': request.return_to,
- })
- webresponse = self.encode(response)
- self.failUnlessEqual(webresponse.code, server.HTTP_REDIRECT)
- self.failUnless(webresponse.headers.has_key('location'))
-
- location = webresponse.headers['location']
- self.failUnless(location.startswith(request.return_to),
- "%s does not start with %s" % (location,
- request.return_to))
- # argh.
- q2 = dict(cgi.parse_qsl(urlparse(location)[4]))
- expected = response.fields.toPostArgs()
- self.failUnlessEqual(q2, expected)
-
- def test_cancel(self):
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'mode': 'cancel',
- })
- webresponse = self.encode(response)
- self.failUnlessEqual(webresponse.code, server.HTTP_REDIRECT)
- self.failUnless(webresponse.headers.has_key('location'))
-
- def test_cancelToForm(self):
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'mode': 'cancel',
- })
- form = response.toFormMarkup()
- self.failUnless(form)
-
- def test_assocReply(self):
- msg = Message(OPENID2_NS)
- msg.setArg(OPENID2_NS, 'session_type', 'no-encryption')
- request = server.AssociateRequest.fromMessage(msg)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromPostArgs(
- {'openid.assoc_handle': "every-zig"})
- webresponse = self.encode(response)
- body = """assoc_handle:every-zig
-"""
- self.failUnlessEqual(webresponse.code, server.HTTP_OK)
- self.failUnlessEqual(webresponse.headers, {})
- self.failUnlessEqual(webresponse.body, body)
-
- def test_checkauthReply(self):
- request = server.CheckAuthRequest('a_sock_monkey',
- 'siggggg',
- [])
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'is_valid': 'true',
- 'invalidate_handle': 'xXxX:xXXx'
- })
- body = """invalidate_handle:xXxX:xXXx
-is_valid:true
-"""
- webresponse = self.encode(response)
- self.failUnlessEqual(webresponse.code, server.HTTP_OK)
- self.failUnlessEqual(webresponse.headers, {})
- self.failUnlessEqual(webresponse.body, body)
-
- def test_unencodableError(self):
- args = Message.fromPostArgs({
- 'openid.identity': 'http://limu.unittest/',
- })
- e = server.ProtocolError(args, "wet paint")
- self.failUnlessRaises(server.EncodingError, self.encode, e)
-
- def test_encodableError(self):
- args = Message.fromPostArgs({
- 'openid.mode': 'associate',
- 'openid.identity': 'http://limu.unittest/',
- })
- body="error:snoot\nmode:error\n"
- webresponse = self.encode(server.ProtocolError(args, "snoot"))
- self.failUnlessEqual(webresponse.code, server.HTTP_ERROR)
- self.failUnlessEqual(webresponse.headers, {})
- self.failUnlessEqual(webresponse.body, body)
-
-
-
-class TestSigningEncode(unittest.TestCase):
- def setUp(self):
- self._dumb_key = server.Signatory._dumb_key
- self._normal_key = server.Signatory._normal_key
- self.store = memstore.MemoryStore()
- self.server = server.Server(self.store, "http://signing.unittest/enc")
- self.request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- self.request.message = Message(OPENID2_NS)
- self.response = server.OpenIDResponse(self.request)
- self.response.fields = Message.fromOpenIDArgs({
- 'mode': 'id_res',
- 'identity': self.request.identity,
- 'return_to': self.request.return_to,
- })
- self.signatory = server.Signatory(self.store)
- self.encoder = server.SigningEncoder(self.signatory)
- self.encode = self.encoder.encode
-
- def test_idres(self):
- assoc_handle = '{bicycle}{shed}'
- self.store.storeAssociation(
- self._normal_key,
- association.Association.fromExpiresIn(60, assoc_handle,
- 'sekrit', 'HMAC-SHA1'))
- self.request.assoc_handle = assoc_handle
- webresponse = self.encode(self.response)
- self.failUnlessEqual(webresponse.code, server.HTTP_REDIRECT)
- self.failUnless(webresponse.headers.has_key('location'))
-
- location = webresponse.headers['location']
- query = cgi.parse_qs(urlparse(location)[4])
- self.failUnless('openid.sig' in query)
- self.failUnless('openid.assoc_handle' in query)
- self.failUnless('openid.signed' in query)
-
- def test_idresDumb(self):
- webresponse = self.encode(self.response)
- self.failUnlessEqual(webresponse.code, server.HTTP_REDIRECT)
- self.failUnless(webresponse.headers.has_key('location'))
-
- location = webresponse.headers['location']
- query = cgi.parse_qs(urlparse(location)[4])
- self.failUnless('openid.sig' in query)
- self.failUnless('openid.assoc_handle' in query)
- self.failUnless('openid.signed' in query)
-
- def test_forgotStore(self):
- self.encoder.signatory = None
- self.failUnlessRaises(ValueError, self.encode, self.response)
-
- def test_cancel(self):
- request = server.CheckIDRequest(
- identity = 'http://bombom.unittest/',
- trust_root = 'http://burr.unittest/',
- return_to = 'http://burr.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- request.message = Message(OPENID2_NS)
- response = server.OpenIDResponse(request)
- response.fields.setArg(OPENID_NS, 'mode', 'cancel')
- webresponse = self.encode(response)
- self.failUnlessEqual(webresponse.code, server.HTTP_REDIRECT)
- self.failUnless(webresponse.headers.has_key('location'))
- location = webresponse.headers['location']
- query = cgi.parse_qs(urlparse(location)[4])
- self.failIf('openid.sig' in query, response.fields.toPostArgs())
-
- def test_assocReply(self):
- msg = Message(OPENID2_NS)
- msg.setArg(OPENID2_NS, 'session_type', 'no-encryption')
- request = server.AssociateRequest.fromMessage(msg)
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({'assoc_handle': "every-zig"})
- webresponse = self.encode(response)
- body = """assoc_handle:every-zig
-"""
- self.failUnlessEqual(webresponse.code, server.HTTP_OK)
- self.failUnlessEqual(webresponse.headers, {})
- self.failUnlessEqual(webresponse.body, body)
-
- def test_alreadySigned(self):
- self.response.fields.setArg(OPENID_NS, 'sig', 'priorSig==')
- self.failUnlessRaises(server.AlreadySigned, self.encode, self.response)
-
-class TestCheckID(unittest.TestCase):
- def setUp(self):
- self.op_endpoint = 'http://endpoint.unittest/'
- self.store = memstore.MemoryStore()
- self.server = server.Server(self.store, self.op_endpoint)
- self.request = server.CheckIDRequest(
- identity = 'http://bambam.unittest/',
- trust_root = 'http://bar.unittest/',
- return_to = 'http://bar.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- self.request.message = Message(OPENID2_NS)
-
- def test_trustRootInvalid(self):
- self.request.trust_root = "http://foo.unittest/17"
- self.request.return_to = "http://foo.unittest/39"
- self.failIf(self.request.trustRootValid())
-
- def test_trustRootValid(self):
- self.request.trust_root = "http://foo.unittest/"
- self.request.return_to = "http://foo.unittest/39"
- self.failUnless(self.request.trustRootValid())
-
- def test_malformedTrustRoot(self):
- self.request.trust_root = "invalid://trust*root/"
- self.request.return_to = "http://foo.unittest/39"
- sentinel = object()
- self.request.message = sentinel
- try:
- result = self.request.trustRootValid()
- except server.MalformedTrustRoot, why:
- self.failUnless(sentinel is why.openid_message)
- else:
- self.fail('Expected MalformedTrustRoot exception. Got %r'
- % (result,))
-
- def test_trustRootValidNoReturnTo(self):
- request = server.CheckIDRequest(
- identity = 'http://bambam.unittest/',
- trust_root = 'http://bar.unittest/',
- return_to = None,
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
-
- self.failUnless(request.trustRootValid())
-
- def test_returnToVerified_callsVerify(self):
- """Make sure that verifyReturnTo is calling the trustroot
- function verifyReturnTo
- """
- def withVerifyReturnTo(new_verify, callable):
- old_verify = server.verifyReturnTo
- try:
- server.verifyReturnTo = new_verify
- return callable()
- finally:
- server.verifyReturnTo = old_verify
-
- # Ensure that exceptions are passed through
- sentinel = Exception()
- def vrfyExc(trust_root, return_to):
- self.failUnlessEqual(self.request.trust_root, trust_root)
- self.failUnlessEqual(self.request.return_to, return_to)
- raise sentinel
-
- try:
- withVerifyReturnTo(vrfyExc, self.request.returnToVerified)
- except Exception, e:
- self.failUnless(e is sentinel, e)
-
- # Ensure that True and False are passed through unchanged
- def constVerify(val):
- def verify(trust_root, return_to):
- self.failUnlessEqual(self.request.trust_root, trust_root)
- self.failUnlessEqual(self.request.return_to, return_to)
- return val
- return verify
-
- for val in [True, False]:
- self.failUnlessEqual(
- val,
- withVerifyReturnTo(constVerify(val),
- self.request.returnToVerified))
-
- def _expectAnswer(self, answer, identity=None, claimed_id=None):
- expected_list = [
- ('mode', 'id_res'),
- ('return_to', self.request.return_to),
- ('op_endpoint', self.op_endpoint),
- ]
- if identity:
- expected_list.append(('identity', identity))
- if claimed_id:
- expected_list.append(('claimed_id', claimed_id))
- else:
- expected_list.append(('claimed_id', identity))
-
- for k, expected in expected_list:
- actual = answer.fields.getArg(OPENID_NS, k)
- self.failUnlessEqual(actual, expected, "%s: expected %s, got %s" % (k, expected, actual))
-
- self.failUnless(answer.fields.hasKey(OPENID_NS, 'response_nonce'))
- self.failUnless(answer.fields.getOpenIDNamespace() == OPENID2_NS)
-
- # One for nonce, one for ns
- self.failUnlessEqual(len(answer.fields.toPostArgs()),
- len(expected_list) + 2,
- answer.fields.toPostArgs())
-
- def test_answerAllow(self):
- """Check the fields specified by "Positive Assertions"
-
- including mode=id_res, identity, claimed_id, op_endpoint, return_to
- """
- answer = self.request.answer(True)
- self.failUnlessEqual(answer.request, self.request)
- self._expectAnswer(answer, self.request.identity)
-
- def test_answerAllowDelegatedIdentity(self):
- self.request.claimed_id = 'http://delegating.unittest/'
- answer = self.request.answer(True)
- self._expectAnswer(answer, self.request.identity,
- self.request.claimed_id)
-
- def test_answerAllowDelegatedIdentity2(self):
- # This time with the identity argument explicitly passed in to
- # answer()
- self.request.claimed_id = 'http://delegating.unittest/'
- answer = self.request.answer(True, identity='http://bambam.unittest/')
- self._expectAnswer(answer, self.request.identity,
- self.request.claimed_id)
-
- def test_answerAllowWithoutIdentityReally(self):
- self.request.identity = None
- answer = self.request.answer(True)
- self.failUnlessEqual(answer.request, self.request)
- self._expectAnswer(answer)
-
- def test_answerAllowAnonymousFail(self):
- self.request.identity = None
- # XXX - Check on this, I think this behavior is legal in OpenID 2.0?
- self.failUnlessRaises(
- ValueError, self.request.answer, True, identity="=V")
-
- def test_answerAllowWithIdentity(self):
- self.request.identity = IDENTIFIER_SELECT
- selected_id = 'http://anon.unittest/9861'
- answer = self.request.answer(True, identity=selected_id)
- self._expectAnswer(answer, selected_id)
-
- def test_answerAllowWithDelegatedIdentityOpenID2(self):
- """Answer an IDENTIFIER_SELECT case with a delegated identifier.
- """
- # claimed_id delegates to selected_id here.
- self.request.identity = IDENTIFIER_SELECT
- selected_id = 'http://anon.unittest/9861'
- claimed_id = 'http://monkeyhat.unittest/'
- answer = self.request.answer(True, identity=selected_id,
- claimed_id=claimed_id)
- self._expectAnswer(answer, selected_id, claimed_id)
-
- def test_answerAllowWithDelegatedIdentityOpenID1(self):
- """claimed_id parameter doesn't exist in OpenID 1.
- """
- self.request.message = Message(OPENID1_NS)
- # claimed_id delegates to selected_id here.
- self.request.identity = IDENTIFIER_SELECT
- selected_id = 'http://anon.unittest/9861'
- claimed_id = 'http://monkeyhat.unittest/'
- self.failUnlessRaises(server.VersionError,
- self.request.answer, True,
- identity=selected_id,
- claimed_id=claimed_id)
-
- def test_answerAllowWithAnotherIdentity(self):
- # XXX - Check on this, I think this behavior is legal in OpenID 2.0?
- self.failUnlessRaises(ValueError, self.request.answer, True,
- identity="http://pebbles.unittest/")
-
- def test_answerAllowWithIdentityNormalization(self):
- # The RP has sent us a non-normalized value for openid.identity,
- # and the library user is passing an explicit value for identity
- # to CheckIDRequest.answer.
- non_normalized = 'http://bambam.unittest'
- normalized = non_normalized + '/'
-
- self.request.identity = non_normalized
- self.request.claimed_id = non_normalized
-
- answer = self.request.answer(True, identity=normalized)
-
- # Expect the values that were sent in the request, even though
- # they're not normalized.
- self._expectAnswer(answer, identity=non_normalized,
- claimed_id=non_normalized)
-
- def test_answerAllowNoIdentityOpenID1(self):
- self.request.message = Message(OPENID1_NS)
- self.request.identity = None
- self.failUnlessRaises(ValueError, self.request.answer, True,
- identity=None)
-
- def test_answerAllowForgotEndpoint(self):
- self.request.op_endpoint = None
- self.failUnlessRaises(RuntimeError, self.request.answer, True)
-
- def test_checkIDWithNoIdentityOpenID1(self):
- msg = Message(OPENID1_NS)
- msg.setArg(OPENID_NS, 'return_to', 'bogus')
- msg.setArg(OPENID_NS, 'trust_root', 'bogus')
- msg.setArg(OPENID_NS, 'mode', 'checkid_setup')
- msg.setArg(OPENID_NS, 'assoc_handle', 'bogus')
-
- self.failUnlessRaises(server.ProtocolError,
- server.CheckIDRequest.fromMessage,
- msg, self.server)
-
- def test_fromMessageClaimedIDWithoutIdentityOpenID2(self):
- name = 'https://example.myopenid.com'
-
- msg = Message(OPENID2_NS)
- msg.setArg(OPENID_NS, 'mode', 'checkid_setup')
- msg.setArg(OPENID_NS, 'return_to', 'http://invalid:8000/rt')
- msg.setArg(OPENID_NS, 'claimed_id', name)
-
- self.failUnlessRaises(server.ProtocolError,
- server.CheckIDRequest.fromMessage,
- msg, self.server)
-
- def test_fromMessageIdentityWithoutClaimedIDOpenID2(self):
- name = 'https://example.myopenid.com'
-
- msg = Message(OPENID2_NS)
- msg.setArg(OPENID_NS, 'mode', 'checkid_setup')
- msg.setArg(OPENID_NS, 'return_to', 'http://invalid:8000/rt')
- msg.setArg(OPENID_NS, 'identity', name)
-
- self.failUnlessRaises(server.ProtocolError,
- server.CheckIDRequest.fromMessage,
- msg, self.server)
-
- def test_trustRootOpenID1(self):
- """Ignore openid.realm in OpenID 1"""
- msg = Message(OPENID1_NS)
- msg.setArg(OPENID_NS, 'mode', 'checkid_setup')
- msg.setArg(OPENID_NS, 'trust_root', 'http://real_trust_root/')
- msg.setArg(OPENID_NS, 'realm', 'http://fake_trust_root/')
- msg.setArg(OPENID_NS, 'return_to', 'http://real_trust_root/foo')
- msg.setArg(OPENID_NS, 'assoc_handle', 'bogus')
- msg.setArg(OPENID_NS, 'identity', 'george')
-
- result = server.CheckIDRequest.fromMessage(msg, self.server.op_endpoint)
-
- self.failUnless(result.trust_root == 'http://real_trust_root/')
-
- def test_trustRootOpenID2(self):
- """Ignore openid.trust_root in OpenID 2"""
- msg = Message(OPENID2_NS)
- msg.setArg(OPENID_NS, 'mode', 'checkid_setup')
- msg.setArg(OPENID_NS, 'realm', 'http://real_trust_root/')
- msg.setArg(OPENID_NS, 'trust_root', 'http://fake_trust_root/')
- msg.setArg(OPENID_NS, 'return_to', 'http://real_trust_root/foo')
- msg.setArg(OPENID_NS, 'assoc_handle', 'bogus')
- msg.setArg(OPENID_NS, 'identity', 'george')
- msg.setArg(OPENID_NS, 'claimed_id', 'george')
-
- result = server.CheckIDRequest.fromMessage(msg, self.server.op_endpoint)
-
- self.failUnless(result.trust_root == 'http://real_trust_root/')
-
- def test_answerAllowNoTrustRoot(self):
- self.request.trust_root = None
- answer = self.request.answer(True)
- self.failUnlessEqual(answer.request, self.request)
- self._expectAnswer(answer, self.request.identity)
-
- def test_fromMessageWithoutTrustRoot(self):
- msg = Message(OPENID2_NS)
- msg.setArg(OPENID_NS, 'mode', 'checkid_setup')
- msg.setArg(OPENID_NS, 'return_to', 'http://real_trust_root/foo')
- msg.setArg(OPENID_NS, 'assoc_handle', 'bogus')
- msg.setArg(OPENID_NS, 'identity', 'george')
- msg.setArg(OPENID_NS, 'claimed_id', 'george')
-
- result = server.CheckIDRequest.fromMessage(msg, self.server.op_endpoint)
-
- self.failUnlessEqual(result.trust_root, 'http://real_trust_root/foo')
-
- def test_fromMessageWithEmptyTrustRoot(self):
- return_to = u'http://someplace.invalid/?go=thing'
- msg = Message.fromPostArgs({
- u'openid.assoc_handle': u'{blah}{blah}{OZivdQ==}',
- u'openid.claimed_id': u'http://delegated.invalid/',
- u'openid.identity': u'http://op-local.example.com/',
- u'openid.mode': u'checkid_setup',
- u'openid.ns': u'http://openid.net/signon/1.0',
- u'openid.return_to': return_to,
- u'openid.trust_root': u''})
-
- result = server.CheckIDRequest.fromMessage(msg, self.server.op_endpoint)
-
- self.failUnlessEqual(result.trust_root, return_to)
-
- def test_fromMessageWithoutTrustRootOrReturnTo(self):
- msg = Message(OPENID2_NS)
- msg.setArg(OPENID_NS, 'mode', 'checkid_setup')
- msg.setArg(OPENID_NS, 'assoc_handle', 'bogus')
- msg.setArg(OPENID_NS, 'identity', 'george')
- msg.setArg(OPENID_NS, 'claimed_id', 'george')
-
- self.failUnlessRaises(server.ProtocolError,
- server.CheckIDRequest.fromMessage,
- msg, self.server.op_endpoint)
-
- def test_answerAllowNoEndpointOpenID1(self):
- """Test .allow() with an OpenID 1.x Message on a CheckIDRequest
- built without an op_endpoint parameter.
- """
- identity = 'http://bambam.unittest/'
- reqmessage = Message.fromOpenIDArgs({
- 'identity': identity,
- 'trust_root': 'http://bar.unittest/',
- 'return_to': 'http://bar.unittest/999',
- })
- self.request = server.CheckIDRequest.fromMessage(reqmessage, None)
- answer = self.request.answer(True)
-
- expected_list = [
- ('mode', 'id_res'),
- ('return_to', self.request.return_to),
- ('identity', identity),
- ]
-
- for k, expected in expected_list:
- actual = answer.fields.getArg(OPENID_NS, k)
- self.failUnlessEqual(
- expected, actual,
- "%s: expected %s, got %s" % (k, expected, actual))
-
- self.failUnless(answer.fields.hasKey(OPENID_NS, 'response_nonce'))
- self.failUnlessEqual(answer.fields.getOpenIDNamespace(), OPENID1_NS)
- self.failUnless(answer.fields.namespaces.isImplicit(OPENID1_NS))
-
- # One for nonce (OpenID v1 namespace is implicit)
- self.failUnlessEqual(len(answer.fields.toPostArgs()),
- len(expected_list) + 1,
- answer.fields.toPostArgs())
-
- def test_answerImmediateDenyOpenID2(self):
- """Look for mode=setup_needed in checkid_immediate negative
- response in OpenID 2 case.
-
- See specification Responding to Authentication Requests /
- Negative Assertions / In Response to Immediate Requests.
- """
- self.request.mode = 'checkid_immediate'
- self.request.immediate = True
- self.request.claimed_id = 'http://claimed-id.test/'
- server_url = "http://setup-url.unittest/"
- # crappiting setup_url, you dirty my interface with your presence!
- answer = self.request.answer(False, server_url=server_url)
- self.failUnlessEqual(answer.request, self.request)
- self.failUnlessEqual(len(answer.fields.toPostArgs()), 3, answer.fields)
- self.failUnlessEqual(answer.fields.getOpenIDNamespace(), OPENID2_NS)
- self.failUnlessEqual(answer.fields.getArg(OPENID_NS, 'mode'),
- 'setup_needed')
-
- usu = answer.fields.getArg(OPENID_NS, 'user_setup_url')
- expected_substr = 'openid.claimed_id=http%3A%2F%2Fclaimed-id.test%2F'
- self.failUnless(expected_substr in usu, usu)
-
- def test_answerImmediateDenyOpenID1(self):
- """Look for user_setup_url in checkid_immediate negative
- response in OpenID 1 case."""
- self.request.message = Message(OPENID1_NS)
- self.request.mode = 'checkid_immediate'
- self.request.immediate = True
- server_url = "http://setup-url.unittest/"
- # crappiting setup_url, you dirty my interface with your presence!
- answer = self.request.answer(False, server_url=server_url)
- self.failUnlessEqual(answer.request, self.request)
- self.failUnlessEqual(len(answer.fields.toPostArgs()), 2, answer.fields)
- self.failUnlessEqual(answer.fields.getOpenIDNamespace(), OPENID1_NS)
- self.failUnless(answer.fields.namespaces.isImplicit(OPENID1_NS))
- self.failUnlessEqual(answer.fields.getArg(OPENID_NS, 'mode'), 'id_res')
- self.failUnless(answer.fields.getArg(
- OPENID_NS, 'user_setup_url', '').startswith(server_url))
-
- def test_answerSetupDeny(self):
- answer = self.request.answer(False)
- self.failUnlessEqual(answer.fields.getArgs(OPENID_NS), {
- 'mode': 'cancel',
- })
-
- def test_encodeToURL(self):
- server_url = 'http://openid-server.unittest/'
- result = self.request.encodeToURL(server_url)
-
- # How to check? How about a round-trip test.
- base, result_args = result.split('?', 1)
- result_args = dict(cgi.parse_qsl(result_args))
- message = Message.fromPostArgs(result_args)
- rebuilt_request = server.CheckIDRequest.fromMessage(message,
- self.server.op_endpoint)
- # argh, lousy hack
- self.request.message = message
- self.failUnlessEqual(rebuilt_request.__dict__, self.request.__dict__)
-
- def test_getCancelURL(self):
- url = self.request.getCancelURL()
- rt, query_string = url.split('?')
- self.failUnlessEqual(self.request.return_to, rt)
- query = dict(cgi.parse_qsl(query_string))
- self.failUnlessEqual(query, {'openid.mode':'cancel',
- 'openid.ns':OPENID2_NS})
-
- def test_getCancelURLimmed(self):
- self.request.mode = 'checkid_immediate'
- self.request.immediate = True
- self.failUnlessRaises(ValueError, self.request.getCancelURL)
-
-
-
-class TestCheckIDExtension(unittest.TestCase):
-
- def setUp(self):
- self.op_endpoint = 'http://endpoint.unittest/ext'
- self.store = memstore.MemoryStore()
- self.server = server.Server(self.store, self.op_endpoint)
- self.request = server.CheckIDRequest(
- identity = 'http://bambam.unittest/',
- trust_root = 'http://bar.unittest/',
- return_to = 'http://bar.unittest/999',
- immediate = False,
- op_endpoint = self.server.op_endpoint,
- )
- self.request.message = Message(OPENID2_NS)
- self.response = server.OpenIDResponse(self.request)
- self.response.fields.setArg(OPENID_NS, 'mode', 'id_res')
- self.response.fields.setArg(OPENID_NS, 'blue', 'star')
-
-
- def test_addField(self):
- namespace = 'something:'
- self.response.fields.setArg(namespace, 'bright', 'potato')
- self.failUnlessEqual(self.response.fields.getArgs(OPENID_NS),
- {'blue': 'star',
- 'mode': 'id_res',
- })
-
- self.failUnlessEqual(self.response.fields.getArgs(namespace),
- {'bright':'potato'})
-
-
- def test_addFields(self):
- namespace = 'mi5:'
- args = {'tangy': 'suspenders',
- 'bravo': 'inclusion'}
- self.response.fields.updateArgs(namespace, args)
- self.failUnlessEqual(self.response.fields.getArgs(OPENID_NS),
- {'blue': 'star',
- 'mode': 'id_res',
- })
- self.failUnlessEqual(self.response.fields.getArgs(namespace), args)
-
-
-
-class MockSignatory(object):
- isValid = True
-
- def __init__(self, assoc):
- self.assocs = [assoc]
-
- def verify(self, assoc_handle, message):
- assert message.hasKey(OPENID_NS, "sig")
- if (True, assoc_handle) in self.assocs:
- return self.isValid
- else:
- return False
-
- def getAssociation(self, assoc_handle, dumb):
- if (dumb, assoc_handle) in self.assocs:
- # This isn't a valid implementation for many uses of this
- # function, mind you.
- return True
- else:
- return None
-
- def invalidate(self, assoc_handle, dumb):
- if (dumb, assoc_handle) in self.assocs:
- self.assocs.remove((dumb, assoc_handle))
-
-
-class TestCheckAuth(unittest.TestCase):
- def setUp(self):
- self.assoc_handle = 'mooooooooo'
- self.message = Message.fromPostArgs({
- 'openid.sig': 'signarture',
- 'one': 'alpha',
- 'two': 'beta',
- })
- self.request = server.CheckAuthRequest(
- self.assoc_handle, self.message)
-
- self.signatory = MockSignatory((True, self.assoc_handle))
-
- def test_valid(self):
- r = self.request.answer(self.signatory)
- self.failUnlessEqual(r.fields.getArgs(OPENID_NS), {'is_valid': 'true'})
- self.failUnlessEqual(r.request, self.request)
-
- def test_invalid(self):
- self.signatory.isValid = False
- r = self.request.answer(self.signatory)
- self.failUnlessEqual(r.fields.getArgs(OPENID_NS),
- {'is_valid': 'false'})
-
- def test_replay(self):
- """Don't validate the same response twice.
-
- From "Checking the Nonce"::
-
- When using "check_authentication", the OP MUST ensure that an
- assertion has not yet been accepted with the same value for
- "openid.response_nonce".
-
- In this implementation, the assoc_handle is only valid once. And
- nonces are a signed component of the message, so they can't be used
- with another handle without breaking the sig.
- """
- r = self.request.answer(self.signatory)
- r = self.request.answer(self.signatory)
- self.failUnlessEqual(r.fields.getArgs(OPENID_NS),
- {'is_valid': 'false'})
-
- def test_invalidatehandle(self):
- self.request.invalidate_handle = "bogusHandle"
- r = self.request.answer(self.signatory)
- self.failUnlessEqual(r.fields.getArgs(OPENID_NS),
- {'is_valid': 'true',
- 'invalidate_handle': "bogusHandle"})
- self.failUnlessEqual(r.request, self.request)
-
- def test_invalidatehandleNo(self):
- assoc_handle = 'goodhandle'
- self.signatory.assocs.append((False, 'goodhandle'))
- self.request.invalidate_handle = assoc_handle
- r = self.request.answer(self.signatory)
- self.failUnlessEqual(r.fields.getArgs(OPENID_NS), {'is_valid': 'true'})
-
-
-class TestAssociate(unittest.TestCase):
- # TODO: test DH with non-default values for modulus and gen.
- # (important to do because we actually had it broken for a while.)
-
- def setUp(self):
- self.request = server.AssociateRequest.fromMessage(
- Message.fromPostArgs({}))
- self.store = memstore.MemoryStore()
- self.signatory = server.Signatory(self.store)
-
- def test_dhSHA1(self):
- self.assoc = self.signatory.createAssociation(dumb=False, assoc_type='HMAC-SHA1')
- from askbot.deps.openid.dh import DiffieHellman
- from askbot.deps.openid.server.server import DiffieHellmanSHA1ServerSession
- consumer_dh = DiffieHellman.fromDefaults()
- cpub = consumer_dh.public
- server_dh = DiffieHellman.fromDefaults()
- session = DiffieHellmanSHA1ServerSession(server_dh, cpub)
- self.request = server.AssociateRequest(session, 'HMAC-SHA1')
- response = self.request.answer(self.assoc)
- rfg = lambda f: response.fields.getArg(OPENID_NS, f)
- self.failUnlessEqual(rfg("assoc_type"), "HMAC-SHA1")
- self.failUnlessEqual(rfg("assoc_handle"), self.assoc.handle)
- self.failIf(rfg("mac_key"))
- self.failUnlessEqual(rfg("session_type"), "DH-SHA1")
- self.failUnless(rfg("enc_mac_key"))
- self.failUnless(rfg("dh_server_public"))
-
- enc_key = rfg("enc_mac_key").decode('base64')
- spub = cryptutil.base64ToLong(rfg("dh_server_public"))
- secret = consumer_dh.xorSecret(spub, enc_key, cryptutil.sha1)
- self.failUnlessEqual(secret, self.assoc.secret)
-
-
- if not cryptutil.SHA256_AVAILABLE:
- warnings.warn("Not running SHA256 tests.")
- else:
- def test_dhSHA256(self):
- self.assoc = self.signatory.createAssociation(
- dumb=False, assoc_type='HMAC-SHA256')
- from askbot.deps.openid.dh import DiffieHellman
- from askbot.deps.openid.server.server import DiffieHellmanSHA256ServerSession
- consumer_dh = DiffieHellman.fromDefaults()
- cpub = consumer_dh.public
- server_dh = DiffieHellman.fromDefaults()
- session = DiffieHellmanSHA256ServerSession(server_dh, cpub)
- self.request = server.AssociateRequest(session, 'HMAC-SHA256')
- response = self.request.answer(self.assoc)
- rfg = lambda f: response.fields.getArg(OPENID_NS, f)
- self.failUnlessEqual(rfg("assoc_type"), "HMAC-SHA256")
- self.failUnlessEqual(rfg("assoc_handle"), self.assoc.handle)
- self.failIf(rfg("mac_key"))
- self.failUnlessEqual(rfg("session_type"), "DH-SHA256")
- self.failUnless(rfg("enc_mac_key"))
- self.failUnless(rfg("dh_server_public"))
-
- enc_key = rfg("enc_mac_key").decode('base64')
- spub = cryptutil.base64ToLong(rfg("dh_server_public"))
- secret = consumer_dh.xorSecret(spub, enc_key, cryptutil.sha256)
- self.failUnlessEqual(secret, self.assoc.secret)
-
- def test_protoError256(self):
- from askbot.deps.openid.consumer.consumer import \
- DiffieHellmanSHA256ConsumerSession
-
- s256_session = DiffieHellmanSHA256ConsumerSession()
-
- invalid_s256 = {'openid.assoc_type':'HMAC-SHA1',
- 'openid.session_type':'DH-SHA256',}
- invalid_s256.update(s256_session.getRequest())
-
- invalid_s256_2 = {'openid.assoc_type':'MONKEY-PIRATE',
- 'openid.session_type':'DH-SHA256',}
- invalid_s256_2.update(s256_session.getRequest())
-
- bad_request_argss = [
- invalid_s256,
- invalid_s256_2,
- ]
-
- for request_args in bad_request_argss:
- message = Message.fromPostArgs(request_args)
- self.failUnlessRaises(server.ProtocolError,
- server.AssociateRequest.fromMessage,
- message)
-
- def test_protoError(self):
- from askbot.deps.openid.consumer.consumer import DiffieHellmanSHA1ConsumerSession
-
- s1_session = DiffieHellmanSHA1ConsumerSession()
-
- invalid_s1 = {'openid.assoc_type':'HMAC-SHA256',
- 'openid.session_type':'DH-SHA1',}
- invalid_s1.update(s1_session.getRequest())
-
- invalid_s1_2 = {'openid.assoc_type':'ROBOT-NINJA',
- 'openid.session_type':'DH-SHA1',}
- invalid_s1_2.update(s1_session.getRequest())
-
- bad_request_argss = [
- {'openid.assoc_type':'Wha?'},
- invalid_s1,
- invalid_s1_2,
- ]
-
- for request_args in bad_request_argss:
- message = Message.fromPostArgs(request_args)
- self.failUnlessRaises(server.ProtocolError,
- server.AssociateRequest.fromMessage,
- message)
-
- def test_protoErrorFields(self):
-
- contact = 'user@example.invalid'
- reference = 'Trac ticket number MAX_INT'
- error = 'poltergeist'
-
- openid1_args = {
- 'openid.identitiy': 'invalid',
- 'openid.mode': 'checkid_setup',
- }
-
- openid2_args = dict(openid1_args)
- openid2_args.update({'openid.ns': OPENID2_NS})
-
- # Check presence of optional fields in both protocol versions
-
- openid1_msg = Message.fromPostArgs(openid1_args)
- p = server.ProtocolError(openid1_msg, error,
- contact=contact, reference=reference)
- reply = p.toMessage()
-
- self.failUnlessEqual(reply.getArg(OPENID_NS, 'reference'), reference)
- self.failUnlessEqual(reply.getArg(OPENID_NS, 'contact'), contact)
-
- openid2_msg = Message.fromPostArgs(openid2_args)
- p = server.ProtocolError(openid2_msg, error,
- contact=contact, reference=reference)
- reply = p.toMessage()
-
- self.failUnlessEqual(reply.getArg(OPENID_NS, 'reference'), reference)
- self.failUnlessEqual(reply.getArg(OPENID_NS, 'contact'), contact)
-
- def failUnlessExpiresInMatches(self, msg, expected_expires_in):
- expires_in_str = msg.getArg(OPENID_NS, 'expires_in', no_default)
- expires_in = int(expires_in_str)
-
- # Slop is necessary because the tests can sometimes get run
- # right on a second boundary
- slop = 1 # second
- difference = expected_expires_in - expires_in
-
- error_message = ('"expires_in" value not within %s of expected: '
- 'expected=%s, actual=%s' %
- (slop, expected_expires_in, expires_in))
- self.failUnless(0 <= difference <= slop, error_message)
-
- def test_plaintext(self):
- self.assoc = self.signatory.createAssociation(dumb=False, assoc_type='HMAC-SHA1')
- response = self.request.answer(self.assoc)
- rfg = lambda f: response.fields.getArg(OPENID_NS, f)
-
- self.failUnlessEqual(rfg("assoc_type"), "HMAC-SHA1")
- self.failUnlessEqual(rfg("assoc_handle"), self.assoc.handle)
-
- self.failUnlessExpiresInMatches(
- response.fields, self.signatory.SECRET_LIFETIME)
-
- self.failUnlessEqual(
- rfg("mac_key"), oidutil.toBase64(self.assoc.secret))
- self.failIf(rfg("session_type"))
- self.failIf(rfg("enc_mac_key"))
- self.failIf(rfg("dh_server_public"))
-
- def test_plaintext_v2(self):
- # The main difference between this and the v1 test is that
- # session_type is always returned in v2.
- args = {
- 'openid.ns': OPENID2_NS,
- 'openid.mode': 'associate',
- 'openid.assoc_type': 'HMAC-SHA1',
- 'openid.session_type': 'no-encryption',
- }
- self.request = server.AssociateRequest.fromMessage(
- Message.fromPostArgs(args))
-
- self.failIf(self.request.message.isOpenID1())
-
- self.assoc = self.signatory.createAssociation(
- dumb=False, assoc_type='HMAC-SHA1')
- response = self.request.answer(self.assoc)
- rfg = lambda f: response.fields.getArg(OPENID_NS, f)
-
- self.failUnlessEqual(rfg("assoc_type"), "HMAC-SHA1")
- self.failUnlessEqual(rfg("assoc_handle"), self.assoc.handle)
-
- self.failUnlessExpiresInMatches(
- response.fields, self.signatory.SECRET_LIFETIME)
-
- self.failUnlessEqual(
- rfg("mac_key"), oidutil.toBase64(self.assoc.secret))
-
- self.failUnlessEqual(rfg("session_type"), "no-encryption")
- self.failIf(rfg("enc_mac_key"))
- self.failIf(rfg("dh_server_public"))
-
- def test_plaintext256(self):
- self.assoc = self.signatory.createAssociation(dumb=False, assoc_type='HMAC-SHA256')
- response = self.request.answer(self.assoc)
- rfg = lambda f: response.fields.getArg(OPENID_NS, f)
-
- self.failUnlessEqual(rfg("assoc_type"), "HMAC-SHA1")
- self.failUnlessEqual(rfg("assoc_handle"), self.assoc.handle)
-
- self.failUnlessExpiresInMatches(
- response.fields, self.signatory.SECRET_LIFETIME)
-
- self.failUnlessEqual(
- rfg("mac_key"), oidutil.toBase64(self.assoc.secret))
- self.failIf(rfg("session_type"))
- self.failIf(rfg("enc_mac_key"))
- self.failIf(rfg("dh_server_public"))
-
- def test_unsupportedPrefer(self):
- allowed_assoc = 'COLD-PET-RAT'
- allowed_sess = 'FROG-BONES'
- message = 'This is a unit test'
-
- # Set an OpenID 2 message so answerUnsupported doesn't raise
- # ProtocolError.
- self.request.message = Message(OPENID2_NS)
-
- response = self.request.answerUnsupported(
- message=message,
- preferred_session_type=allowed_sess,
- preferred_association_type=allowed_assoc,
- )
- rfg = lambda f: response.fields.getArg(OPENID_NS, f)
- self.failUnlessEqual(rfg('error_code'), 'unsupported-type')
- self.failUnlessEqual(rfg('assoc_type'), allowed_assoc)
- self.failUnlessEqual(rfg('error'), message)
- self.failUnlessEqual(rfg('session_type'), allowed_sess)
-
- def test_unsupported(self):
- message = 'This is a unit test'
-
- # Set an OpenID 2 message so answerUnsupported doesn't raise
- # ProtocolError.
- self.request.message = Message(OPENID2_NS)
-
- response = self.request.answerUnsupported(message)
- rfg = lambda f: response.fields.getArg(OPENID_NS, f)
- self.failUnlessEqual(rfg('error_code'), 'unsupported-type')
- self.failUnlessEqual(rfg('assoc_type'), None)
- self.failUnlessEqual(rfg('error'), message)
- self.failUnlessEqual(rfg('session_type'), None)
-
-class Counter(object):
- def __init__(self):
- self.count = 0
-
- def inc(self):
- self.count += 1
-
-class TestServer(unittest.TestCase, CatchLogs):
- def setUp(self):
- self.store = memstore.MemoryStore()
- self.server = server.Server(self.store, "http://server.unittest/endpt")
- CatchLogs.setUp(self)
-
- def test_dispatch(self):
- monkeycalled = Counter()
- def monkeyDo(request):
- monkeycalled.inc()
- r = server.OpenIDResponse(request)
- return r
- self.server.openid_monkeymode = monkeyDo
- request = server.OpenIDRequest()
- request.mode = "monkeymode"
- request.namespace = OPENID1_NS
- webresult = self.server.handleRequest(request)
- self.failUnlessEqual(monkeycalled.count, 1)
-
- def test_associate(self):
- request = server.AssociateRequest.fromMessage(Message.fromPostArgs({}))
- response = self.server.openid_associate(request)
- self.failUnless(response.fields.hasKey(OPENID_NS, "assoc_handle"),
- "No assoc_handle here: %s" % (response.fields,))
-
- def test_associate2(self):
- """Associate when the server has no allowed association types
-
- Gives back an error with error_code and no fallback session or
- assoc types."""
- self.server.negotiator.setAllowedTypes([])
-
- # Set an OpenID 2 message so answerUnsupported doesn't raise
- # ProtocolError.
- msg = Message.fromPostArgs({
- 'openid.ns': OPENID2_NS,
- 'openid.session_type': 'no-encryption',
- })
-
- request = server.AssociateRequest.fromMessage(msg)
-
- response = self.server.openid_associate(request)
- self.failUnless(response.fields.hasKey(OPENID_NS, "error"))
- self.failUnless(response.fields.hasKey(OPENID_NS, "error_code"))
- self.failIf(response.fields.hasKey(OPENID_NS, "assoc_handle"))
- self.failIf(response.fields.hasKey(OPENID_NS, "assoc_type"))
- self.failIf(response.fields.hasKey(OPENID_NS, "session_type"))
-
- def test_associate3(self):
- """Request an assoc type that is not supported when there are
- supported types.
-
- Should give back an error message with a fallback type.
- """
- self.server.negotiator.setAllowedTypes([('HMAC-SHA256', 'DH-SHA256')])
-
- msg = Message.fromPostArgs({
- 'openid.ns': OPENID2_NS,
- 'openid.session_type': 'no-encryption',
- })
-
- request = server.AssociateRequest.fromMessage(msg)
- response = self.server.openid_associate(request)
-
- self.failUnless(response.fields.hasKey(OPENID_NS, "error"))
- self.failUnless(response.fields.hasKey(OPENID_NS, "error_code"))
- self.failIf(response.fields.hasKey(OPENID_NS, "assoc_handle"))
- self.failUnlessEqual(response.fields.getArg(OPENID_NS, "assoc_type"),
- 'HMAC-SHA256')
- self.failUnlessEqual(response.fields.getArg(OPENID_NS, "session_type"),
- 'DH-SHA256')
-
- if not cryptutil.SHA256_AVAILABLE:
- warnings.warn("Not running SHA256 tests.")
- else:
- def test_associate4(self):
- """DH-SHA256 association session"""
- self.server.negotiator.setAllowedTypes(
- [('HMAC-SHA256', 'DH-SHA256')])
- query = {
- 'openid.dh_consumer_public':
- 'ALZgnx8N5Lgd7pCj8K86T/DDMFjJXSss1SKoLmxE72kJTzOtG6I2PaYrHX'
- 'xku4jMQWSsGfLJxwCZ6280uYjUST/9NWmuAfcrBfmDHIBc3H8xh6RBnlXJ'
- '1WxJY3jHd5k1/ZReyRZOxZTKdF/dnIqwF8ZXUwI6peV0TyS/K1fOfF/s',
- 'openid.assoc_type': 'HMAC-SHA256',
- 'openid.session_type': 'DH-SHA256',
- }
- message = Message.fromPostArgs(query)
- request = server.AssociateRequest.fromMessage(message)
- response = self.server.openid_associate(request)
- self.failUnless(response.fields.hasKey(OPENID_NS, "assoc_handle"))
-
- def test_missingSessionTypeOpenID2(self):
- """Make sure session_type is required in OpenID 2"""
- msg = Message.fromPostArgs({
- 'openid.ns': OPENID2_NS,
- })
-
- self.assertRaises(server.ProtocolError,
- server.AssociateRequest.fromMessage, msg)
-
- def test_checkAuth(self):
- request = server.CheckAuthRequest('arrrrrf', '0x3999', [])
- response = self.server.openid_check_authentication(request)
- self.failUnless(response.fields.hasKey(OPENID_NS, "is_valid"))
-
-class TestSignatory(unittest.TestCase, CatchLogs):
- def setUp(self):
- self.store = memstore.MemoryStore()
- self.signatory = server.Signatory(self.store)
- self._dumb_key = self.signatory._dumb_key
- self._normal_key = self.signatory._normal_key
- CatchLogs.setUp(self)
-
- def test_sign(self):
- request = server.OpenIDRequest()
- assoc_handle = '{assoc}{lookatme}'
- self.store.storeAssociation(
- self._normal_key,
- association.Association.fromExpiresIn(60, assoc_handle,
- 'sekrit', 'HMAC-SHA1'))
- request.assoc_handle = assoc_handle
- request.namespace = OPENID1_NS
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'foo': 'amsigned',
- 'bar': 'notsigned',
- 'azu': 'alsosigned',
- })
- sresponse = self.signatory.sign(response)
- self.failUnlessEqual(
- sresponse.fields.getArg(OPENID_NS, 'assoc_handle'),
- assoc_handle)
- self.failUnlessEqual(sresponse.fields.getArg(OPENID_NS, 'signed'),
- 'assoc_handle,azu,bar,foo,signed')
- self.failUnless(sresponse.fields.getArg(OPENID_NS, 'sig'))
- self.failIf(self.messages, self.messages)
-
- def test_signDumb(self):
- request = server.OpenIDRequest()
- request.assoc_handle = None
- request.namespace = OPENID2_NS
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'foo': 'amsigned',
- 'bar': 'notsigned',
- 'azu': 'alsosigned',
- 'ns':OPENID2_NS,
- })
- sresponse = self.signatory.sign(response)
- assoc_handle = sresponse.fields.getArg(OPENID_NS, 'assoc_handle')
- self.failUnless(assoc_handle)
- assoc = self.signatory.getAssociation(assoc_handle, dumb=True)
- self.failUnless(assoc)
- self.failUnlessEqual(sresponse.fields.getArg(OPENID_NS, 'signed'),
- 'assoc_handle,azu,bar,foo,ns,signed')
- self.failUnless(sresponse.fields.getArg(OPENID_NS, 'sig'))
- self.failIf(self.messages, self.messages)
-
- def test_signExpired(self):
- """Sign a response to a message with an expired handle (using invalidate_handle).
-
- From "Verifying with an Association"::
-
- If an authentication request included an association handle for an
- association between the OP and the Relying party, and the OP no
- longer wishes to use that handle (because it has expired or the
- secret has been compromised, for instance), the OP will send a
- response that must be verified directly with the OP, as specified
- in Section 11.3.2. In that instance, the OP will include the field
- "openid.invalidate_handle" set to the association handle that the
- Relying Party included with the original request.
- """
- request = server.OpenIDRequest()
- request.namespace = OPENID2_NS
- assoc_handle = '{assoc}{lookatme}'
- self.store.storeAssociation(
- self._normal_key,
- association.Association.fromExpiresIn(-10, assoc_handle,
- 'sekrit', 'HMAC-SHA1'))
- self.failUnless(self.store.getAssociation(self._normal_key, assoc_handle))
-
- request.assoc_handle = assoc_handle
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'foo': 'amsigned',
- 'bar': 'notsigned',
- 'azu': 'alsosigned',
- })
- sresponse = self.signatory.sign(response)
-
- new_assoc_handle = sresponse.fields.getArg(OPENID_NS, 'assoc_handle')
- self.failUnless(new_assoc_handle)
- self.failIfEqual(new_assoc_handle, assoc_handle)
-
- self.failUnlessEqual(
- sresponse.fields.getArg(OPENID_NS, 'invalidate_handle'),
- assoc_handle)
-
- self.failUnlessEqual(sresponse.fields.getArg(OPENID_NS, 'signed'),
- 'assoc_handle,azu,bar,foo,invalidate_handle,signed')
- self.failUnless(sresponse.fields.getArg(OPENID_NS, 'sig'))
-
- # make sure the expired association is gone
- self.failIf(self.store.getAssociation(self._normal_key, assoc_handle),
- "expired association is still retrievable.")
-
- # make sure the new key is a dumb mode association
- self.failUnless(self.store.getAssociation(self._dumb_key, new_assoc_handle))
- self.failIf(self.store.getAssociation(self._normal_key, new_assoc_handle))
- self.failUnless(self.messages)
-
-
- def test_signInvalidHandle(self):
- request = server.OpenIDRequest()
- request.namespace = OPENID2_NS
- assoc_handle = '{bogus-assoc}{notvalid}'
-
- request.assoc_handle = assoc_handle
- response = server.OpenIDResponse(request)
- response.fields = Message.fromOpenIDArgs({
- 'foo': 'amsigned',
- 'bar': 'notsigned',
- 'azu': 'alsosigned',
- })
- sresponse = self.signatory.sign(response)
-
- new_assoc_handle = sresponse.fields.getArg(OPENID_NS, 'assoc_handle')
- self.failUnless(new_assoc_handle)
- self.failIfEqual(new_assoc_handle, assoc_handle)
-
- self.failUnlessEqual(
- sresponse.fields.getArg(OPENID_NS, 'invalidate_handle'),
- assoc_handle)
-
- self.failUnlessEqual(
- sresponse.fields.getArg(OPENID_NS, 'signed'), 'assoc_handle,azu,bar,foo,invalidate_handle,signed')
- self.failUnless(sresponse.fields.getArg(OPENID_NS, 'sig'))
-
- # make sure the new key is a dumb mode association
- self.failUnless(self.store.getAssociation(self._dumb_key, new_assoc_handle))
- self.failIf(self.store.getAssociation(self._normal_key, new_assoc_handle))
- self.failIf(self.messages, self.messages)
-
-
- def test_verify(self):
- assoc_handle = '{vroom}{zoom}'
- assoc = association.Association.fromExpiresIn(
- 60, assoc_handle, 'sekrit', 'HMAC-SHA1')
-
- self.store.storeAssociation(self._dumb_key, assoc)
-
- signed = Message.fromPostArgs({
- 'openid.foo': 'bar',
- 'openid.apple': 'orange',
- 'openid.assoc_handle': assoc_handle,
- 'openid.signed': 'apple,assoc_handle,foo,signed',
- 'openid.sig': 'uXoT1qm62/BB09Xbj98TQ8mlBco=',
- })
-
- verified = self.signatory.verify(assoc_handle, signed)
- self.failIf(self.messages, self.messages)
- self.failUnless(verified)
-
-
- def test_verifyBadSig(self):
- assoc_handle = '{vroom}{zoom}'
- assoc = association.Association.fromExpiresIn(
- 60, assoc_handle, 'sekrit', 'HMAC-SHA1')
-
- self.store.storeAssociation(self._dumb_key, assoc)
-
- signed = Message.fromPostArgs({
- 'openid.foo': 'bar',
- 'openid.apple': 'orange',
- 'openid.assoc_handle': assoc_handle,
- 'openid.signed': 'apple,assoc_handle,foo,signed',
- 'openid.sig': 'uXoT1qm62/BB09Xbj98TQ8mlBco='.encode('rot13'),
- })
-
- verified = self.signatory.verify(assoc_handle, signed)
- self.failIf(self.messages, self.messages)
- self.failIf(verified)
-
- def test_verifyBadHandle(self):
- assoc_handle = '{vroom}{zoom}'
- signed = Message.fromPostArgs({
- 'foo': 'bar',
- 'apple': 'orange',
- 'openid.sig': "Ylu0KcIR7PvNegB/K41KpnRgJl0=",
- })
-
- verified = self.signatory.verify(assoc_handle, signed)
- self.failIf(verified)
- self.failUnless(self.messages)
-
-
- def test_verifyAssocMismatch(self):
- """Attempt to validate sign-all message with a signed-list assoc."""
- assoc_handle = '{vroom}{zoom}'
- assoc = association.Association.fromExpiresIn(
- 60, assoc_handle, 'sekrit', 'HMAC-SHA1')
-
- self.store.storeAssociation(self._dumb_key, assoc)
-
- signed = Message.fromPostArgs({
- 'foo': 'bar',
- 'apple': 'orange',
- 'openid.sig': "d71xlHtqnq98DonoSgoK/nD+QRM=",
- })
-
- verified = self.signatory.verify(assoc_handle, signed)
- self.failIf(verified)
- self.failUnless(self.messages)
-
- def test_getAssoc(self):
- assoc_handle = self.makeAssoc(dumb=True)
- assoc = self.signatory.getAssociation(assoc_handle, True)
- self.failUnless(assoc)
- self.failUnlessEqual(assoc.handle, assoc_handle)
- self.failIf(self.messages, self.messages)
-
- def test_getAssocExpired(self):
- assoc_handle = self.makeAssoc(dumb=True, lifetime=-10)
- assoc = self.signatory.getAssociation(assoc_handle, True)
- self.failIf(assoc, assoc)
- self.failUnless(self.messages)
-
- def test_getAssocInvalid(self):
- ah = 'no-such-handle'
- self.failUnlessEqual(
- self.signatory.getAssociation(ah, dumb=False), None)
- self.failIf(self.messages, self.messages)
-
- def test_getAssocDumbVsNormal(self):
- """getAssociation(dumb=False) cannot get a dumb assoc"""
- assoc_handle = self.makeAssoc(dumb=True)
- self.failUnlessEqual(
- self.signatory.getAssociation(assoc_handle, dumb=False), None)
- self.failIf(self.messages, self.messages)
-
- def test_getAssocNormalVsDumb(self):
- """getAssociation(dumb=True) cannot get a shared assoc
-
- From "Verifying Directly with the OpenID Provider"::
-
- An OP MUST NOT verify signatures for associations that have shared
- MAC keys.
- """
- assoc_handle = self.makeAssoc(dumb=False)
- self.failUnlessEqual(
- self.signatory.getAssociation(assoc_handle, dumb=True), None)
- self.failIf(self.messages, self.messages)
-
- def test_createAssociation(self):
- assoc = self.signatory.createAssociation(dumb=False)
- self.failUnless(self.signatory.getAssociation(assoc.handle, dumb=False))
- self.failIf(self.messages, self.messages)
-
- def makeAssoc(self, dumb, lifetime=60):
- assoc_handle = '{bling}'
- assoc = association.Association.fromExpiresIn(lifetime, assoc_handle,
- 'sekrit', 'HMAC-SHA1')
-
- self.store.storeAssociation((dumb and self._dumb_key) or self._normal_key, assoc)
- return assoc_handle
-
- def test_invalidate(self):
- assoc_handle = '-squash-'
- assoc = association.Association.fromExpiresIn(60, assoc_handle,
- 'sekrit', 'HMAC-SHA1')
-
- self.store.storeAssociation(self._dumb_key, assoc)
- assoc = self.signatory.getAssociation(assoc_handle, dumb=True)
- self.failUnless(assoc)
- assoc = self.signatory.getAssociation(assoc_handle, dumb=True)
- self.failUnless(assoc)
- self.signatory.invalidate(assoc_handle, dumb=True)
- assoc = self.signatory.getAssociation(assoc_handle, dumb=True)
- self.failIf(assoc)
- self.failIf(self.messages, self.messages)
-
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_services.py b/askbot/deps/openid/test/test_services.py
deleted file mode 100644
index 9459cc24..00000000
--- a/askbot/deps/openid/test/test_services.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import unittest
-
-from askbot.deps.openid.yadis import services
-from askbot.deps.openid.yadis.discover import DiscoveryFailure, DiscoveryResult
-
-
-class TestGetServiceEndpoints(unittest.TestCase):
- def setUp(self):
- self.orig_discover = services.discover
- services.discover = self.discover
-
- def tearDown(self):
- services.discover = self.orig_discover
-
- def discover(self, input_url):
- result = DiscoveryResult(input_url)
- result.response_text = "This is not XRDS text."
- return result
-
- def test_catchXRDSError(self):
- self.failUnlessRaises(DiscoveryFailure,
- services.getServiceEndpoints,
- "http://example.invalid/sometest")
diff --git a/askbot/deps/openid/test/test_sreg.py b/askbot/deps/openid/test/test_sreg.py
deleted file mode 100644
index 5c3af027..00000000
--- a/askbot/deps/openid/test/test_sreg.py
+++ /dev/null
@@ -1,484 +0,0 @@
-from askbot.deps.openid.extensions import sreg
-from askbot.deps.openid.message import NamespaceMap, Message, registerNamespaceAlias
-from askbot.deps.openid.server.server import OpenIDRequest, OpenIDResponse
-
-import unittest
-
-class SRegURITest(unittest.TestCase):
- def test_is11(self):
- self.failUnlessEqual(sreg.ns_uri_1_1, sreg.ns_uri)
-
-class CheckFieldNameTest(unittest.TestCase):
- def test_goodNamePasses(self):
- for field_name in sreg.data_fields:
- sreg.checkFieldName(field_name)
-
- def test_badNameFails(self):
- self.failUnlessRaises(ValueError, sreg.checkFieldName, 'INVALID')
-
- def test_badTypeFails(self):
- self.failUnlessRaises(ValueError, sreg.checkFieldName, None)
-
-# For supportsSReg test
-class FakeEndpoint(object):
- def __init__(self, supported):
- self.supported = supported
- self.checked_uris = []
-
- def usesExtension(self, namespace_uri):
- self.checked_uris.append(namespace_uri)
- return namespace_uri in self.supported
-
-class SupportsSRegTest(unittest.TestCase):
- def test_unsupported(self):
- endpoint = FakeEndpoint([])
- self.failIf(sreg.supportsSReg(endpoint))
- self.failUnlessEqual([sreg.ns_uri_1_1, sreg.ns_uri_1_0],
- endpoint.checked_uris)
-
- def test_supported_1_1(self):
- endpoint = FakeEndpoint([sreg.ns_uri_1_1])
- self.failUnless(sreg.supportsSReg(endpoint))
- self.failUnlessEqual([sreg.ns_uri_1_1], endpoint.checked_uris)
-
- def test_supported_1_0(self):
- endpoint = FakeEndpoint([sreg.ns_uri_1_0])
- self.failUnless(sreg.supportsSReg(endpoint))
- self.failUnlessEqual([sreg.ns_uri_1_1, sreg.ns_uri_1_0],
- endpoint.checked_uris)
-
-class FakeMessage(object):
- def __init__(self):
- self.openid1 = False
- self.namespaces = NamespaceMap()
-
- def isOpenID1(self):
- return self.openid1
-
-class GetNSTest(unittest.TestCase):
- def setUp(self):
- self.msg = FakeMessage()
-
- def test_openID2Empty(self):
- ns_uri = sreg.getSRegNS(self.msg)
- self.failUnlessEqual(self.msg.namespaces.getAlias(ns_uri), 'sreg')
- self.failUnlessEqual(sreg.ns_uri, ns_uri)
-
- def test_openID1Empty(self):
- self.msg.openid1 = True
- ns_uri = sreg.getSRegNS(self.msg)
- self.failUnlessEqual(self.msg.namespaces.getAlias(ns_uri), 'sreg')
- self.failUnlessEqual(sreg.ns_uri, ns_uri)
-
- def test_openID1Defined_1_0(self):
- self.msg.openid1 = True
- self.msg.namespaces.add(sreg.ns_uri_1_0)
- ns_uri = sreg.getSRegNS(self.msg)
- self.failUnlessEqual(sreg.ns_uri_1_0, ns_uri)
-
- def test_openID1Defined_1_0_overrideAlias(self):
- for openid_version in [True, False]:
- for sreg_version in [sreg.ns_uri_1_0, sreg.ns_uri_1_1]:
- for alias in ['sreg', 'bogus']:
- self.setUp()
-
- self.msg.openid1 = openid_version
- self.msg.namespaces.addAlias(sreg_version, alias)
- ns_uri = sreg.getSRegNS(self.msg)
- self.failUnlessEqual(self.msg.namespaces.getAlias(ns_uri), alias)
- self.failUnlessEqual(sreg_version, ns_uri)
-
- def test_openID1DefinedBadly(self):
- self.msg.openid1 = True
- self.msg.namespaces.addAlias('http://invalid/', 'sreg')
- self.failUnlessRaises(sreg.SRegNamespaceError,
- sreg.getSRegNS, self.msg)
-
- def test_openID2DefinedBadly(self):
- self.msg.openid1 = False
- self.msg.namespaces.addAlias('http://invalid/', 'sreg')
- self.failUnlessRaises(sreg.SRegNamespaceError,
- sreg.getSRegNS, self.msg)
-
- def test_openID2Defined_1_0(self):
- self.msg.namespaces.add(sreg.ns_uri_1_0)
- ns_uri = sreg.getSRegNS(self.msg)
- self.failUnlessEqual(sreg.ns_uri_1_0, ns_uri)
-
- def test_openID1_sregNSfromArgs(self):
- args = {
- 'sreg.optional': 'nickname',
- 'sreg.required': 'dob',
- }
-
- m = Message.fromOpenIDArgs(args)
-
- self.failUnless(m.getArg(sreg.ns_uri_1_1, 'optional') == 'nickname')
- self.failUnless(m.getArg(sreg.ns_uri_1_1, 'required') == 'dob')
-
-class SRegRequestTest(unittest.TestCase):
- def test_constructEmpty(self):
- req = sreg.SRegRequest()
- self.failUnlessEqual([], req.optional)
- self.failUnlessEqual([], req.required)
- self.failUnlessEqual(None, req.policy_url)
- self.failUnlessEqual(sreg.ns_uri, req.ns_uri)
-
- def test_constructFields(self):
- req = sreg.SRegRequest(
- ['nickname'],
- ['gender'],
- 'http://policy',
- 'http://sreg.ns_uri')
- self.failUnlessEqual(['gender'], req.optional)
- self.failUnlessEqual(['nickname'], req.required)
- self.failUnlessEqual('http://policy', req.policy_url)
- self.failUnlessEqual('http://sreg.ns_uri', req.ns_uri)
-
- def test_constructBadFields(self):
- self.failUnlessRaises(
- ValueError,
- sreg.SRegRequest, ['elvis'])
-
- def test_fromOpenIDRequest(self):
- args = {}
- ns_sentinel = object()
- args_sentinel = object()
-
- class FakeMessage(object):
- copied = False
-
- def __init__(self):
- self.message = Message()
-
- def getArgs(msg_self, ns_uri):
- self.failUnlessEqual(ns_sentinel, ns_uri)
- return args_sentinel
-
- def copy(msg_self):
- msg_self.copied = True
- return msg_self
-
- class TestingReq(sreg.SRegRequest):
- def _getSRegNS(req_self, unused):
- return ns_sentinel
-
- def parseExtensionArgs(req_self, args):
- self.failUnlessEqual(args_sentinel, args)
-
- openid_req = OpenIDRequest()
-
- msg = FakeMessage()
- openid_req.message = msg
-
- req = TestingReq.fromOpenIDRequest(openid_req)
- self.failUnless(type(req) is TestingReq)
- self.failUnless(msg.copied)
-
- def test_parseExtensionArgs_empty(self):
- req = sreg.SRegRequest()
- results = req.parseExtensionArgs({})
- self.failUnlessEqual(None, results)
-
- def test_parseExtensionArgs_extraIgnored(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'janrain':'inc'})
-
- def test_parseExtensionArgs_nonStrict(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'required':'beans'})
- self.failUnlessEqual([], req.required)
-
- def test_parseExtensionArgs_strict(self):
- req = sreg.SRegRequest()
- self.failUnlessRaises(
- ValueError,
- req.parseExtensionArgs, {'required':'beans'}, strict=True)
-
- def test_parseExtensionArgs_policy(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'policy_url':'http://policy'}, strict=True)
- self.failUnlessEqual('http://policy', req.policy_url)
-
- def test_parseExtensionArgs_requiredEmpty(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'required':''}, strict=True)
- self.failUnlessEqual([], req.required)
-
- def test_parseExtensionArgs_optionalEmpty(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'optional':''}, strict=True)
- self.failUnlessEqual([], req.optional)
-
- def test_parseExtensionArgs_optionalSingle(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'optional':'nickname'}, strict=True)
- self.failUnlessEqual(['nickname'], req.optional)
-
- def test_parseExtensionArgs_optionalList(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'optional':'nickname,email'}, strict=True)
- self.failUnlessEqual(['nickname','email'], req.optional)
-
- def test_parseExtensionArgs_optionalListBadNonStrict(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'optional':'nickname,email,beer'})
- self.failUnlessEqual(['nickname','email'], req.optional)
-
- def test_parseExtensionArgs_optionalListBadStrict(self):
- req = sreg.SRegRequest()
- self.failUnlessRaises(
- ValueError,
- req.parseExtensionArgs, {'optional':'nickname,email,beer'},
- strict=True)
-
- def test_parseExtensionArgs_bothNonStrict(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'optional':'nickname',
- 'required':'nickname'})
- self.failUnlessEqual([], req.optional)
- self.failUnlessEqual(['nickname'], req.required)
-
- def test_parseExtensionArgs_bothStrict(self):
- req = sreg.SRegRequest()
- self.failUnlessRaises(
- ValueError,
- req.parseExtensionArgs,
- {'optional':'nickname',
- 'required':'nickname'},
- strict=True)
-
- def test_parseExtensionArgs_bothList(self):
- req = sreg.SRegRequest()
- req.parseExtensionArgs({'optional':'nickname,email',
- 'required':'country,postcode'}, strict=True)
- self.failUnlessEqual(['nickname','email'], req.optional)
- self.failUnlessEqual(['country','postcode'], req.required)
-
- def test_allRequestedFields(self):
- req = sreg.SRegRequest()
- self.failUnlessEqual([], req.allRequestedFields())
- req.requestField('nickname')
- self.failUnlessEqual(['nickname'], req.allRequestedFields())
- req.requestField('gender', required=True)
- requested = req.allRequestedFields()
- requested.sort()
- self.failUnlessEqual(['gender', 'nickname'], requested)
-
- def test_wereFieldsRequested(self):
- req = sreg.SRegRequest()
- self.failIf(req.wereFieldsRequested())
- req.requestField('gender')
- self.failUnless(req.wereFieldsRequested())
-
- def test_contains(self):
- req = sreg.SRegRequest()
- for field_name in sreg.data_fields:
- self.failIf(field_name in req)
-
- self.failIf('something else' in req)
-
- req.requestField('nickname')
- for field_name in sreg.data_fields:
- if field_name == 'nickname':
- self.failUnless(field_name in req)
- else:
- self.failIf(field_name in req)
-
- def test_requestField_bogus(self):
- req = sreg.SRegRequest()
- self.failUnlessRaises(
- ValueError,
- req.requestField, 'something else')
-
- self.failUnlessRaises(
- ValueError,
- req.requestField, 'something else', strict=True)
-
- def test_requestField(self):
- # Add all of the fields, one at a time
- req = sreg.SRegRequest()
- fields = list(sreg.data_fields)
- for field_name in fields:
- req.requestField(field_name)
-
- self.failUnlessEqual(fields, req.optional)
- self.failUnlessEqual([], req.required)
-
- # By default, adding the same fields over again has no effect
- for field_name in fields:
- req.requestField(field_name)
-
- self.failUnlessEqual(fields, req.optional)
- self.failUnlessEqual([], req.required)
-
- # Requesting a field as required overrides requesting it as optional
- expected = list(fields)
- overridden = expected.pop(0)
- req.requestField(overridden, required=True)
- self.failUnlessEqual(expected, req.optional)
- self.failUnlessEqual([overridden], req.required)
-
- # Requesting a field as required overrides requesting it as optional
- for field_name in fields:
- req.requestField(field_name, required=True)
-
- self.failUnlessEqual([], req.optional)
- self.failUnlessEqual(fields, req.required)
-
- # Requesting it as optional does not downgrade it to optional
- for field_name in fields:
- req.requestField(field_name)
-
- self.failUnlessEqual([], req.optional)
- self.failUnlessEqual(fields, req.required)
-
- def test_requestFields_type(self):
- req = sreg.SRegRequest()
- self.failUnlessRaises(TypeError, req.requestFields, 'nickname')
-
- def test_requestFields(self):
- # Add all of the fields
- req = sreg.SRegRequest()
-
- fields = list(sreg.data_fields)
- req.requestFields(fields)
-
- self.failUnlessEqual(fields, req.optional)
- self.failUnlessEqual([], req.required)
-
- # By default, adding the same fields over again has no effect
- req.requestFields(fields)
-
- self.failUnlessEqual(fields, req.optional)
- self.failUnlessEqual([], req.required)
-
- # Requesting a field as required overrides requesting it as optional
- expected = list(fields)
- overridden = expected.pop(0)
- req.requestFields([overridden], required=True)
- self.failUnlessEqual(expected, req.optional)
- self.failUnlessEqual([overridden], req.required)
-
- # Requesting a field as required overrides requesting it as optional
- req.requestFields(fields, required=True)
-
- self.failUnlessEqual([], req.optional)
- self.failUnlessEqual(fields, req.required)
-
- # Requesting it as optional does not downgrade it to optional
- req.requestFields(fields)
-
- self.failUnlessEqual([], req.optional)
- self.failUnlessEqual(fields, req.required)
-
- def test_getExtensionArgs(self):
- req = sreg.SRegRequest()
- self.failUnlessEqual({}, req.getExtensionArgs())
-
- req.requestField('nickname')
- self.failUnlessEqual({'optional':'nickname'}, req.getExtensionArgs())
-
- req.requestField('email')
- self.failUnlessEqual({'optional':'nickname,email'},
- req.getExtensionArgs())
-
- req.requestField('gender', required=True)
- self.failUnlessEqual({'optional':'nickname,email',
- 'required':'gender'},
- req.getExtensionArgs())
-
- req.requestField('postcode', required=True)
- self.failUnlessEqual({'optional':'nickname,email',
- 'required':'gender,postcode'},
- req.getExtensionArgs())
-
- req.policy_url = 'http://policy.invalid/'
- self.failUnlessEqual({'optional':'nickname,email',
- 'required':'gender,postcode',
- 'policy_url':'http://policy.invalid/'},
- req.getExtensionArgs())
-
-data = {
- 'nickname':'linusaur',
- 'postcode':'12345',
- 'country':'US',
- 'gender':'M',
- 'fullname':'Leonhard Euler',
- 'email':'president@whitehouse.gov',
- 'dob':'0000-00-00',
- 'language':'en-us',
- }
-
-class DummySuccessResponse(object):
- def __init__(self, message, signed_stuff):
- self.message = message
- self.signed_stuff = signed_stuff
-
- def getSignedNS(self, ns_uri):
- return self.signed_stuff
-
-class SRegResponseTest(unittest.TestCase):
- def test_construct(self):
- resp = sreg.SRegResponse(data)
-
- self.failUnless(resp)
-
- empty_resp = sreg.SRegResponse({})
- self.failIf(empty_resp)
-
- # XXX: finish this test
-
- def test_fromSuccessResponse_signed(self):
- message = Message.fromOpenIDArgs({
- 'sreg.nickname':'The Mad Stork',
- })
- success_resp = DummySuccessResponse(message, {})
- sreg_resp = sreg.SRegResponse.fromSuccessResponse(success_resp)
- self.failIf(sreg_resp)
-
- def test_fromSuccessResponse_unsigned(self):
- message = Message.fromOpenIDArgs({
- 'sreg.nickname':'The Mad Stork',
- })
- success_resp = DummySuccessResponse(message, {})
- sreg_resp = sreg.SRegResponse.fromSuccessResponse(success_resp,
- signed_only=False)
- self.failUnlessEqual([('nickname', 'The Mad Stork')],
- sreg_resp.items())
-
-class SendFieldsTest(unittest.TestCase):
- def test(self):
- # Create a request message with simple registration fields
- sreg_req = sreg.SRegRequest(required=['nickname', 'email'],
- optional=['fullname'])
- req_msg = Message()
- req_msg.updateArgs(sreg.ns_uri, sreg_req.getExtensionArgs())
-
- req = OpenIDRequest()
- req.message = req_msg
- req.namespace = req_msg.getOpenIDNamespace()
-
- # -> send checkid_* request
-
- # Create an empty response message
- resp_msg = Message()
- resp = OpenIDResponse(req)
- resp.fields = resp_msg
-
- # Put the requested data fields in the response message
- sreg_resp = sreg.SRegResponse.extractResponse(sreg_req, data)
- resp.addExtension(sreg_resp)
-
- # <- send id_res response
-
- # Extract the fields that were sent
- sreg_data_resp = resp_msg.getArgs(sreg.ns_uri)
- self.failUnlessEqual(
- {'nickname':'linusaur',
- 'email':'president@whitehouse.gov',
- 'fullname':'Leonhard Euler',
- }, sreg_data_resp)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_symbol.py b/askbot/deps/openid/test/test_symbol.py
deleted file mode 100644
index 6f28048a..00000000
--- a/askbot/deps/openid/test/test_symbol.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import unittest
-
-from askbot.deps.openid import oidutil
-
-class SymbolTest(unittest.TestCase):
- def test_selfEquality(self):
- s = oidutil.Symbol('xxx')
- self.failUnlessEqual(s, s)
-
- def test_otherEquality(self):
- x = oidutil.Symbol('xxx')
- y = oidutil.Symbol('xxx')
- self.failUnlessEqual(x, y)
-
- def test_inequality(self):
- x = oidutil.Symbol('xxx')
- y = oidutil.Symbol('yyy')
- self.failIfEqual(x, y)
-
- def test_selfInequality(self):
- x = oidutil.Symbol('xxx')
- self.failIf(x != x)
-
- def test_otherInequality(self):
- x = oidutil.Symbol('xxx')
- y = oidutil.Symbol('xxx')
- self.failIf(x != y)
-
- def test_ne_inequality(self):
- x = oidutil.Symbol('xxx')
- y = oidutil.Symbol('yyy')
- self.failUnless(x != y)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_urinorm.py b/askbot/deps/openid/test/test_urinorm.py
deleted file mode 100644
index ecc4344f..00000000
--- a/askbot/deps/openid/test/test_urinorm.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import os
-import unittest
-from askbot.deps.openid import urinorm
-
-class UrinormTest(unittest.TestCase):
- def __init__(self, desc, case, expected):
- unittest.TestCase.__init__(self)
- self.desc = desc
- self.case = case
- self.expected = expected
-
- def shortDescription(self):
- return self.desc
-
- def runTest(self):
- try:
- actual = urinorm.urinorm(self.case)
- except ValueError, why:
- self.assertEqual(self.expected, 'fail', why)
- else:
- self.assertEqual(actual, self.expected)
-
- def parse(cls, full_case):
- desc, case, expected = full_case.split('\n')
- case = unicode(case, 'utf-8')
-
- return cls(desc, case, expected)
-
- parse = classmethod(parse)
-
-
-def parseTests(test_data):
- result = []
-
- cases = test_data.split('\n\n')
- for case in cases:
- case = case.strip()
-
- if case:
- result.append(UrinormTest.parse(case))
-
- return result
-
-def pyUnitTests():
- here = os.path.dirname(os.path.abspath(__file__))
- test_data_file_name = os.path.join(here, 'urinorm.txt')
- test_data_file = file(test_data_file_name)
- test_data = test_data_file.read()
- test_data_file.close()
-
- tests = parseTests(test_data)
- return unittest.TestSuite(tests)
diff --git a/askbot/deps/openid/test/test_verifydisco.py b/askbot/deps/openid/test/test_verifydisco.py
deleted file mode 100644
index acf99f01..00000000
--- a/askbot/deps/openid/test/test_verifydisco.py
+++ /dev/null
@@ -1,270 +0,0 @@
-import unittest
-from askbot.deps.openid import message
-from askbot.deps.openid.test.support import OpenIDTestMixin
-from askbot.deps.openid.consumer import consumer
-from askbot.deps.openid.test.test_consumer import TestIdRes
-from askbot.deps.openid.consumer import discover
-
-def const(result):
- """Return a function that ignores any arguments and just returns
- the specified result"""
- def constResult(*args, **kwargs):
- return result
-
- return constResult
-
-class DiscoveryVerificationTest(OpenIDTestMixin, TestIdRes):
- def failUnlessProtocolError(self, prefix, callable, *args, **kwargs):
- try:
- result = callable(*args, **kwargs)
- except consumer.ProtocolError, e:
- self.failUnless(
- e[0].startswith(prefix),
- 'Expected message prefix %r, got message %r' % (prefix, e[0]))
- else:
- self.fail('Expected ProtocolError with prefix %r, '
- 'got successful return %r' % (prefix, result))
-
- def test_openID1NoLocalID(self):
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.claimed_id = 'bogus'
-
- msg = message.Message.fromOpenIDArgs({})
- self.failUnlessProtocolError(
- 'Missing required field openid.identity',
- self.consumer._verifyDiscoveryResults, msg, endpoint)
- self.failUnlessLogEmpty()
-
- def test_openID1NoEndpoint(self):
- msg = message.Message.fromOpenIDArgs({'identity':'snakes on a plane'})
- self.failUnlessRaises(RuntimeError,
- self.consumer._verifyDiscoveryResults, msg)
- self.failUnlessLogEmpty()
-
- def test_openID2NoOPEndpointArg(self):
- msg = message.Message.fromOpenIDArgs({'ns':message.OPENID2_NS})
- self.failUnlessRaises(KeyError,
- self.consumer._verifyDiscoveryResults, msg)
- self.failUnlessLogEmpty()
-
- def test_openID2LocalIDNoClaimed(self):
- msg = message.Message.fromOpenIDArgs({'ns':message.OPENID2_NS,
- 'op_endpoint':'Phone Home',
- 'identity':'Jose Lius Borges'})
- self.failUnlessProtocolError(
- 'openid.identity is present without',
- self.consumer._verifyDiscoveryResults, msg)
- self.failUnlessLogEmpty()
-
- def test_openID2NoLocalIDClaimed(self):
- msg = message.Message.fromOpenIDArgs({'ns':message.OPENID2_NS,
- 'op_endpoint':'Phone Home',
- 'claimed_id':'Manuel Noriega'})
- self.failUnlessProtocolError(
- 'openid.claimed_id is present without',
- self.consumer._verifyDiscoveryResults, msg)
- self.failUnlessLogEmpty()
-
- def test_openID2NoIdentifiers(self):
- op_endpoint = 'Phone Home'
- msg = message.Message.fromOpenIDArgs({'ns':message.OPENID2_NS,
- 'op_endpoint':op_endpoint})
- result_endpoint = self.consumer._verifyDiscoveryResults(msg)
- self.failUnless(result_endpoint.isOPIdentifier())
- self.failUnlessEqual(op_endpoint, result_endpoint.server_url)
- self.failUnlessEqual(None, result_endpoint.claimed_id)
- self.failUnlessLogEmpty()
-
- def test_openID2NoEndpointDoesDisco(self):
- op_endpoint = 'Phone Home'
- sentinel = discover.OpenIDServiceEndpoint()
- sentinel.claimed_id = 'monkeysoft'
- self.consumer._discoverAndVerify = const(sentinel)
- msg = message.Message.fromOpenIDArgs(
- {'ns':message.OPENID2_NS,
- 'identity':'sour grapes',
- 'claimed_id':'monkeysoft',
- 'op_endpoint':op_endpoint})
- result = self.consumer._verifyDiscoveryResults(msg)
- self.failUnlessEqual(sentinel, result)
- self.failUnlessLogMatches('No pre-discovered')
-
- def test_openID2MismatchedDoesDisco(self):
- mismatched = discover.OpenIDServiceEndpoint()
- mismatched.identity = 'nothing special, but different'
- mismatched.local_id = 'green cheese'
-
- op_endpoint = 'Phone Home'
- sentinel = discover.OpenIDServiceEndpoint()
- sentinel.claimed_id = 'monkeysoft'
- self.consumer._discoverAndVerify = const(sentinel)
- msg = message.Message.fromOpenIDArgs(
- {'ns':message.OPENID2_NS,
- 'identity':'sour grapes',
- 'claimed_id':'monkeysoft',
- 'op_endpoint':op_endpoint})
- result = self.consumer._verifyDiscoveryResults(msg, mismatched)
- self.failUnlessEqual(sentinel, result)
- self.failUnlessLogMatches('Error attempting to use stored',
- 'Attempting discovery')
-
- def test_openid2UsePreDiscovered(self):
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.local_id = 'my identity'
- endpoint.claimed_id = 'i am sam'
- endpoint.server_url = 'Phone Home'
- endpoint.type_uris = [discover.OPENID_2_0_TYPE]
-
- msg = message.Message.fromOpenIDArgs(
- {'ns':message.OPENID2_NS,
- 'identity':endpoint.local_id,
- 'claimed_id':endpoint.claimed_id,
- 'op_endpoint':endpoint.server_url})
- result = self.consumer._verifyDiscoveryResults(msg, endpoint)
- self.failUnless(result is endpoint)
- self.failUnlessLogEmpty()
-
- def test_openid2UsePreDiscoveredWrongType(self):
- text = "verify failed"
-
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.local_id = 'my identity'
- endpoint.claimed_id = 'i am sam'
- endpoint.server_url = 'Phone Home'
- endpoint.type_uris = [discover.OPENID_1_1_TYPE]
-
- def discoverAndVerify(claimed_id, to_match_endpoints):
- self.failUnlessEqual(claimed_id, endpoint.claimed_id)
- for to_match in to_match_endpoints:
- self.failUnlessEqual(claimed_id, to_match.claimed_id)
- raise consumer.ProtocolError(text)
-
- self.consumer._discoverAndVerify = discoverAndVerify
-
- msg = message.Message.fromOpenIDArgs(
- {'ns':message.OPENID2_NS,
- 'identity':endpoint.local_id,
- 'claimed_id':endpoint.claimed_id,
- 'op_endpoint':endpoint.server_url})
-
- try:
- r = self.consumer._verifyDiscoveryResults(msg, endpoint)
- except consumer.ProtocolError, e:
- # Should we make more ProtocolError subclasses?
- self.failUnless(str(e), text)
- else:
- self.fail("expected ProtocolError, %r returned." % (r,))
-
- self.failUnlessLogMatches('Error attempting to use stored',
- 'Attempting discovery')
-
- def test_openid1UsePreDiscovered(self):
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.local_id = 'my identity'
- endpoint.claimed_id = 'i am sam'
- endpoint.server_url = 'Phone Home'
- endpoint.type_uris = [discover.OPENID_1_1_TYPE]
-
- msg = message.Message.fromOpenIDArgs(
- {'ns':message.OPENID1_NS,
- 'identity':endpoint.local_id})
- result = self.consumer._verifyDiscoveryResults(msg, endpoint)
- self.failUnless(result is endpoint)
- self.failUnlessLogEmpty()
-
- def test_openid1UsePreDiscoveredWrongType(self):
- class VerifiedError(Exception): pass
-
- def discoverAndVerify(claimed_id, _to_match):
- raise VerifiedError
-
- self.consumer._discoverAndVerify = discoverAndVerify
-
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.local_id = 'my identity'
- endpoint.claimed_id = 'i am sam'
- endpoint.server_url = 'Phone Home'
- endpoint.type_uris = [discover.OPENID_2_0_TYPE]
-
- msg = message.Message.fromOpenIDArgs(
- {'ns':message.OPENID1_NS,
- 'identity':endpoint.local_id})
-
- self.failUnlessRaises(
- VerifiedError,
- self.consumer._verifyDiscoveryResults, msg, endpoint)
-
- self.failUnlessLogMatches('Error attempting to use stored',
- 'Attempting discovery')
-
- def test_openid2Fragment(self):
- claimed_id = "http://unittest.invalid/"
- claimed_id_frag = claimed_id + "#fragment"
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.local_id = 'my identity'
- endpoint.claimed_id = claimed_id
- endpoint.server_url = 'Phone Home'
- endpoint.type_uris = [discover.OPENID_2_0_TYPE]
-
- msg = message.Message.fromOpenIDArgs(
- {'ns':message.OPENID2_NS,
- 'identity':endpoint.local_id,
- 'claimed_id': claimed_id_frag,
- 'op_endpoint': endpoint.server_url})
- result = self.consumer._verifyDiscoveryResults(msg, endpoint)
-
- self.failUnlessEqual(result.local_id, endpoint.local_id)
- self.failUnlessEqual(result.server_url, endpoint.server_url)
- self.failUnlessEqual(result.type_uris, endpoint.type_uris)
-
- self.failUnlessEqual(result.claimed_id, claimed_id_frag)
-
- self.failUnlessLogEmpty()
-
- def test_openid1Fallback1_0(self):
- claimed_id = 'http://claimed.id/'
- endpoint = None
- resp_mesg = message.Message.fromOpenIDArgs({
- 'ns': message.OPENID1_NS,
- 'identity': claimed_id})
- # Pass the OpenID 1 claimed_id this way since we're passing
- # None for the endpoint.
- resp_mesg.setArg(message.BARE_NS, 'openid1_claimed_id', claimed_id)
-
- # We expect the OpenID 1 discovery verification to try
- # matching the discovered endpoint against the 1.1 type and
- # fall back to 1.0.
- expected_endpoint = discover.OpenIDServiceEndpoint()
- expected_endpoint.type_uris = [discover.OPENID_1_0_TYPE]
- expected_endpoint.local_id = None
- expected_endpoint.claimed_id = claimed_id
-
- discovered_services = [expected_endpoint]
- self.consumer._discover = lambda *args: ('unused', discovered_services)
-
- actual_endpoint = self.consumer._verifyDiscoveryResults(
- resp_mesg, endpoint)
- self.failUnless(actual_endpoint is expected_endpoint)
-
-# XXX: test the implementation of _discoverAndVerify
-
-
-class TestVerifyDiscoverySingle(TestIdRes):
- # XXX: more test the implementation of _verifyDiscoverySingle
- def test_endpointWithoutLocalID(self):
- # An endpoint like this with no local_id is generated as a result of
- # e.g. Yadis discovery with no LocalID tag.
- endpoint = discover.OpenIDServiceEndpoint()
- endpoint.server_url = "http://localhost:8000/openidserver"
- endpoint.claimed_id = "http://localhost:8000/id/id-jo"
- to_match = discover.OpenIDServiceEndpoint()
- to_match.server_url = "http://localhost:8000/openidserver"
- to_match.claimed_id = "http://localhost:8000/id/id-jo"
- to_match.local_id = "http://localhost:8000/id/id-jo"
- result = self.consumer._verifyDiscoverySingle(endpoint, to_match)
- # result should always be None, raises exception on failure.
- self.failUnlessEqual(result, None)
- self.failUnlessLogEmpty()
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/askbot/deps/openid/test/test_xri.py b/askbot/deps/openid/test/test_xri.py
deleted file mode 100644
index ddab614f..00000000
--- a/askbot/deps/openid/test/test_xri.py
+++ /dev/null
@@ -1,102 +0,0 @@
-from unittest import TestCase
-from askbot.deps.openid.yadis import xri
-
-class XriDiscoveryTestCase(TestCase):
- def test_isXRI(self):
- i = xri.identifierScheme
- self.failUnlessEqual(i('=john.smith'), 'XRI')
- self.failUnlessEqual(i('@smiths/john'), 'XRI')
- self.failUnlessEqual(i('smoker.myopenid.com'), 'URI')
- self.failUnlessEqual(i('xri://=john'), 'XRI')
- self.failUnlessEqual(i(''), 'URI')
-
-
-class XriEscapingTestCase(TestCase):
- def test_escaping_percents(self):
- self.failUnlessEqual(xri.escapeForIRI('@example/abc%2Fd/ef'),
- '@example/abc%252Fd/ef')
-
-
- def test_escaping_xref(self):
- # no escapes
- esc = xri.escapeForIRI
- self.failUnlessEqual('@example/foo/(@bar)', esc('@example/foo/(@bar)'))
- # escape slashes
- self.failUnlessEqual('@example/foo/(@bar%2Fbaz)',
- esc('@example/foo/(@bar/baz)'))
- self.failUnlessEqual('@example/foo/(@bar%2Fbaz)/(+a%2Fb)',
- esc('@example/foo/(@bar/baz)/(+a/b)'))
- # escape query ? and fragment #
- self.failUnlessEqual('@example/foo/(@baz%3Fp=q%23r)?i=j#k',
- esc('@example/foo/(@baz?p=q#r)?i=j#k'))
-
-
-
-class XriTransformationTestCase(TestCase):
- def test_to_iri_normal(self):
- self.failUnlessEqual(xri.toIRINormal('@example'), 'xri://@example')
-
- try:
- unichr(0x10000)
- except ValueError:
- # bleh narrow python build
- def test_iri_to_url(self):
- s = u'l\xa1m'
- expected = 'l%C2%A1m'
- self.failUnlessEqual(xri.iriToURI(s), expected)
- else:
- def test_iri_to_url(self):
- s = u'l\xa1m\U00101010n'
- expected = 'l%C2%A1m%F4%81%80%90n'
- self.failUnlessEqual(xri.iriToURI(s), expected)
-
-
-
-class CanonicalIDTest(TestCase):
- def mkTest(providerID, canonicalID, isAuthoritative):
- def test(self):
- result = xri.providerIsAuthoritative(providerID, canonicalID)
- format = "%s providing %s, expected %s"
- message = format % (providerID, canonicalID, isAuthoritative)
- self.failUnlessEqual(isAuthoritative, result, message)
-
- return test
-
- test_equals = mkTest('=', '=!698.74D1.A1F2.86C7', True)
- test_atOne = mkTest('@!1234', '@!1234!ABCD', True)
- test_atTwo = mkTest('@!1234!5678', '@!1234!5678!ABCD', True)
-
- test_atEqualsFails = mkTest('@!1234', '=!1234!ABCD', False)
- test_tooDeepFails = mkTest('@!1234', '@!1234!ABCD!9765', False)
- test_atEqualsAndTooDeepFails = mkTest('@!1234!ABCD', '=!1234', False)
- test_differentBeginningFails = mkTest('=!BABE', '=!D00D', False)
-
-class TestGetRootAuthority(TestCase):
- def mkTest(the_xri, expected_root):
- def test(self):
- actual_root = xri.rootAuthority(the_xri)
- self.failUnlessEqual(actual_root, xri.XRI(expected_root))
- return test
-
- test_at = mkTest("@foo", "@")
- test_atStar = mkTest("@foo*bar", "@")
- test_atStarStar = mkTest("@*foo*bar", "@")
- test_atWithPath = mkTest("@foo/bar", "@")
- test_bangBang = mkTest("!!990!991", "!")
- test_bang = mkTest("!1001!02", "!")
- test_equalsStar = mkTest("=foo*bar", "=")
- test_xrefPath = mkTest("(example.com)/foo", "(example.com)")
- test_xrefStar = mkTest("(example.com)*bar/foo", "(example.com)")
- test_uriAuth = mkTest("baz.example.com/foo", "baz.example.com")
- test_uriAuthPort = mkTest("baz.example.com:8080/foo",
- "baz.example.com:8080")
-
- # Looking at the ABNF in XRI Syntax 2.0, I don't think you can
- # have example.com*bar. You can do (example.com)*bar, but that
- # would mean something else.
- ##("example.com*bar/(=baz)", "example.com*bar"),
- ##("baz.example.com!01/foo", "baz.example.com!01"),
-
-if __name__ == '__main__':
- import unittest
- unittest.main()
diff --git a/askbot/deps/openid/test/test_xrires.py b/askbot/deps/openid/test/test_xrires.py
deleted file mode 100644
index 02d010d6..00000000
--- a/askbot/deps/openid/test/test_xrires.py
+++ /dev/null
@@ -1,40 +0,0 @@
-
-from unittest import TestCase
-from askbot.deps.openid.yadis import xrires
-
-class ProxyQueryTestCase(TestCase):
- def setUp(self):
- self.proxy_url = 'http://xri.example.com/'
- self.proxy = xrires.ProxyResolver(self.proxy_url)
- self.servicetype = 'xri://+i-service*(+forwarding)*($v*1.0)'
- self.servicetype_enc = 'xri%3A%2F%2F%2Bi-service%2A%28%2Bforwarding%29%2A%28%24v%2A1.0%29'
-
-
- def test_proxy_url(self):
- st = self.servicetype
- ste = self.servicetype_enc
- args_esc = "_xrd_r=application%2Fxrds%2Bxml&_xrd_t=" + ste
- pqu = self.proxy.queryURL
- h = self.proxy_url
- self.failUnlessEqual(h + '=foo?' + args_esc, pqu('=foo', st))
- self.failUnlessEqual(h + '=foo/bar?baz&' + args_esc,
- pqu('=foo/bar?baz', st))
- self.failUnlessEqual(h + '=foo/bar?baz=quux&' + args_esc,
- pqu('=foo/bar?baz=quux', st))
- self.failUnlessEqual(h + '=foo/bar?mi=fa&so=la&' + args_esc,
- pqu('=foo/bar?mi=fa&so=la', st))
-
- # With no service endpoint selection.
- args_esc = "_xrd_r=application%2Fxrds%2Bxml%3Bsep%3Dfalse"
- self.failUnlessEqual(h + '=foo?' + args_esc, pqu('=foo', None))
-
-
- def test_proxy_url_qmarks(self):
- st = self.servicetype
- ste = self.servicetype_enc
- args_esc = "_xrd_r=application%2Fxrds%2Bxml&_xrd_t=" + ste
- pqu = self.proxy.queryURL
- h = self.proxy_url
- self.failUnlessEqual(h + '=foo/bar??' + args_esc, pqu('=foo/bar?', st))
- self.failUnlessEqual(h + '=foo/bar????' + args_esc,
- pqu('=foo/bar???', st))
diff --git a/askbot/deps/openid/test/test_yadis_discover.py b/askbot/deps/openid/test/test_yadis_discover.py
deleted file mode 100644
index aae83993..00000000
--- a/askbot/deps/openid/test/test_yadis_discover.py
+++ /dev/null
@@ -1,179 +0,0 @@
-#!/usr/bin/env python
-
-"""Tests for yadis.discover.
-
-@todo: Now that yadis.discover uses urljr.fetchers, we should be able to do
- tests with a mock fetcher instead of spawning threads with BaseHTTPServer.
-"""
-
-import unittest
-import urlparse
-import re
-import types
-
-from askbot.deps.openid.yadis.discover import discover, DiscoveryFailure
-
-from askbot.deps.openid import fetchers
-
-import discoverdata
-
-status_header_re = re.compile(r'Status: (\d+) .*?$', re.MULTILINE)
-
-four04_pat = """\
-Content-Type: text/plain
-
-No such file %s
-"""
-
-class QuitServer(Exception): pass
-
-def mkResponse(data):
- status_mo = status_header_re.match(data)
- headers_str, body = data.split('\n\n', 1)
- headers = {}
- for line in headers_str.split('\n'):
- k, v = line.split(':', 1)
- k = k.strip().lower()
- v = v.strip()
- headers[k] = v
- status = int(status_mo.group(1))
- return fetchers.HTTPResponse(status=status,
- headers=headers,
- body=body)
-
-class TestFetcher(object):
- def __init__(self, base_url):
- self.base_url = base_url
-
- def fetch(self, url, headers, body):
- current_url = url
- while True:
- parsed = urlparse.urlparse(current_url)
- path = parsed[2][1:]
- try:
- data = discoverdata.generateSample(path, self.base_url)
- except KeyError:
- return fetchers.HTTPResponse(status=404,
- final_url=current_url,
- headers={},
- body='')
-
- response = mkResponse(data)
- if response.status in [301, 302, 303, 307]:
- current_url = response.headers['location']
- else:
- response.final_url = current_url
- return response
-
-class TestSecondGet(unittest.TestCase):
- class MockFetcher(object):
- def __init__(self):
- self.count = 0
- def fetch(self, uri, headers=None, body=None):
- self.count += 1
- if self.count == 1:
- headers = {
- 'X-XRDS-Location'.lower(): 'http://unittest/404',
- }
- return fetchers.HTTPResponse(uri, 200, headers, '')
- else:
- return fetchers.HTTPResponse(uri, 404)
-
- def setUp(self):
- self.oldfetcher = fetchers.getDefaultFetcher()
- fetchers.setDefaultFetcher(self.MockFetcher())
-
- def tearDown(self):
- fetchers.setDefaultFetcher(self.oldfetcher)
-
- def test_404(self):
- uri = "http://something.unittest/"
- self.failUnlessRaises(DiscoveryFailure, discover, uri)
-
-
-class _TestCase(unittest.TestCase):
- base_url = 'http://invalid.unittest/'
-
- def __init__(self, input_name, id_name, result_name, success):
- self.input_name = input_name
- self.id_name = id_name
- self.result_name = result_name
- self.success = success
- # Still not quite sure how to best construct these custom tests.
- # Between python2.3 and python2.4, a patch attached to pyunit.sf.net
- # bug #469444 got applied which breaks loadTestsFromModule on this
- # class if it has test_ or runTest methods. So, kludge to change
- # the method name.
- unittest.TestCase.__init__(self, methodName='runCustomTest')
-
- def setUp(self):
- fetchers.setDefaultFetcher(TestFetcher(self.base_url),
- wrap_exceptions=False)
-
- self.input_url, self.expected = discoverdata.generateResult(
- self.base_url,
- self.input_name,
- self.id_name,
- self.result_name,
- self.success)
-
- def tearDown(self):
- fetchers.setDefaultFetcher(None)
-
- def runCustomTest(self):
- if self.expected is DiscoveryFailure:
- self.failUnlessRaises(DiscoveryFailure,
- discover, self.input_url)
- else:
- result = discover(self.input_url)
- self.failUnlessEqual(self.input_url, result.request_uri)
-
- msg = 'Identity URL mismatch: actual = %r, expected = %r' % (
- result.normalized_uri, self.expected.normalized_uri)
- self.failUnlessEqual(
- self.expected.normalized_uri, result.normalized_uri, msg)
-
- msg = 'Content mismatch: actual = %r, expected = %r' % (
- result.response_text, self.expected.response_text)
- self.failUnlessEqual(
- self.expected.response_text, result.response_text, msg)
-
- expected_keys = dir(self.expected)
- expected_keys.sort()
- actual_keys = dir(result)
- actual_keys.sort()
- self.failUnlessEqual(actual_keys, expected_keys)
-
- for k in dir(self.expected):
- if k.startswith('__') and k.endswith('__'):
- continue
- exp_v = getattr(self.expected, k)
- if isinstance(exp_v, types.MethodType):
- continue
- act_v = getattr(result, k)
- assert act_v == exp_v, (k, exp_v, act_v)
-
- def shortDescription(self):
- try:
- n = self.input_url
- except AttributeError:
- # run before setUp, or if setUp did not complete successfully.
- n = self.input_name
- return "%s (%s)" % (
- n,
- self.__class__.__module__)
-
-def pyUnitTests():
- s = unittest.TestSuite()
- for success, input_name, id_name, result_name in discoverdata.testlist:
- test = _TestCase(input_name, id_name, result_name, success)
- s.addTest(test)
-
- return s
-
-def test():
- runner = unittest.TextTestRunner()
- return runner.run(loadTests())
-
-if __name__ == '__main__':
- test()
diff --git a/askbot/deps/openid/test/trustroot.py b/askbot/deps/openid/test/trustroot.py
deleted file mode 100644
index 2c378823..00000000
--- a/askbot/deps/openid/test/trustroot.py
+++ /dev/null
@@ -1,85 +0,0 @@
-import os
-import unittest
-from askbot.deps.openid.server.trustroot import TrustRoot
-
-class _ParseTest(unittest.TestCase):
- def __init__(self, sanity, desc, case):
- unittest.TestCase.__init__(self)
- self.desc = desc + ': ' + repr(case)
- self.case = case
- self.sanity = sanity
-
- def shortDescription(self):
- return self.desc
-
- def runTest(self):
- tr = TrustRoot.parse(self.case)
- if self.sanity == 'sane':
- assert tr.isSane(), self.case
- elif self.sanity == 'insane':
- assert not tr.isSane(), self.case
- else:
- assert tr is None, tr
-
-class _MatchTest(unittest.TestCase):
- def __init__(self, match, desc, line):
- unittest.TestCase.__init__(self)
- tr, rt = line.split()
- self.desc = desc + ': ' + repr(tr) + ' ' + repr(rt)
- self.tr = tr
- self.rt = rt
- self.match = match
-
- def shortDescription(self):
- return self.desc
-
- def runTest(self):
- tr = TrustRoot.parse(self.tr)
- self.failIf(tr is None, self.tr)
-
- match = tr.validateURL(self.rt)
- if self.match:
- assert match
- else:
- assert not match
-
-def getTests(t, grps, head, dat):
- tests = []
- top = head.strip()
- gdat = map(str.strip, dat.split('-' * 40 + '\n'))
- assert not gdat[0]
- assert len(gdat) == (len(grps) * 2 + 1), (gdat, grps)
- i = 1
- for x in grps:
- n, desc = gdat[i].split(': ')
- cases = gdat[i + 1].split('\n')
- assert len(cases) == int(n)
- for case in cases:
- tests.append(t(x, top + ' - ' + desc, case))
- i += 2
- return tests
-
-def parseTests(data):
- parts = map(str.strip, data.split('=' * 40 + '\n'))
- assert not parts[0]
- _, ph, pdat, mh, mdat = parts
-
- tests = []
- tests.extend(getTests(_ParseTest, ['bad', 'insane', 'sane'], ph, pdat))
- tests.extend(getTests(_MatchTest, [1, 0], mh, mdat))
- return tests
-
-def pyUnitTests():
- here = os.path.dirname(os.path.abspath(__file__))
- test_data_file_name = os.path.join(here, 'data', 'trustroot.txt')
- test_data_file = file(test_data_file_name)
- test_data = test_data_file.read()
- test_data_file.close()
-
- tests = parseTests(test_data)
- return unittest.TestSuite(tests)
-
-if __name__ == '__main__':
- suite = pyUnitTests()
- runner = unittest.TextTestRunner()
- runner.run(suite)
diff --git a/askbot/deps/openid/test/urinorm.txt b/askbot/deps/openid/test/urinorm.txt
deleted file mode 100644
index a5db39e9..00000000
--- a/askbot/deps/openid/test/urinorm.txt
+++ /dev/null
@@ -1,87 +0,0 @@
-Already normal form
-http://example.com/
-http://example.com/
-
-Add a trailing slash
-http://example.com
-http://example.com/
-
-Remove an empty port segment
-http://example.com:/
-http://example.com/
-
-Remove a default port segment
-http://example.com:80/
-http://example.com/
-
-Capitalization in host names
-http://wWw.exaMPLE.COm/
-http://www.example.com/
-
-Capitalization in scheme names
-htTP://example.com/
-http://example.com/
-
-Capitalization in percent-escaped reserved characters
-http://example.com/foo%2cbar
-http://example.com/foo%2Cbar
-
-Unescape percent-encoded unreserved characters
-http://example.com/foo%2Dbar%2dbaz
-http://example.com/foo-bar-baz
-
-remove_dot_segments example 1
-http://example.com/a/b/c/./../../g
-http://example.com/a/g
-
-remove_dot_segments example 2
-http://example.com/mid/content=5/../6
-http://example.com/mid/6
-
-remove_dot_segments: single-dot
-http://example.com/a/./b
-http://example.com/a/b
-
-remove_dot_segments: double-dot
-http://example.com/a/../b
-http://example.com/b
-
-remove_dot_segments: leading double-dot
-http://example.com/../b
-http://example.com/b
-
-remove_dot_segments: trailing single-dot
-http://example.com/a/.
-http://example.com/a/
-
-remove_dot_segments: trailing double-dot
-http://example.com/a/..
-http://example.com/
-
-remove_dot_segments: trailing single-dot-slash
-http://example.com/a/./
-http://example.com/a/
-
-remove_dot_segments: trailing double-dot-slash
-http://example.com/a/../
-http://example.com/
-
-Test of all kinds of syntax-based normalization
-hTTPS://a/./b/../b/%63/%7bfoo%7d
-https://a/b/c/%7Bfoo%7D
-
-Unsupported scheme
-ftp://example.com/
-fail
-
-Non-absolute URI
-http:/foo
-fail
-
-Illegal character in URI
-http://<illegal>.com/
-fail
-
-Non-ascii character in URI
-http://foo.com/
-fail
diff --git a/askbot/deps/openid/urinorm.py b/askbot/deps/openid/urinorm.py
deleted file mode 100644
index 5bdbaeff..00000000
--- a/askbot/deps/openid/urinorm.py
+++ /dev/null
@@ -1,202 +0,0 @@
-import re
-
-# from appendix B of rfc 3986 (http://www.ietf.org/rfc/rfc3986.txt)
-uri_pattern = r'^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?'
-uri_re = re.compile(uri_pattern)
-
-# gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
-#
-# sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
-# / "*" / "+" / "," / ";" / "="
-#
-# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
-
-uri_illegal_char_re = re.compile(
- "[^-A-Za-z0-9:/?#[\]@!$&'()*+,;=._~%]", re.UNICODE)
-
-authority_pattern = r'^([^@]*@)?([^:]*)(:.*)?'
-authority_re = re.compile(authority_pattern)
-
-
-pct_encoded_pattern = r'%([0-9A-Fa-f]{2})'
-pct_encoded_re = re.compile(pct_encoded_pattern)
-
-try:
- unichr(0x10000)
-except ValueError:
- # narrow python build
- UCSCHAR = [
- (0xA0, 0xD7FF),
- (0xF900, 0xFDCF),
- (0xFDF0, 0xFFEF),
- ]
-
- IPRIVATE = [
- (0xE000, 0xF8FF),
- ]
-else:
- UCSCHAR = [
- (0xA0, 0xD7FF),
- (0xF900, 0xFDCF),
- (0xFDF0, 0xFFEF),
- (0x10000, 0x1FFFD),
- (0x20000, 0x2FFFD),
- (0x30000, 0x3FFFD),
- (0x40000, 0x4FFFD),
- (0x50000, 0x5FFFD),
- (0x60000, 0x6FFFD),
- (0x70000, 0x7FFFD),
- (0x80000, 0x8FFFD),
- (0x90000, 0x9FFFD),
- (0xA0000, 0xAFFFD),
- (0xB0000, 0xBFFFD),
- (0xC0000, 0xCFFFD),
- (0xD0000, 0xDFFFD),
- (0xE1000, 0xEFFFD),
- ]
-
- IPRIVATE = [
- (0xE000, 0xF8FF),
- (0xF0000, 0xFFFFD),
- (0x100000, 0x10FFFD),
- ]
-
-
-_unreserved = [False] * 256
-for _ in range(ord('A'), ord('Z') + 1): _unreserved[_] = True
-for _ in range(ord('0'), ord('9') + 1): _unreserved[_] = True
-for _ in range(ord('a'), ord('z') + 1): _unreserved[_] = True
-_unreserved[ord('-')] = True
-_unreserved[ord('.')] = True
-_unreserved[ord('_')] = True
-_unreserved[ord('~')] = True
-
-
-_escapeme_re = re.compile('[%s]' % (''.join(
- map(lambda (m, n): u'%s-%s' % (unichr(m), unichr(n)),
- UCSCHAR + IPRIVATE)),))
-
-
-def _pct_escape_unicode(char_match):
- c = char_match.group()
- return ''.join(['%%%X' % (ord(octet),) for octet in c.encode('utf-8')])
-
-
-def _pct_encoded_replace_unreserved(mo):
- try:
- i = int(mo.group(1), 16)
- if _unreserved[i]:
- return chr(i)
- else:
- return mo.group().upper()
-
- except ValueError:
- return mo.group()
-
-
-def _pct_encoded_replace(mo):
- try:
- return chr(int(mo.group(1), 16))
- except ValueError:
- return mo.group()
-
-
-def remove_dot_segments(path):
- result_segments = []
-
- while path:
- if path.startswith('../'):
- path = path[3:]
- elif path.startswith('./'):
- path = path[2:]
- elif path.startswith('/./'):
- path = path[2:]
- elif path == '/.':
- path = '/'
- elif path.startswith('/../'):
- path = path[3:]
- if result_segments:
- result_segments.pop()
- elif path == '/..':
- path = '/'
- if result_segments:
- result_segments.pop()
- elif path == '..' or path == '.':
- path = ''
- else:
- i = 0
- if path[0] == '/':
- i = 1
- i = path.find('/', i)
- if i == -1:
- i = len(path)
- result_segments.append(path[:i])
- path = path[i:]
-
- return ''.join(result_segments)
-
-
-def urinorm(uri):
- if isinstance(uri, unicode):
- uri = _escapeme_re.sub(_pct_escape_unicode, uri).encode('ascii')
-
- illegal_mo = uri_illegal_char_re.search(uri)
- if illegal_mo:
- raise ValueError('Illegal characters in URI: %r at position %s' %
- (illegal_mo.group(), illegal_mo.start()))
-
- uri_mo = uri_re.match(uri)
-
- scheme = uri_mo.group(2)
- if scheme is None:
- raise ValueError('No scheme specified')
-
- scheme = scheme.lower()
- if scheme not in ('http', 'https'):
- raise ValueError('Not an absolute HTTP or HTTPS URI: %r' % (uri,))
-
- authority = uri_mo.group(4)
- if authority is None:
- raise ValueError('Not an absolute URI: %r' % (uri,))
-
- authority_mo = authority_re.match(authority)
- if authority_mo is None:
- raise ValueError('URI does not have a valid authority: %r' % (uri,))
-
- userinfo, host, port = authority_mo.groups()
-
- if userinfo is None:
- userinfo = ''
-
- if '%' in host:
- host = host.lower()
- host = pct_encoded_re.sub(_pct_encoded_replace, host)
- host = unicode(host, 'utf-8').encode('idna')
- else:
- host = host.lower()
-
- if port:
- if (port == ':' or
- (scheme == 'http' and port == ':80') or
- (scheme == 'https' and port == ':443')):
- port = ''
- else:
- port = ''
-
- authority = userinfo + host + port
-
- path = uri_mo.group(5)
- path = pct_encoded_re.sub(_pct_encoded_replace_unreserved, path)
- path = remove_dot_segments(path)
- if not path:
- path = '/'
-
- query = uri_mo.group(6)
- if query is None:
- query = ''
-
- fragment = uri_mo.group(8)
- if fragment is None:
- fragment = ''
-
- return scheme + '://' + authority + path + query + fragment
diff --git a/askbot/deps/openid/yadis/__init__.py b/askbot/deps/openid/yadis/__init__.py
deleted file mode 100644
index cfa5f1e7..00000000
--- a/askbot/deps/openid/yadis/__init__.py
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-__all__ = [
- 'constants',
- 'discover',
- 'etxrd',
- 'filters',
- 'manager',
- 'parsehtml',
- 'services',
- 'xri',
- 'xrires',
- ]
-
-__version__ = '[library version:1.1.0-rc1]'[17:-1]
-
-# Parse the version info
-try:
- version_info = map(int, __version__.split('.'))
-except ValueError:
- version_info = (None, None, None)
-else:
- if len(version_info) != 3:
- version_info = (None, None, None)
- else:
- version_info = tuple(version_info)
diff --git a/askbot/deps/openid/yadis/accept.py b/askbot/deps/openid/yadis/accept.py
deleted file mode 100644
index d7508131..00000000
--- a/askbot/deps/openid/yadis/accept.py
+++ /dev/null
@@ -1,133 +0,0 @@
-"""Functions for generating and parsing HTTP Accept: headers for
-supporting server-directed content negotiation.
-"""
-
-def generateAcceptHeader(*elements):
- """Generate an accept header value
-
- [str or (str, float)] -> str
- """
- parts = []
- for element in elements:
- if type(element) is str:
- qs = "1.0"
- mtype = element
- else:
- mtype, q = element
- q = float(q)
- if q > 1 or q <= 0:
- raise ValueError('Invalid preference factor: %r' % q)
-
- qs = '%0.1f' % (q,)
-
- parts.append((qs, mtype))
-
- parts.sort()
- chunks = []
- for q, mtype in parts:
- if q == '1.0':
- chunks.append(mtype)
- else:
- chunks.append('%s; q=%s' % (mtype, q))
-
- return ', '.join(chunks)
-
-def parseAcceptHeader(value):
- """Parse an accept header, ignoring any accept-extensions
-
- returns a list of tuples containing main MIME type, MIME subtype,
- and quality markdown.
-
- str -> [(str, str, float)]
- """
- chunks = [chunk.strip() for chunk in value.split(',')]
- accept = []
- for chunk in chunks:
- parts = [s.strip() for s in chunk.split(';')]
-
- mtype = parts.pop(0)
- if '/' not in mtype:
- # This is not a MIME type, so ignore the bad data
- continue
-
- main, sub = mtype.split('/', 1)
-
- for ext in parts:
- if '=' in ext:
- k, v = ext.split('=', 1)
- if k == 'q':
- try:
- q = float(v)
- break
- except ValueError:
- # Ignore poorly formed q-values
- pass
- else:
- q = 1.0
-
- accept.append((q, main, sub))
-
- accept.sort()
- accept.reverse()
- return [(main, sub, q) for (q, main, sub) in accept]
-
-def matchTypes(accept_types, have_types):
- """Given the result of parsing an Accept: header, and the
- available MIME types, return the acceptable types with their
- quality markdowns.
-
- For example:
-
- >>> acceptable = parseAcceptHeader('text/html, text/plain; q=0.5')
- >>> matchTypes(acceptable, ['text/plain', 'text/html', 'image/jpeg'])
- [('text/html', 1.0), ('text/plain', 0.5)]
-
-
- Type signature: ([(str, str, float)], [str]) -> [(str, float)]
- """
- if not accept_types:
- # Accept all of them
- default = 1
- else:
- default = 0
-
- match_main = {}
- match_sub = {}
- for (main, sub, q) in accept_types:
- if main == '*':
- default = max(default, q)
- continue
- elif sub == '*':
- match_main[main] = max(match_main.get(main, 0), q)
- else:
- match_sub[(main, sub)] = max(match_sub.get((main, sub), 0), q)
-
- accepted_list = []
- order_maintainer = 0
- for mtype in have_types:
- main, sub = mtype.split('/')
- if (main, sub) in match_sub:
- q = match_sub[(main, sub)]
- else:
- q = match_main.get(main, default)
-
- if q:
- accepted_list.append((1 - q, order_maintainer, q, mtype))
- order_maintainer += 1
-
- accepted_list.sort()
- return [(mtype, q) for (_, _, q, mtype) in accepted_list]
-
-def getAcceptable(accept_header, have_types):
- """Parse the accept header and return a list of available types in
- preferred order. If a type is unacceptable, it will not be in the
- resulting list.
-
- This is a convenience wrapper around matchTypes and
- parseAcceptHeader.
-
- (str, [str]) -> [str]
- """
- accepted = parseAcceptHeader(accept_header)
- preferred = matchTypes(accepted, have_types)
- return [mtype for (mtype, _) in preferred]
diff --git a/askbot/deps/openid/yadis/constants.py b/askbot/deps/openid/yadis/constants.py
deleted file mode 100644
index 83765b02..00000000
--- a/askbot/deps/openid/yadis/constants.py
+++ /dev/null
@@ -1,13 +0,0 @@
-__all__ = ['YADIS_HEADER_NAME', 'YADIS_CONTENT_TYPE', 'YADIS_ACCEPT_HEADER']
-from askbot.deps.openid.yadis.accept import generateAcceptHeader
-
-YADIS_HEADER_NAME = 'X-XRDS-Location'
-YADIS_CONTENT_TYPE = 'application/xrds+xml'
-
-# A value suitable for using as an accept header when performing YADIS
-# discovery, unless the application has special requirements
-YADIS_ACCEPT_HEADER = generateAcceptHeader(
- ('text/html', 0.3),
- ('application/xhtml+xml', 0.5),
- (YADIS_CONTENT_TYPE, 1.0),
- )
diff --git a/askbot/deps/openid/yadis/discover.py b/askbot/deps/openid/yadis/discover.py
deleted file mode 100644
index 7e714fde..00000000
--- a/askbot/deps/openid/yadis/discover.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# -*- test-case-name: openid.test.test_yadis_discover -*-
-__all__ = ['discover', 'DiscoveryResult', 'DiscoveryFailure']
-
-from cStringIO import StringIO
-
-from askbot.deps.openid import fetchers
-
-from askbot.deps.openid.yadis.constants import \
- YADIS_HEADER_NAME, YADIS_CONTENT_TYPE, YADIS_ACCEPT_HEADER
-from askbot.deps.openid.yadis.parsehtml import MetaNotFound, findHTMLMeta
-
-class DiscoveryFailure(Exception):
- """Raised when a YADIS protocol error occurs in the discovery process"""
- identity_url = None
-
- def __init__(self, message, http_response):
- Exception.__init__(self, message)
- self.http_response = http_response
-
-class DiscoveryResult(object):
- """Contains the result of performing Yadis discovery on a URI"""
-
- # The URI that was passed to the fetcher
- request_uri = None
-
- # The result of following redirects from the request_uri
- normalized_uri = None
-
- # The URI from which the response text was returned (set to
- # None if there was no XRDS document found)
- xrds_uri = None
-
- # The content-type returned with the response_text
- content_type = None
-
- # The document returned from the xrds_uri
- response_text = None
-
- def __init__(self, request_uri):
- """Initialize the state of the object
-
- sets all attributes to None except the request_uri
- """
- self.request_uri = request_uri
-
- def usedYadisLocation(self):
- """Was the Yadis protocol's indirection used?"""
- return self.normalized_uri != self.xrds_uri
-
- def isXRDS(self):
- """Is the response text supposed to be an XRDS document?"""
- return (self.usedYadisLocation() or
- self.content_type == YADIS_CONTENT_TYPE)
-
-def discover(uri):
- """Discover services for a given URI.
-
- @param uri: The identity URI as a well-formed http or https
- URI. The well-formedness and the protocol are not checked, but
- the results of this function are undefined if those properties
- do not hold.
-
- @return: DiscoveryResult object
-
- @raises Exception: Any exception that can be raised by fetching a URL with
- the given fetcher.
- @raises DiscoveryFailure: When the HTTP response does not have a 200 code.
- """
- result = DiscoveryResult(uri)
- resp = fetchers.fetch(uri, headers={'Accept': YADIS_ACCEPT_HEADER})
- if resp.status not in (200, 206):
- raise DiscoveryFailure(
- 'HTTP Response status from identity URL host is not 200. '
- 'Got status %r' % (resp.status,), resp)
-
- # Note the URL after following redirects
- result.normalized_uri = resp.final_url
-
- # Attempt to find out where to go to discover the document
- # or if we already have it
- result.content_type = resp.headers.get('content-type')
-
- result.xrds_uri = whereIsYadis(resp)
-
- if result.xrds_uri and result.usedYadisLocation():
- resp = fetchers.fetch(result.xrds_uri)
- if resp.status not in (200, 206):
- exc = DiscoveryFailure(
- 'HTTP Response status from Yadis host is not 200. '
- 'Got status %r' % (resp.status,), resp)
- exc.identity_url = result.normalized_uri
- raise exc
- result.content_type = resp.headers.get('content-type')
-
- result.response_text = resp.body
- return result
-
-
-
-def whereIsYadis(resp):
- """Given a HTTPResponse, return the location of the Yadis document.
-
- May be the URL just retrieved, another URL, or None, if I can't
- find any.
-
- [non-blocking]
-
- @returns: str or None
- """
- # Attempt to find out where to go to discover the document
- # or if we already have it
- content_type = resp.headers.get('content-type')
-
- # According to the spec, the content-type header must be an exact
- # match, or else we have to look for an indirection.
- if (content_type and
- content_type.split(';', 1)[0].lower() == YADIS_CONTENT_TYPE):
- return resp.final_url
- else:
- # Try the header
- yadis_loc = resp.headers.get(YADIS_HEADER_NAME.lower())
-
- if not yadis_loc:
- # Parse as HTML if the header is missing.
- #
- # XXX: do we want to do something with content-type, like
- # have a whitelist or a blacklist (for detecting that it's
- # HTML)?
- try:
- yadis_loc = findHTMLMeta(StringIO(resp.body))
- except MetaNotFound:
- pass
-
- return yadis_loc
-
diff --git a/askbot/deps/openid/yadis/etxrd.py b/askbot/deps/openid/yadis/etxrd.py
deleted file mode 100644
index 7c921389..00000000
--- a/askbot/deps/openid/yadis/etxrd.py
+++ /dev/null
@@ -1,300 +0,0 @@
-# -*- test-case-name: yadis.test.test_etxrd -*-
-"""
-ElementTree interface to an XRD document.
-"""
-
-__all__ = [
- 'nsTag',
- 'mkXRDTag',
- 'isXRDS',
- 'parseXRDS',
- 'getCanonicalID',
- 'getYadisXRD',
- 'getPriorityStrict',
- 'getPriority',
- 'prioSort',
- 'iterServices',
- 'expandService',
- 'expandServices',
- ]
-
-import sys
-import random
-
-from datetime import datetime
-from time import strptime
-
-from askbot.deps.openid.oidutil import importElementTree
-ElementTree = importElementTree()
-
-# the different elementtree modules don't have a common exception
-# model. We just want to be able to catch the exceptions that signify
-# malformed XML data and wrap them, so that the other library code
-# doesn't have to know which XML library we're using.
-try:
- # Make the parser raise an exception so we can sniff out the type
- # of exceptions
- ElementTree.XML('> purposely malformed XML <')
-except (SystemExit, MemoryError, AssertionError, ImportError):
- raise
-except:
- XMLError = sys.exc_info()[0]
-
-from askbot.deps.openid.yadis import xri
-
-class XRDSError(Exception):
- """An error with the XRDS document."""
-
- # The exception that triggered this exception
- reason = None
-
-
-
-class XRDSFraud(XRDSError):
- """Raised when there's an assertion in the XRDS that it does not have
- the authority to make.
- """
-
-
-
-def parseXRDS(text):
- """Parse the given text as an XRDS document.
-
- @return: ElementTree containing an XRDS document
-
- @raises XRDSError: When there is a parse error or the document does
- not contain an XRDS.
- """
- try:
- element = ElementTree.XML(text)
- except XMLError, why:
- exc = XRDSError('Error parsing document as XML')
- exc.reason = why
- raise exc
- else:
- tree = ElementTree.ElementTree(element)
- if not isXRDS(tree):
- raise XRDSError('Not an XRDS document')
-
- return tree
-
-XRD_NS_2_0 = 'xri://$xrd*($v*2.0)'
-XRDS_NS = 'xri://$xrds'
-
-def nsTag(ns, t):
- return '{%s}%s' % (ns, t)
-
-def mkXRDTag(t):
- """basestring -> basestring
-
- Create a tag name in the XRD 2.0 XML namespace suitable for using
- with ElementTree
- """
- return nsTag(XRD_NS_2_0, t)
-
-def mkXRDSTag(t):
- """basestring -> basestring
-
- Create a tag name in the XRDS XML namespace suitable for using
- with ElementTree
- """
- return nsTag(XRDS_NS, t)
-
-# Tags that are used in Yadis documents
-root_tag = mkXRDSTag('XRDS')
-service_tag = mkXRDTag('Service')
-xrd_tag = mkXRDTag('XRD')
-type_tag = mkXRDTag('Type')
-uri_tag = mkXRDTag('URI')
-expires_tag = mkXRDTag('Expires')
-
-# Other XRD tags
-canonicalID_tag = mkXRDTag('CanonicalID')
-
-def isXRDS(xrd_tree):
- """Is this document an XRDS document?"""
- root = xrd_tree.getroot()
- return root.tag == root_tag
-
-def getYadisXRD(xrd_tree):
- """Return the XRD element that should contain the Yadis services"""
- xrd = None
-
- # for the side-effect of assigning the last one in the list to the
- # xrd variable
- for xrd in xrd_tree.findall(xrd_tag):
- pass
-
- # There were no elements found, or else xrd would be set to the
- # last one
- if xrd is None:
- raise XRDSError('No XRD present in tree')
-
- return xrd
-
-def getXRDExpiration(xrd_element, default=None):
- """Return the expiration date of this XRD element, or None if no
- expiration was specified.
-
- @type xrd_element: ElementTree node
-
- @param default: The value to use as the expiration if no
- expiration was specified in the XRD.
-
- @rtype: datetime.datetime
-
- @raises ValueError: If the xrd:Expires element is present, but its
- contents are not formatted according to the specification.
- """
- expires_element = xrd_element.find(expires_tag)
- if expires_element is None:
- return default
- else:
- expires_string = expires_element.text
-
- # Will raise ValueError if the string is not the expected format
- expires_time = strptime(expires_string, "%Y-%m-%dT%H:%M:%SZ")
- return datetime(*expires_time[0:6])
-
-def getCanonicalID(iname, xrd_tree):
- """Return the CanonicalID from this XRDS document.
-
- @param iname: the XRI being resolved.
- @type iname: unicode
-
- @param xrd_tree: The XRDS output from the resolver.
- @type xrd_tree: ElementTree
-
- @returns: The XRI CanonicalID or None.
- @returntype: unicode or None
- """
- xrd_list = xrd_tree.findall(xrd_tag)
- xrd_list.reverse()
-
- try:
- canonicalID = xri.XRI(xrd_list[0].findall(canonicalID_tag)[0].text)
- except IndexError:
- return None
-
- childID = canonicalID.lower()
-
- for xrd in xrd_list[1:]:
- # XXX: can't use rsplit until we require python >= 2.4.
- parent_sought = childID[:childID.rindex('!')]
- parent = xri.XRI(xrd.findtext(canonicalID_tag))
- if parent_sought != parent.lower():
- raise XRDSFraud("%r can not come from %s" % (childID, parent))
-
- childID = parent_sought
-
- root = xri.rootAuthority(iname)
- if not xri.providerIsAuthoritative(root, childID):
- raise XRDSFraud("%r can not come from root %r" % (childID, root))
-
- return canonicalID
-
-
-
-class _Max(object):
- """Value that compares greater than any other value.
-
- Should only be used as a singleton. Implemented for use as a
- priority value for when a priority is not specified."""
- def __cmp__(self, other):
- if other is self:
- return 0
-
- return 1
-
-Max = _Max()
-
-def getPriorityStrict(element):
- """Get the priority of this element.
-
- Raises ValueError if the value of the priority is invalid. If no
- priority is specified, it returns a value that compares greater
- than any other value.
- """
- prio_str = element.get('priority')
- if prio_str is not None:
- prio_val = int(prio_str)
- if prio_val >= 0:
- return prio_val
- else:
- raise ValueError('Priority values must be non-negative integers')
-
- # Any errors in parsing the priority fall through to here
- return Max
-
-def getPriority(element):
- """Get the priority of this element
-
- Returns Max if no priority is specified or the priority value is invalid.
- """
- try:
- return getPriorityStrict(element)
- except ValueError:
- return Max
-
-def prioSort(elements):
- """Sort a list of elements that have priority attributes"""
- # Randomize the services before sorting so that equal priority
- # elements are load-balanced.
- random.shuffle(elements)
-
- prio_elems = [(getPriority(e), e) for e in elements]
- prio_elems.sort()
- sorted_elems = [s for (_, s) in prio_elems]
- return sorted_elems
-
-def iterServices(xrd_tree):
- """Return an iterable over the Service elements in the Yadis XRD
-
- sorted by priority"""
- xrd = getYadisXRD(xrd_tree)
- return prioSort(xrd.findall(service_tag))
-
-def sortedURIs(service_element):
- """Given a Service element, return a list of the contents of all
- URI tags in priority order."""
- return [uri_element.text for uri_element
- in prioSort(service_element.findall(uri_tag))]
-
-def getTypeURIs(service_element):
- """Given a Service element, return a list of the contents of all
- Type tags"""
- return [type_element.text for type_element
- in service_element.findall(type_tag)]
-
-def expandService(service_element):
- """Take a service element and expand it into an iterator of:
- ([type_uri], uri, service_element)
- """
- uris = sortedURIs(service_element)
- if not uris:
- uris = [None]
-
- expanded = []
- for uri in uris:
- type_uris = getTypeURIs(service_element)
- expanded.append((type_uris, uri, service_element))
-
- return expanded
-
-def expandServices(service_elements):
- """Take a sorted iterator of service elements and expand it into a
- sorted iterator of:
- ([type_uri], uri, service_element)
-
- There may be more than one item in the resulting list for each
- service element if there is more than one URI or type for a
- service, but each triple will be unique.
-
- If there is no URI or Type for a Service element, it will not
- appear in the result.
- """
- expanded = []
- for service_element in service_elements:
- expanded.extend(expandService(service_element))
-
- return expanded
diff --git a/askbot/deps/openid/yadis/filters.py b/askbot/deps/openid/yadis/filters.py
deleted file mode 100644
index 0008fd2f..00000000
--- a/askbot/deps/openid/yadis/filters.py
+++ /dev/null
@@ -1,200 +0,0 @@
-"""This module contains functions and classes used for extracting
-endpoint information out of a Yadis XRD file using the ElementTree XML
-parser.
-"""
-
-__all__ = [
- 'BasicServiceEndpoint',
- 'mkFilter',
- 'IFilter',
- 'TransformFilterMaker',
- 'CompoundFilter',
- ]
-
-from askbot.deps.openid.yadis.etxrd import expandService
-
-class BasicServiceEndpoint(object):
- """Generic endpoint object that contains parsed service
- information, as well as a reference to the service element from
- which it was generated. If there is more than one xrd:Type or
- xrd:URI in the xrd:Service, this object represents just one of
- those pairs.
-
- This object can be used as a filter, because it implements
- fromBasicServiceEndpoint.
-
- The simplest kind of filter you can write implements
- fromBasicServiceEndpoint, which takes one of these objects.
- """
- def __init__(self, yadis_url, type_uris, uri, service_element):
- self.type_uris = type_uris
- self.yadis_url = yadis_url
- self.uri = uri
- self.service_element = service_element
-
- def matchTypes(self, type_uris):
- """Query this endpoint to see if it has any of the given type
- URIs. This is useful for implementing other endpoint classes
- that e.g. need to check for the presence of multiple versions
- of a single protocol.
-
- @param type_uris: The URIs that you wish to check
- @type type_uris: iterable of str
-
- @return: all types that are in both in type_uris and
- self.type_uris
- """
- return [uri for uri in type_uris if uri in self.type_uris]
-
- def fromBasicServiceEndpoint(endpoint):
- """Trivial transform from a basic endpoint to itself. This
- method exists to allow BasicServiceEndpoint to be used as a
- filter.
-
- If you are subclassing this object, re-implement this function.
-
- @param endpoint: An instance of BasicServiceEndpoint
- @return: The object that was passed in, with no processing.
- """
- return endpoint
-
- fromBasicServiceEndpoint = staticmethod(fromBasicServiceEndpoint)
-
-class IFilter(object):
- """Interface for Yadis filter objects. Other filter-like things
- are convertable to this class."""
-
- def getServiceEndpoints(self, yadis_url, service_element):
- """Returns an iterator of endpoint objects"""
- raise NotImplementedError
-
-class TransformFilterMaker(object):
- """Take a list of basic filters and makes a filter that transforms
- the basic filter into a top-level filter. This is mostly useful
- for the implementation of mkFilter, which should only be needed
- for special cases or internal use by this library.
-
- This object is useful for creating simple filters for services
- that use one URI and are specified by one Type (we expect most
- Types will fit this paradigm).
-
- Creates a BasicServiceEndpoint object and apply the filter
- functions to it until one of them returns a value.
- """
-
- def __init__(self, filter_functions):
- """Initialize the filter maker's state
-
- @param filter_functions: The endpoint transformer functions to
- apply to the basic endpoint. These are called in turn
- until one of them does not return None, and the result of
- that transformer is returned.
- """
- self.filter_functions = filter_functions
-
- def getServiceEndpoints(self, yadis_url, service_element):
- """Returns an iterator of endpoint objects produced by the
- filter functions."""
- endpoints = []
-
- # Do an expansion of the service element by xrd:Type and xrd:URI
- for type_uris, uri, _ in expandService(service_element):
-
- # Create a basic endpoint object to represent this
- # yadis_url, Service, Type, URI combination
- endpoint = BasicServiceEndpoint(
- yadis_url, type_uris, uri, service_element)
-
- e = self.applyFilters(endpoint)
- if e is not None:
- endpoints.append(e)
-
- return endpoints
-
- def applyFilters(self, endpoint):
- """Apply filter functions to an endpoint until one of them
- returns non-None."""
- for filter_function in self.filter_functions:
- e = filter_function(endpoint)
- if e is not None:
- # Once one of the filters has returned an
- # endpoint, do not apply any more.
- return e
-
- return None
-
-class CompoundFilter(object):
- """Create a new filter that applies a set of filters to an endpoint
- and collects their results.
- """
- def __init__(self, subfilters):
- self.subfilters = subfilters
-
- def getServiceEndpoints(self, yadis_url, service_element):
- """Generate all endpoint objects for all of the subfilters of
- this filter and return their concatenation."""
- endpoints = []
- for subfilter in self.subfilters:
- endpoints.extend(
- subfilter.getServiceEndpoints(yadis_url, service_element))
- return endpoints
-
-# Exception raised when something is not able to be turned into a filter
-filter_type_error = TypeError(
- 'Expected a filter, an endpoint, a callable or a list of any of these.')
-
-def mkFilter(parts):
- """Convert a filter-convertable thing into a filter
-
- @param parts: a filter, an endpoint, a callable, or a list of any of these.
- """
- # Convert the parts into a list, and pass to mkCompoundFilter
- if parts is None:
- parts = [BasicServiceEndpoint]
-
- try:
- parts = list(parts)
- except TypeError:
- return mkCompoundFilter([parts])
- else:
- return mkCompoundFilter(parts)
-
-def mkCompoundFilter(parts):
- """Create a filter out of a list of filter-like things
-
- Used by mkFilter
-
- @param parts: list of filter, endpoint, callable or list of any of these
- """
- # Separate into a list of callables and a list of filter objects
- transformers = []
- filters = []
- for subfilter in parts:
- try:
- subfilter = list(subfilter)
- except TypeError:
- # If it's not an iterable
- if hasattr(subfilter, 'getServiceEndpoints'):
- # It's a full filter
- filters.append(subfilter)
- elif hasattr(subfilter, 'fromBasicServiceEndpoint'):
- # It's an endpoint object, so put its endpoint
- # conversion attribute into the list of endpoint
- # transformers
- transformers.append(subfilter.fromBasicServiceEndpoint)
- elif callable(subfilter):
- # It's a simple callable, so add it to the list of
- # endpoint transformers
- transformers.append(subfilter)
- else:
- raise filter_type_error
- else:
- filters.append(mkCompoundFilter(subfilter))
-
- if transformers:
- filters.append(TransformFilterMaker(transformers))
-
- if len(filters) == 1:
- return filters[0]
- else:
- return CompoundFilter(filters)
diff --git a/askbot/deps/openid/yadis/manager.py b/askbot/deps/openid/yadis/manager.py
deleted file mode 100644
index 709adb7d..00000000
--- a/askbot/deps/openid/yadis/manager.py
+++ /dev/null
@@ -1,194 +0,0 @@
-class YadisServiceManager(object):
- """Holds the state of a list of selected Yadis services, managing
- storing it in a session and iterating over the services in order."""
-
- def __init__(self, starting_url, yadis_url, services, session_key):
- # The URL that was used to initiate the Yadis protocol
- self.starting_url = starting_url
-
- # The URL after following redirects (the identifier)
- self.yadis_url = yadis_url
-
- # List of service elements
- self.services = list(services)
-
- self.session_key = session_key
-
- # Reference to the current service object
- self._current = None
-
- def __len__(self):
- """How many untried services remain?"""
- return len(self.services)
-
- def __iter__(self):
- return self
-
- def next(self):
- """Return the next service
-
- self.current() will continue to return that service until the
- next call to this method."""
- try:
- self._current = self.services.pop(0)
- except IndexError:
- raise StopIteration
- else:
- return self._current
-
- def current(self):
- """Return the current service.
-
- Returns None if there are no services left.
- """
- return self._current
-
- def forURL(self, url):
- return url in [self.starting_url, self.yadis_url]
-
- def started(self):
- """Has the first service been returned?"""
- return self._current is not None
-
- def store(self, session):
- """Store this object in the session, by its session key."""
- session[self.session_key] = self
-
-class Discovery(object):
- """State management for discovery.
-
- High-level usage pattern is to call .getNextService(discover) in
- order to find the next available service for this user for this
- session. Once a request completes, call .finish() to clean up the
- session state.
-
- @ivar session: a dict-like object that stores state unique to the
- requesting user-agent. This object must be able to store
- serializable objects.
-
- @ivar url: the URL that is used to make the discovery request
-
- @ivar session_key_suffix: The suffix that will be used to identify
- this object in the session object.
- """
-
- DEFAULT_SUFFIX = 'auth'
- PREFIX = '_yadis_services_'
-
- def __init__(self, session, url, session_key_suffix=None):
- """Initialize a discovery object"""
- self.session = session
- self.url = url
- if session_key_suffix is None:
- session_key_suffix = self.DEFAULT_SUFFIX
-
- self.session_key_suffix = session_key_suffix
-
- def getNextService(self, discover):
- """Return the next authentication service for the pair of
- user_input and session. This function handles fallback.
-
-
- @param discover: a callable that takes a URL and returns a
- list of services
-
- @type discover: str -> [service]
-
-
- @return: the next available service
- """
- manager = self.getManager()
- if manager is not None and not manager:
- self.destroyManager()
-
- if not manager:
- yadis_url, services = discover(self.url)
- manager = self.createManager(services, yadis_url)
-
- if manager:
- service = manager.next()
- manager.store(self.session)
- else:
- service = None
-
- return service
-
- def cleanup(self, force=False):
- """Clean up Yadis-related services in the session and return
- the most-recently-attempted service from the manager, if one
- exists.
-
- @param force: True if the manager should be deleted regardless
- of whether it's a manager for self.url.
-
- @return: current service endpoint object or None if there is
- no current service
- """
- manager = self.getManager(force=force)
- if manager is not None:
- service = manager.current()
- self.destroyManager(force=force)
- else:
- service = None
-
- return service
-
- ### Lower-level methods
-
- def getSessionKey(self):
- """Get the session key for this starting URL and suffix
-
- @return: The session key
- @rtype: str
- """
- return self.PREFIX + self.session_key_suffix
-
- def getManager(self, force=False):
- """Extract the YadisServiceManager for this object's URL and
- suffix from the session.
-
- @param force: True if the manager should be returned
- regardless of whether it's a manager for self.url.
-
- @return: The current YadisServiceManager, if it's for this
- URL, or else None
- """
- manager = self.session.get(self.getSessionKey())
- if (manager is not None and (manager.forURL(self.url) or force)):
- return manager
- else:
- return None
-
- def createManager(self, services, yadis_url=None):
- """Create a new YadisService Manager for this starting URL and
- suffix, and store it in the session.
-
- @raises KeyError: When I already have a manager.
-
- @return: A new YadisServiceManager or None
- """
- key = self.getSessionKey()
- if self.getManager():
- raise KeyError('There is already a %r manager for %r' %
- (key, self.url))
-
- if not services:
- return None
-
- manager = YadisServiceManager(self.url, yadis_url, services, key)
- manager.store(self.session)
- return manager
-
- def destroyManager(self, force=False):
- """Delete any YadisServiceManager with this starting URL and
- suffix from the session.
-
- If there is no service manager or the service manager is for a
- different URL, it silently does nothing.
-
- @param force: True if the manager should be deleted regardless
- of whether it's a manager for self.url.
- """
- if self.getManager(force=force) is not None:
- key = self.getSessionKey()
- del self.session[key]
diff --git a/askbot/deps/openid/yadis/parsehtml.py b/askbot/deps/openid/yadis/parsehtml.py
deleted file mode 100644
index 948fef86..00000000
--- a/askbot/deps/openid/yadis/parsehtml.py
+++ /dev/null
@@ -1,197 +0,0 @@
-__all__ = ['findHTMLMeta', 'MetaNotFound']
-
-from HTMLParser import HTMLParser, HTMLParseError
-import htmlentitydefs
-import re
-
-from askbot.deps.openid.yadis.constants import YADIS_HEADER_NAME
-
-# Size of the chunks to search at a time (also the amount that gets
-# read at a time)
-CHUNK_SIZE = 1024 * 16 # 16 KB
-
-class ParseDone(Exception):
- """Exception to hold the URI that was located when the parse is
- finished. If the parse finishes without finding the URI, set it to
- None."""
-
-class MetaNotFound(Exception):
- """Exception to hold the content of the page if we did not find
- the appropriate <meta> tag"""
-
-re_flags = re.IGNORECASE | re.UNICODE | re.VERBOSE
-ent_pat = r'''
-&
-
-(?: \#x (?P<hex> [a-f0-9]+ )
-| \# (?P<dec> \d+ )
-| (?P<word> \w+ )
-)
-
-;'''
-
-ent_re = re.compile(ent_pat, re_flags)
-
-def substituteMO(mo):
- if mo.lastgroup == 'hex':
- codepoint = int(mo.group('hex'), 16)
- elif mo.lastgroup == 'dec':
- codepoint = int(mo.group('dec'))
- else:
- assert mo.lastgroup == 'word'
- codepoint = htmlentitydefs.name2codepoint.get(mo.group('word'))
-
- if codepoint is None:
- return mo.group()
- else:
- return unichr(codepoint)
-
-def substituteEntities(s):
- return ent_re.sub(substituteMO, s)
-
-class YadisHTMLParser(HTMLParser):
- """Parser that finds a meta http-equiv tag in the head of a html
- document.
-
- When feeding in data, if the tag is matched or it will never be
- found, the parser will raise ParseDone with the uri as the first
- attribute.
-
- Parsing state diagram
- =====================
-
- Any unlisted input does not affect the state::
-
- 1, 2, 5 8
- +--------------------------+ +-+
- | | | |
- 4 | 3 1, 2, 5, 7 v | v
- TOP -> HTML -> HEAD ----------> TERMINATED
- | | ^ | ^ ^
- | | 3 | | | |
- | +------------+ +-> FOUND ------+ |
- | 6 8 |
- | 1, 2 |
- +------------------------------------+
-
- 1. any of </body>, </html>, </head> -> TERMINATE
- 2. <body> -> TERMINATE
- 3. <head> -> HEAD
- 4. <html> -> HTML
- 5. <html> -> TERMINATE
- 6. <meta http-equiv='X-XRDS-Location'> -> FOUND
- 7. <head> -> TERMINATE
- 8. Any input -> TERMINATE
- """
- TOP = 0
- HTML = 1
- HEAD = 2
- FOUND = 3
- TERMINATED = 4
-
- def __init__(self):
- HTMLParser.__init__(self)
- self.phase = self.TOP
-
- def _terminate(self):
- self.phase = self.TERMINATED
- raise ParseDone(None)
-
- def handle_endtag(self, tag):
- # If we ever see an end of head, body, or html, bail out right away.
- # [1]
- if tag in ['head', 'body', 'html']:
- self._terminate()
-
- def handle_starttag(self, tag, attrs):
- # if we ever see a start body tag, bail out right away, since
- # we want to prevent the meta tag from appearing in the body
- # [2]
- if tag=='body':
- self._terminate()
-
- if self.phase == self.TOP:
- # At the top level, allow a html tag or a head tag to move
- # to the head or html phase
- if tag == 'head':
- # [3]
- self.phase = self.HEAD
- elif tag == 'html':
- # [4]
- self.phase = self.HTML
-
- elif self.phase == self.HTML:
- # if we are in the html tag, allow a head tag to move to
- # the HEAD phase. If we get another html tag, then bail
- # out
- if tag == 'head':
- # [3]
- self.phase = self.HEAD
- elif tag == 'html':
- # [5]
- self._terminate()
-
- elif self.phase == self.HEAD:
- # If we are in the head phase, look for the appropriate
- # meta tag. If we get a head or body tag, bail out.
- if tag == 'meta':
- attrs_d = dict(attrs)
- http_equiv = attrs_d.get('http-equiv', '').lower()
- if http_equiv == YADIS_HEADER_NAME.lower():
- raw_attr = attrs_d.get('content')
- yadis_loc = substituteEntities(raw_attr)
- # [6]
- self.phase = self.FOUND
- raise ParseDone(yadis_loc)
-
- elif tag in ['head', 'html']:
- # [5], [7]
- self._terminate()
-
- def feed(self, chars):
- # [8]
- if self.phase in [self.TERMINATED, self.FOUND]:
- self._terminate()
-
- return HTMLParser.feed(self, chars)
-
-def findHTMLMeta(stream):
- """Look for a meta http-equiv tag with the YADIS header name.
-
- @param stream: Source of the html text
- @type stream: Object that implements a read() method that works
- like file.read
-
- @return: The URI from which to fetch the XRDS document
- @rtype: str
-
- @raises MetaNotFound: raised with the content that was
- searched as the first parameter.
- """
- parser = YadisHTMLParser()
- chunks = []
-
- while 1:
- chunk = stream.read(CHUNK_SIZE)
- if not chunk:
- # End of file
- break
-
- chunks.append(chunk)
- try:
- parser.feed(chunk)
- except HTMLParseError, why:
- # HTML parse error, so bail
- chunks.append(stream.read())
- break
- except ParseDone, why:
- uri = why[0]
- if uri is None:
- # Parse finished, but we may need the rest of the file
- chunks.append(stream.read())
- break
- else:
- return uri
-
- content = ''.join(chunks)
- raise MetaNotFound(content)
diff --git a/askbot/deps/openid/yadis/services.py b/askbot/deps/openid/yadis/services.py
deleted file mode 100644
index dad230c1..00000000
--- a/askbot/deps/openid/yadis/services.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- test-case-name: openid.test.test_services -*-
-
-from askbot.deps.openid.yadis.filters import mkFilter
-from askbot.deps.openid.yadis.discover import discover, DiscoveryFailure
-from askbot.deps.openid.yadis.etxrd import parseXRDS, iterServices, XRDSError
-
-def getServiceEndpoints(input_url, flt=None):
- """Perform the Yadis protocol on the input URL and return an
- iterable of resulting endpoint objects.
-
- @param flt: A filter object or something that is convertable to
- a filter object (using mkFilter) that will be used to generate
- endpoint objects. This defaults to generating BasicEndpoint
- objects.
-
- @param input_url: The URL on which to perform the Yadis protocol
-
- @return: The normalized identity URL and an iterable of endpoint
- objects generated by the filter function.
-
- @rtype: (str, [endpoint])
-
- @raises DiscoveryFailure: when Yadis fails to obtain an XRDS document.
- """
- result = discover(input_url)
- try:
- endpoints = applyFilter(result.normalized_uri,
- result.response_text, flt)
- except XRDSError, err:
- raise DiscoveryFailure(str(err), None)
- return (result.normalized_uri, endpoints)
-
-def applyFilter(normalized_uri, xrd_data, flt=None):
- """Generate an iterable of endpoint objects given this input data,
- presumably from the result of performing the Yadis protocol.
-
- @param normalized_uri: The input URL, after following redirects,
- as in the Yadis protocol.
-
-
- @param xrd_data: The XML text the XRDS file fetched from the
- normalized URI.
- @type xrd_data: str
-
- """
- flt = mkFilter(flt)
- et = parseXRDS(xrd_data)
-
- endpoints = []
- for service_element in iterServices(et):
- endpoints.extend(
- flt.getServiceEndpoints(normalized_uri, service_element))
-
- return endpoints
diff --git a/askbot/deps/openid/yadis/xri.py b/askbot/deps/openid/yadis/xri.py
deleted file mode 100644
index 3a39a6b8..00000000
--- a/askbot/deps/openid/yadis/xri.py
+++ /dev/null
@@ -1,168 +0,0 @@
-# -*- test-case-name: openid.test.test_xri -*-
-"""Utility functions for handling XRIs.
-
-@see: XRI Syntax v2.0 at the U{OASIS XRI Technical Committee<http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xri>}
-"""
-
-import re
-
-XRI_AUTHORITIES = ['!', '=', '@', '+', '$', '(']
-
-try:
- unichr(0x10000)
-except ValueError:
- # narrow python build
- UCSCHAR = [
- (0xA0, 0xD7FF),
- (0xF900, 0xFDCF),
- (0xFDF0, 0xFFEF),
- ]
-
- IPRIVATE = [
- (0xE000, 0xF8FF),
- ]
-else:
- UCSCHAR = [
- (0xA0, 0xD7FF),
- (0xF900, 0xFDCF),
- (0xFDF0, 0xFFEF),
- (0x10000, 0x1FFFD),
- (0x20000, 0x2FFFD),
- (0x30000, 0x3FFFD),
- (0x40000, 0x4FFFD),
- (0x50000, 0x5FFFD),
- (0x60000, 0x6FFFD),
- (0x70000, 0x7FFFD),
- (0x80000, 0x8FFFD),
- (0x90000, 0x9FFFD),
- (0xA0000, 0xAFFFD),
- (0xB0000, 0xBFFFD),
- (0xC0000, 0xCFFFD),
- (0xD0000, 0xDFFFD),
- (0xE1000, 0xEFFFD),
- ]
-
- IPRIVATE = [
- (0xE000, 0xF8FF),
- (0xF0000, 0xFFFFD),
- (0x100000, 0x10FFFD),
- ]
-
-
-_escapeme_re = re.compile('[%s]' % (''.join(
- map(lambda (m, n): u'%s-%s' % (unichr(m), unichr(n)),
- UCSCHAR + IPRIVATE)),))
-
-
-def identifierScheme(identifier):
- """Determine if this identifier is an XRI or URI.
-
- @returns: C{"XRI"} or C{"URI"}
- """
- if identifier.startswith('xri://') or (
- identifier and identifier[0] in XRI_AUTHORITIES):
- return "XRI"
- else:
- return "URI"
-
-
-def toIRINormal(xri):
- """Transform an XRI to IRI-normal form."""
- if not xri.startswith('xri://'):
- xri = 'xri://' + xri
- return escapeForIRI(xri)
-
-
-_xref_re = re.compile('\((.*?)\)')
-
-
-def _escape_xref(xref_match):
- """Escape things that need to be escaped if they're in a cross-reference.
- """
- xref = xref_match.group()
- xref = xref.replace('/', '%2F')
- xref = xref.replace('?', '%3F')
- xref = xref.replace('#', '%23')
- return xref
-
-
-def escapeForIRI(xri):
- """Escape things that need to be escaped when transforming to an IRI."""
- xri = xri.replace('%', '%25')
- xri = _xref_re.sub(_escape_xref, xri)
- return xri
-
-
-def toURINormal(xri):
- """Transform an XRI to URI normal form."""
- return iriToURI(toIRINormal(xri))
-
-
-def _percentEscapeUnicode(char_match):
- c = char_match.group()
- return ''.join(['%%%X' % (ord(octet),) for octet in c.encode('utf-8')])
-
-
-def iriToURI(iri):
- """Transform an IRI to a URI by escaping unicode."""
- # According to RFC 3987, section 3.1, "Mapping of IRIs to URIs"
- return _escapeme_re.sub(_percentEscapeUnicode, iri)
-
-
-def providerIsAuthoritative(providerID, canonicalID):
- """Is this provider ID authoritative for this XRI?
-
- @returntype: bool
- """
- # XXX: can't use rsplit until we require python >= 2.4.
- lastbang = canonicalID.rindex('!')
- parent = canonicalID[:lastbang]
- return parent == providerID
-
-
-def rootAuthority(xri):
- """Return the root authority for an XRI.
-
- Example::
-
- rootAuthority("xri://@example") == "xri://@"
-
- @type xri: unicode
- @returntype: unicode
- """
- if xri.startswith('xri://'):
- xri = xri[6:]
- authority = xri.split('/', 1)[0]
- if authority[0] == '(':
- # Cross-reference.
- # XXX: This is incorrect if someone nests cross-references so there
- # is another close-paren in there. Hopefully nobody does that
- # before we have a real xriparse function. Hopefully nobody does
- # that *ever*.
- root = authority[:authority.index(')') + 1]
- elif authority[0] in XRI_AUTHORITIES:
- # Other XRI reference.
- root = authority[0]
- else:
- # IRI reference. XXX: Can IRI authorities have segments?
- segments = authority.split('!')
- segments = reduce(list.__add__,
- map(lambda s: s.split('*'), segments))
- root = segments[0]
-
- return XRI(root)
-
-
-def XRI(xri):
- """An XRI object allowing comparison of XRI.
-
- Ideally, this would do full normalization and provide comparsion
- operators as per XRI Syntax. Right now, it just does a bit of
- canonicalization by ensuring the xri scheme is present.
-
- @param xri: an xri string
- @type xri: unicode
- """
- if not xri.startswith('xri://'):
- xri = 'xri://' + xri
- return xri
diff --git a/askbot/deps/openid/yadis/xrires.py b/askbot/deps/openid/yadis/xrires.py
deleted file mode 100644
index 33cc6d65..00000000
--- a/askbot/deps/openid/yadis/xrires.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# -*- test-case-name: openid.test.test_xrires -*-
-"""XRI resolution.
-"""
-
-from urllib import urlencode
-from askbot.deps.openid import fetchers
-from askbot.deps.openid.yadis import etxrd
-from askbot.deps.openid.yadis.xri import toURINormal
-from askbot.deps.openid.yadis.services import iterServices
-
-DEFAULT_PROXY = 'http://proxy.xri.net/'
-
-class ProxyResolver(object):
- """Python interface to a remote XRI proxy resolver.
- """
- def __init__(self, proxy_url=DEFAULT_PROXY):
- self.proxy_url = proxy_url
-
-
- def queryURL(self, xri, service_type=None):
- """Build a URL to query the proxy resolver.
-
- @param xri: An XRI to resolve.
- @type xri: unicode
-
- @param service_type: The service type to resolve, if you desire
- service endpoint selection. A service type is a URI.
- @type service_type: str
-
- @returns: a URL
- @returntype: str
- """
- # Trim off the xri:// prefix. The proxy resolver didn't accept it
- # when this code was written, but that may (or may not) change for
- # XRI Resolution 2.0 Working Draft 11.
- qxri = toURINormal(xri)[6:]
- hxri = self.proxy_url + qxri
- args = {
- # XXX: If the proxy resolver will ensure that it doesn't return
- # bogus CanonicalIDs (as per Steve's message of 15 Aug 2006
- # 11:13:42), then we could ask for application/xrd+xml instead,
- # which would give us a bit less to process.
- '_xrd_r': 'application/xrds+xml',
- }
- if service_type:
- args['_xrd_t'] = service_type
- else:
- # Don't perform service endpoint selection.
- args['_xrd_r'] += ';sep=false'
- query = _appendArgs(hxri, args)
- return query
-
-
- def query(self, xri, service_types):
- """Resolve some services for an XRI.
-
- Note: I don't implement any service endpoint selection beyond what
- the resolver I'm querying does, so the Services I return may well
- include Services that were not of the types you asked for.
-
- May raise fetchers.HTTPFetchingError or L{etxrd.XRDSError} if
- the fetching or parsing don't go so well.
-
- @param xri: An XRI to resolve.
- @type xri: unicode
-
- @param service_types: A list of services types to query for. Service
- types are URIs.
- @type service_types: list of str
-
- @returns: tuple of (CanonicalID, Service elements)
- @returntype: (unicode, list of C{ElementTree.Element}s)
- """
- # FIXME: No test coverage!
- services = []
- # Make a seperate request to the proxy resolver for each service
- # type, as, if it is following Refs, it could return a different
- # XRDS for each.
-
- canonicalID = None
-
- for service_type in service_types:
- url = self.queryURL(xri, service_type)
- response = fetchers.fetch(url)
- if response.status not in (200, 206):
- # XXX: sucks to fail silently.
- # print "response not OK:", response
- continue
- et = etxrd.parseXRDS(response.body)
- canonicalID = etxrd.getCanonicalID(xri, et)
- some_services = list(iterServices(et))
- services.extend(some_services)
- # TODO:
- # * If we do get hits for multiple service_types, we're almost
- # certainly going to have duplicated service entries and
- # broken priority ordering.
- return canonicalID, services
-
-
-def _appendArgs(url, args):
- """Append some arguments to an HTTP query.
- """
- # to be merged with oidutil.appendArgs when we combine the projects.
- if hasattr(args, 'items'):
- args = args.items()
- args.sort()
-
- if len(args) == 0:
- return url
-
- # According to XRI Resolution section "QXRI query parameters":
- #
- # """If the original QXRI had a null query component (only a leading
- # question mark), or a query component consisting of only question
- # marks, one additional leading question mark MUST be added when
- # adding any XRI resolution parameters."""
-
- if '?' in url.rstrip('?'):
- sep = '&'
- else:
- sep = '?'
-
- return '%s%s%s' % (url, sep, urlencode(args))
diff --git a/setup.py b/setup.py
index aee12c28..ddfe917d 100644
--- a/setup.py
+++ b/setup.py
@@ -23,6 +23,7 @@ install_requires = [
'django-celery==2.2.3',
'django-kombu==0.9.2',
'django-followit',
+ 'python-openid',
]
#todo: have a dirty version retriever that