├── examples
├── __init__.py
├── djopenid
│ ├── __init__.py
│ ├── consumer
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── urls.py
│ │ └── tests.py
│ ├── server
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── urls.py
│ │ └── tests.py
│ ├── templates
│ │ ├── consumer
│ │ │ ├── request_form.html
│ │ │ └── index.html
│ │ ├── server
│ │ │ ├── endpoint.html
│ │ │ ├── idPage.html
│ │ │ ├── pape_request_info.html
│ │ │ ├── index.html
│ │ │ └── trust.html
│ │ ├── xrds.xml
│ │ └── index.html
│ ├── urls.py
│ ├── manage.py
│ ├── settings.py
│ ├── README
│ └── util.py
├── discover
└── README
├── MANIFEST.in
├── openid
├── extensions
│ ├── draft
│ │ ├── __init__.py
│ │ └── pape5.py
│ └── __init__.py
├── test
│ ├── data
│ │ ├── test_etxrd
│ │ │ ├── not-xrds.xml
│ │ │ ├── no-xrd.xml
│ │ │ ├── status222.xrds
│ │ │ ├── README
│ │ │ ├── spoof1.xrds
│ │ │ ├── spoof2.xrds
│ │ │ ├── spoof3.xrds
│ │ │ ├── delegated-20060809.xrds
│ │ │ ├── valid-populated-xrds.xml
│ │ │ ├── delegated-20060809-r1.xrds
│ │ │ ├── delegated-20060809-r2.xrds
│ │ │ ├── prefixsometimes.xrds
│ │ │ ├── sometimesprefix.xrds
│ │ │ ├── subsegments.xrds
│ │ │ └── ref.xrds
│ │ ├── test_discover
│ │ │ ├── unicode2.html
│ │ │ ├── unicode3.html
│ │ │ ├── yadis_no_delegate.xml
│ │ │ ├── openid_no_delegate.html
│ │ │ ├── openid2_xrds_no_local_id.xml
│ │ │ ├── unicode.html
│ │ │ ├── yadis_0entries.xml
│ │ │ ├── openid2_xrds.xml
│ │ │ ├── yadis_idp.xml
│ │ │ ├── openid.html
│ │ │ ├── openid2.html
│ │ │ ├── openid_1_and_2.html
│ │ │ ├── yadis_idp_delegate.xml
│ │ │ ├── yadis_another_delegate.xml
│ │ │ ├── openid_and_yadis.html
│ │ │ ├── yadis_2_bad_local_id.xml
│ │ │ ├── openid_1_and_2_xrds.xml
│ │ │ ├── openid_1_and_2_xrds_bad_delegate.xml
│ │ │ ├── yadis_2entries_idp.xml
│ │ │ └── yadis_2entries_delegate.xml
│ │ ├── openid-1.2-consumer-sqlitestore.db
│ │ ├── example-xrds.xml
│ │ ├── test1-discover.txt
│ │ └── accept.txt
│ ├── __init__.py
│ ├── test_pape_draft5.py
│ ├── test_htmldiscover.py
│ ├── test_services.py
│ ├── utils.py
│ ├── test_symbol.py
│ ├── test_extension.py
│ ├── test_xrires.py
│ ├── test_trustroot.py
│ ├── test_nonce.py
│ ├── test_accept.py
│ ├── test_xri.py
│ ├── test_cryptutil.py
│ ├── discoverdata.py
│ ├── test_urinorm.py
│ ├── test_kvform.py
│ ├── test_yadis_discover.py
│ ├── test_openidyadis.py
│ └── test_parsehtml.py
├── consumer
│ └── __init__.py
├── server
│ └── __init__.py
├── store
│ ├── __init__.py
│ ├── nonce.py
│ └── memstore.py
├── sreg.py
├── constants.py
├── yadis
│ ├── constants.py
│ ├── __init__.py
│ ├── parsehtml.py
│ ├── services.py
│ ├── xri.py
│ ├── xrires.py
│ ├── accept.py
│ └── discover.py
├── __init__.py
├── extension.py
├── cryptutil.py
├── kvform.py
├── urinorm.py
└── oidutil.py
├── .gitattributes
├── admin
├── makechangelog
├── fixperms
├── pythonsource
├── makedoc
├── tagrelease
├── gettlds.py
└── builddiscover.py
├── .gitignore
├── setup.cfg
├── .bumpversion.cfg
├── .travis.yml
├── Makefile
├── tox.ini
├── CHANGES-2.2.0
├── README.md
├── setup.py
├── Changelog.md
├── background-associations.txt
└── contrib
└── openid-parse
/examples/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include *.md
2 |
--------------------------------------------------------------------------------
/examples/djopenid/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/djopenid/consumer/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/djopenid/server/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/openid/extensions/draft/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | /Makefile whitespace=space-before-tab,indent-with-non-tab,tabwidth=4
2 |
--------------------------------------------------------------------------------
/admin/makechangelog:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | darcs changes --from-tag '^release-' --summary > CHANGELOG
3 |
--------------------------------------------------------------------------------
/openid/test/data/test_etxrd/not-xrds.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 | {{ error|escape }} 11 |
12 | {% endif %} 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /openid/test/data/test_discover/yadis_no_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 |foo
9 | 10 | 11 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [isort] 2 | line_length = 120 3 | combine_as_imports = true 4 | default_section = THIRDPARTY 5 | known_first_party = openid 6 | add_imports = from __future__ import unicode_literals 7 | 8 | [flake8] 9 | max-line-length = 120 10 | # Ignore E123 - enforce hang-closing instead 11 | ignore = E123,W503 12 | max-complexity = 24 13 | 14 | [sdist] 15 | force_manifest=1 16 | formats=gztar,zip 17 | -------------------------------------------------------------------------------- /examples/djopenid/consumer/urls.py: -------------------------------------------------------------------------------- 1 | """Consumer URLs.""" 2 | from __future__ import unicode_literals 3 | 4 | from django.conf.urls import url 5 | 6 | from djopenid.consumer.views import finishOpenID, rpXRDS, startOpenID 7 | 8 | urlpatterns = [ 9 | url(r'^$', startOpenID, name='index'), 10 | url(r'^finish/$', finishOpenID, name='return_to'), 11 | url(r'^xrds/$', rpXRDS, name='xrds'), 12 | ] 13 | -------------------------------------------------------------------------------- /openid/test/data/test_discover/openid2_xrds_no_local_id.xml: -------------------------------------------------------------------------------- 1 | 2 |This page can be properly decoded and everything will will be fine
8 | 9 | 10 | -------------------------------------------------------------------------------- /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 3.2 3 | commit = True 4 | tag = True 5 | tag_name = {new_version} 6 | parse = (?Pfoo
10 | 11 | 12 | -------------------------------------------------------------------------------- /openid/test/data/test_discover/openid2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |foo
10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/djopenid/templates/xrds.xml: -------------------------------------------------------------------------------- 1 | 2 |foo
10 | 11 | 12 | -------------------------------------------------------------------------------- /admin/tagrelease: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | VERSION="$1" 3 | VERSION_PATTERN='^[0-9]\+\.[0-9]\+\.[0-9]\+\(-[a-z0-9-]\+\)\?$' 4 | 5 | echo "$VERSION" | grep -e "$VERSION_PATTERN" 2>&1 >/dev/null || { 6 | echo "$VERSION" 7 | echo "Malformed version number. Expected X.X.X or X.X.X-name." 1>&2 8 | exit 1 9 | } 10 | 11 | cd $(dirname $(dirname $(readlink --canonicalize "$0"))) 12 | ./admin/setversion "$VERSION" 13 | darcs record -m 'Set version number to '"$VERSION" && darcs tag "release-$VERSION" 14 | -------------------------------------------------------------------------------- /openid/constants.py: -------------------------------------------------------------------------------- 1 | """Basic constants for openid library.""" 2 | from __future__ import unicode_literals 3 | 4 | # Default Diffie-Hellman modulus and generator. 5 | # Defined in OpenID specification http://openid.net/specs/openid-authentication-2_0.html#pvalue 6 | DEFAULT_DH_MODULUS = ('ANz5OguIOXLsDhmYmsWizjEOHTdxfo2Vcbt2I3MYZuYe91ouJ4mLBX+YkcLiemOcPym2CBRYHNOyyjmG0mg3BVd9RcLn5S3I' 7 | 'HHoXGHblzqdLFEi/368Ygo79JRnxTkXjgmY0rxlJ5bU1zIKaSDuKdiI+XUkKJX8Fvf8W8vsixYOr') 8 | DEFAULT_DH_GENERATOR = 'Ag==' 9 | -------------------------------------------------------------------------------- /openid/test/data/test_discover/yadis_idp_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 |12 | This is the identity page for the OpenID that this server serves. 13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /openid/test/data/test_discover/yadis_another_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 |foo
11 | 12 | 13 | -------------------------------------------------------------------------------- /openid/test/data/test_discover/yadis_2_bad_local_id.xml: -------------------------------------------------------------------------------- 1 | 2 |7 | This is a Django package which implements both an OpenID server 8 | and an OpenID consumer. These examples are provided with the 9 | OpenID library so you can learn how to use it in your own 10 | applications. 11 |
12 | 13 |14 | To begin, click one of these links: 15 |
16 | 17 | 21 | 22 |23 | Note: If you want to test the example consumer 24 | using the example server, you must start a separate server process 25 | for each application. 26 |
27 | 28 | 29 | -------------------------------------------------------------------------------- /openid/test/utils.py: -------------------------------------------------------------------------------- 1 | """Test utilities.""" 2 | from __future__ import unicode_literals 3 | 4 | from openid import message 5 | 6 | 7 | class OpenIDTestMixin(object): 8 | """Mixin providing custom asserts.""" 9 | 10 | def assertOpenIDValueEqual(self, msg, key, expected, ns=None): 11 | """Check OpenID message contains key with expected value.""" 12 | if ns is None: 13 | ns = message.OPENID_NS 14 | 15 | actual = msg.getArg(ns, key) 16 | error_format = 'Wrong value for openid.%s: expected=%s, actual=%s' 17 | error_message = error_format % (key, expected, actual) 18 | self.assertEqual(actual, expected, error_message) 19 | 20 | def assertOpenIDKeyMissing(self, msg, key, ns=None): 21 | if ns is None: 22 | ns = message.OPENID_NS 23 | 24 | error_message = 'openid.%s unexpectedly present' % key 25 | self.assertFalse(msg.hasKey(ns, key), error_message) 26 | -------------------------------------------------------------------------------- /examples/djopenid/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import unicode_literals 3 | 4 | import os 5 | import sys 6 | 7 | if __name__ == "__main__": 8 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djopenid.settings") 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError: 12 | # The above import may fail for some other reason. Ensure that the 13 | # issue is really that Django is missing to avoid masking other 14 | # exceptions on Python 2. 15 | try: 16 | import django # noqa: F401 17 | except ImportError: 18 | raise ImportError( 19 | "Couldn't import Django. Are you sure it's installed and " 20 | "available on your PYTHONPATH environment variable? Did you " 21 | "forget to activate a virtual environment?" 22 | ) 23 | raise 24 | execute_from_command_line(sys.argv) 25 | -------------------------------------------------------------------------------- /openid/test/test_symbol.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | import unittest 4 | 5 | from openid import oidutil 6 | 7 | 8 | class SymbolTest(unittest.TestCase): 9 | def test_selfEquality(self): 10 | s = oidutil.Symbol('xxx') 11 | self.assertEqual(s, s) 12 | 13 | def test_otherEquality(self): 14 | x = oidutil.Symbol('xxx') 15 | y = oidutil.Symbol('xxx') 16 | self.assertEqual(x, y) 17 | 18 | def test_inequality(self): 19 | x = oidutil.Symbol('xxx') 20 | y = oidutil.Symbol('yyy') 21 | self.assertNotEqual(x, y) 22 | 23 | def test_selfInequality(self): 24 | x = oidutil.Symbol('xxx') 25 | self.assertFalse(x != x) 26 | 27 | def test_otherInequality(self): 28 | x = oidutil.Symbol('xxx') 29 | y = oidutil.Symbol('xxx') 30 | self.assertFalse(x != y) 31 | 32 | def test_ne_inequality(self): 33 | x = oidutil.Symbol('xxx') 34 | y = oidutil.Symbol('yyy') 35 | self.assertNotEqual(x, y) 36 | 37 | 38 | if __name__ == '__main__': 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /openid/test/data/test_etxrd/spoof3.xrds: -------------------------------------------------------------------------------- 1 | 2 |39 | This is an example server built for the Django framework. It only 40 | authenticates one OpenID, which is also served by this 41 | application. The OpenID it serves is 42 | 43 |
44 | {{ local_id }} 45 |46 | 47 | 48 |
The site {{ trust_root|escape }} has requested verification 8 | of your OpenID.
9 | 10 | {% include "server/pape_request_info.html" %} 11 | {% endifequal %} 12 | {% ifequal trust_root_valid "Invalid" %} 13 |This request claims to be from {{ trust_root|escape }} but I have 15 | determined that it is a pack of lies. Beware, if you release 16 | information to them, they are likely to do unconscionable things with it, 17 | being the lying liars that they are.
18 |Please tell the real {{ trust_root|escape }} that someone is 19 | trying to abuse your trust in their good name.
20 |The site {{ trust_root|escape }} has requested verification 24 | of your OpenID. I have failed to reach it and thus cannot vouch for its 25 | authenticity. Perhaps it is on your local network.
26 | {% endifequal %} 27 | {% ifequal trust_root_valid "DISCOVERY_FAILED" %} 28 |The site {{ trust_root|escape }} has requested verification 29 | of your OpenID. However, {{ trust_root|escape }} does not 30 | implement OpenID 2.0's relying party verification mechanism. Please use 31 | extra caution in deciding whether to release information to this party, 32 | and ask {{ trust_root|escape }} to implement relying party 33 | verification for your future transactions.
34 | 35 | {% include "server/pape_request_info.html" %} 36 | {% endifequal %} 37 | 38 | 39 | 40 |Blah blah blah blah blah blah blah
13 | 14 | 15 | 16 | header 17 | Status: 200 OK 18 | Content-Type: text/html 19 | YADIS_HEADER: URL_BASE/xrds 20 | 21 | 22 | 23 |Blah blah blah blah blah blah blah
28 | 29 | 30 | xrds 31 | Status: 200 OK 32 | Content-Type: application/xrds+xml 33 | 34 |Blah blah blah blah blah blah blah
101 | 102 | 103 | 404_server_response 104 | Status: 404 Not Found 105 | 106 | EEk! 107 | 108 | 500_server_response 109 | Status: 500 Server error 110 | 111 | EEk! 112 | 113 | 201_server_response 114 | Status: 201 Created 115 | 116 | EEk! 117 | 118 | 404_with_header 119 | Status: 404 Not Found 120 | YADIS_HEADER: URL_BASE/xrds 121 | 122 | EEk! 123 | 124 | 404_with_meta 125 | Status: 404 Not Found 126 | Content-Type: text/html 127 | 128 | 129 | 130 | 131 |Blah blah blah blah blah blah blah
136 | 137 | 138 | -------------------------------------------------------------------------------- /examples/README: -------------------------------------------------------------------------------- 1 | Python OpenID library example code 2 | ================================== 3 | 4 | The examples directory contains working code illustrating the use of 5 | the library for performing OpenID authentication, both as a consumer 6 | and a server. There are two kinds of examples, one that can run 7 | without any external dependencies, and one that uses the Django Web 8 | framework. The examples do not illustrate how to use all of the 9 | features of the library, but they should be a good starting point to 10 | see how to use this library with your code. 11 | 12 | Both the Django libraries and the BaseHTTPServer examples require that 13 | the OpenID library is installed or that it has been added to Python's 14 | search path (PYTHONPATH environment variable or sys.path). 15 | 16 | The Django example is probably a good place to start reading the 17 | code. There is little that is Django-specific about the OpenID logic 18 | in the example, and it should be easy to port to any framework. To run 19 | the django examples, see the README file in the djopenid subdirectory. 20 | 21 | The other examples use Python's built-in BaseHTTPServer and have a 22 | good deal of ad-hoc dispatching and rendering code mixed in 23 | 24 | Using the BaseHTTPServer examples 25 | ================================= 26 | 27 | This directory contains a working server and consumer that use this 28 | OpenID library. They are both written using python's standard 29 | BaseHTTPServer. 30 | 31 | 32 | To run the example system: 33 | 34 | 1. Make sure you've installed the library, as explained in the 35 | installation instructions. 36 | 37 | 2. Start the consumer server: 38 | 39 | python consumer.py --port 8001 40 | 41 | 42 | 3. In another terminal, start the identity server: 43 | 44 | python server.py --port 8000 45 | 46 | (Hit Ctrl-C in either server's window to stop that server.) 47 | 48 | 49 | 4. Open your web broswer, and go to the consumer server: 50 | 51 | http://localhost:8001/ 52 | 53 | Note that all pages the consumer server shows will have "Python OpenID 54 | Consumer Example" across the top. 55 | 56 | 57 | 5. Enter an identity url managed by the sample identity server: 58 | 59 | http://localhost:8000/id/bob 60 | 61 | 62 | 6. The browser will be redirected to the sample server, which will be 63 | requesting that you log in to proceed. Enter the username for the 64 | identity URL into the login box: 65 | 66 | bob 67 | 68 | Note that all pages the identity server shows will have "Python 69 | OpenID Server Example" across the top. 70 | 71 | 72 | 7. After you log in as bob, the server example will ask you if you 73 | want to allow http://localhost:8001/ to know your identity. Say 74 | yes. 75 | 76 | 77 | 8. You should end up back on the consumer site, at a page indicating 78 | you've logged in successfully. 79 | 80 | 81 | That's a basic OpenID login procedure. You can continue through it, 82 | playing with variations to see how they work. The python code is 83 | intended to be a straightforward example of how to use the python 84 | OpenID library to function as either an identity server or consumer. 85 | 86 | Getting help 87 | ============ 88 | 89 | Please send bug reports, patches, and other feedback to 90 | 91 | http://openid.net/developers/dev-mailing-lists/ 92 | -------------------------------------------------------------------------------- /openid/test/test_nonce.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | import re 4 | import unittest 5 | 6 | import six 7 | 8 | from openid.store.nonce import checkTimestamp, make_nonce_salt, mkNonce, split as splitNonce 9 | 10 | nonce_re = re.compile(r'\A\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ') 11 | 12 | 13 | class TestMakeNonceSalt(unittest.TestCase): 14 | """Test `make_nonce_salt` function.""" 15 | 16 | def test_default(self): 17 | salt = make_nonce_salt() 18 | self.assertIsInstance(salt, six.text_type) 19 | self.assertEqual(len(salt), 6) 20 | 21 | def test_custom_length(self): 22 | salt = make_nonce_salt(32) 23 | self.assertIsInstance(salt, six.text_type) 24 | self.assertEqual(len(salt), 32) 25 | 26 | 27 | class NonceTest(unittest.TestCase): 28 | def test_mkNonce(self): 29 | nonce = mkNonce() 30 | self.assertIsNotNone(nonce_re.match(nonce)) 31 | self.assertEqual(len(nonce), 26) 32 | 33 | def test_mkNonce_when(self): 34 | nonce = mkNonce(0) 35 | self.assertIsNotNone(nonce_re.match(nonce)) 36 | self.assertTrue(nonce.startswith('1970-01-01T00:00:00Z')) 37 | self.assertEqual(len(nonce), 26) 38 | 39 | def test_splitNonce(self): 40 | s = '1970-01-01T00:00:00Z' 41 | expected_t = 0 42 | expected_salt = '' 43 | actual_t, actual_salt = splitNonce(s) 44 | self.assertEqual(actual_t, expected_t) 45 | self.assertEqual(actual_salt, expected_salt) 46 | 47 | def test_mkSplit(self): 48 | t = 42 49 | nonce_str = mkNonce(t) 50 | self.assertIsNotNone(nonce_re.match(nonce_str)) 51 | et, salt = splitNonce(nonce_str) 52 | self.assertEqual(len(salt), 6) 53 | self.assertEqual(et, t) 54 | 55 | 56 | class BadSplitTest(unittest.TestCase): 57 | cases = [ 58 | '', 59 | '1970-01-01T00:00:00+1:00', 60 | '1969-01-01T00:00:00Z', 61 | '1970-00-01T00:00:00Z', 62 | '1970.01-01T00:00:00Z', 63 | 'Thu Sep 7 13:29:31 PDT 2006', 64 | 'monkeys', 65 | ] 66 | 67 | def test(self): 68 | for nonce_str in self.cases: 69 | self.assertRaises(ValueError, splitNonce, nonce_str) 70 | 71 | 72 | class CheckTimestampTest(unittest.TestCase): 73 | cases = [ 74 | # exact, no allowed skew 75 | ('1970-01-01T00:00:00Z', 0, 0, True), 76 | 77 | # exact, large skew 78 | ('1970-01-01T00:00:00Z', 1000, 0, True), 79 | 80 | # no allowed skew, one second old 81 | ('1970-01-01T00:00:00Z', 0, 1, False), 82 | 83 | # many seconds old, outside of skew 84 | ('1970-01-01T00:00:00Z', 10, 50, False), 85 | 86 | # one second old, one second skew allowed 87 | ('1970-01-01T00:00:00Z', 1, 1, True), 88 | 89 | # One second in the future, one second skew allowed 90 | ('1970-01-01T00:00:02Z', 1, 1, True), 91 | 92 | # two seconds in the future, one second skew allowed 93 | ('1970-01-01T00:00:02Z', 1, 0, False), 94 | 95 | # malformed nonce string 96 | ('monkeys', 0, 0, False), 97 | ] 98 | 99 | def test(self): 100 | for nonce_string, allowed_skew, now, expected in self.cases: 101 | actual = checkTimestamp(nonce_string, allowed_skew, now) 102 | self.assertEqual(bool(actual), bool(expected)) 103 | -------------------------------------------------------------------------------- /examples/djopenid/templates/consumer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |35 | This is an example consumer built for the Django framework. Enter 36 | an OpenID in the box below. 37 |
38 | 39 | {% if error %} 40 |There's really nothing interesting about this
" 106 | "") 107 | self.assertRaises(MetaNotFound, findHTMLMeta, buff) 108 | 109 | def test_unclosed_tag(self): 110 | # script tag not closed 111 | buff = StringIO(' 33 | 34 | 35 | """ % (title, form) 36 | 37 | 38 | def log(message, level=0): 39 | """Handle a log message from the OpenID library. 40 | 41 | This is a legacy function which redirects to logging.error. 42 | The logging module should be used instead of this 43 | 44 | @param message: A string containing a debugging message from the 45 | OpenID library 46 | @type message: six.text_type, six.binary_type is deprecated 47 | 48 | @param level: The severity of the log message. This parameter is 49 | currently unused, but in the future, the library may indicate 50 | more important information with a higher level value. 51 | @type level: int or None 52 | 53 | @returns: Nothing. 54 | """ 55 | message = string_to_text(message, "Binary values for log are deprecated. Use text input instead.") 56 | 57 | logging.error("This is a legacy log message, please use the logging module. Message: %s", message) 58 | 59 | 60 | def appendArgs(url, args): 61 | """Append query arguments to a HTTP(s) URL. If the URL already has 62 | query arguemtns, these arguments will be added, and the existing 63 | arguments will be preserved. Duplicate arguments will not be 64 | detected or collapsed (both will appear in the output). 65 | 66 | @param url: The url to which the arguments will be appended 67 | @type url: six.text_type, six.binary_type is deprecated 68 | 69 | @param args: The query arguments to add to the URL. If a 70 | dictionary is passed, the items will be sorted before 71 | appending them to the URL. If a sequence of pairs is passed, 72 | the order of the sequence will be preserved. 73 | @type args: Union[Dict[six.text_type, six.text_type], List[Tuple[six.text_type, six.text_type]]], 74 | six.binary_type is deprecated 75 | 76 | @returns: The URL with the parameters added 77 | @rtype: six.text_type 78 | """ 79 | url = string_to_text(url, "Binary values for appendArgs are deprecated. Use text input instead.") 80 | 81 | if hasattr(args, 'items'): 82 | args = sorted(args.items()) 83 | else: 84 | args = list(args) 85 | 86 | if len(args) == 0: 87 | return url 88 | 89 | if '?' in url: 90 | sep = '&' 91 | else: 92 | sep = '?' 93 | 94 | i = 0 95 | for k, v in args: 96 | k = string_to_text(k, "Binary values for appendArgs are deprecated. Use text input instead.") 97 | v = string_to_text(v, "Binary values for appendArgs are deprecated. Use text input instead.") 98 | args[i] = (k.encode('utf-8'), v.encode('utf-8')) 99 | i += 1 100 | 101 | encoded_args = urlencode(args) 102 | # `urlencode` returns `str` in both py27 and py3+. We need to convert it to six.text_type. 103 | if not isinstance(encoded_args, six.text_type): 104 | encoded_args = encoded_args.decode('utf-8') 105 | return '%s%s%s' % (url, sep, encoded_args) 106 | 107 | 108 | def toBase64(s): 109 | """Return string s as base64, omitting newlines. 110 | 111 | @type s: six.binary_type 112 | @rtype six.text_type 113 | """ 114 | return binascii.b2a_base64(s)[:-1].decode('utf-8') 115 | 116 | 117 | def fromBase64(s): 118 | """Return binary data from base64 encoded string. 119 | 120 | @type s: six.text_type, six.binary_type deprecated. 121 | @rtype six.binary_type 122 | """ 123 | s = string_to_text(s, "Binary values for s are deprecated. Use text input instead.") 124 | try: 125 | return binascii.a2b_base64(s) 126 | except binascii.Error as why: 127 | # Convert to a common exception type 128 | raise ValueError(six.text_type(why)) 129 | 130 | 131 | class Symbol(object): 132 | """This class implements an object that compares equal to others 133 | of the same type that have the same name. These are distict from 134 | string objects. 135 | """ 136 | 137 | def __init__(self, name): 138 | self.name = name 139 | 140 | def __eq__(self, other): 141 | return type(self) == type(other) and self.name == other.name 142 | 143 | def __ne__(self, other): 144 | return not (self == other) 145 | 146 | def __hash__(self): 147 | return hash((self.__class__, self.name)) 148 | 149 | def __repr__(self): 150 | return '