diff options
author | Vlastimil Zíma <vlastimil.zima@nic.cz> | 2018-05-09 13:24:16 +0200 |
---|---|---|
committer | Vlastimil Zíma <vlastimil.zima@nic.cz> | 2018-05-11 13:39:31 +0200 |
commit | 2f57983ab8ea63f4438acd048cce50cce1e142d6 (patch) | |
tree | b96d2e232e500dd97295493f73197cc0384c15fb /openid | |
parent | 61e6d6a135600db480ed14ec8f6fbb8676668dc3 (diff) | |
download | openid-2f57983ab8ea63f4438acd048cce50cce1e142d6.tar.gz |
Transform remaining API to text strings
Diffstat (limited to 'openid')
30 files changed, 330 insertions, 237 deletions
diff --git a/openid/consumer/consumer.py b/openid/consumer/consumer.py index 96c6ef7..a190ffc 100644 --- a/openid/consumer/consumer.py +++ b/openid/consumer/consumer.py @@ -186,17 +186,21 @@ USING THIS LIBRARY L{SetupNeededResponse<openid.consumer.consumer.SetupNeededResponse>} objects. """ +from __future__ import unicode_literals import copy import logging from urlparse import parse_qsl, urldefrag, urlparse +import six + from openid import cryptutil, fetchers, oidutil, urinorm from openid.association import Association, SessionNegotiator, default_negotiator from openid.consumer.discover import (OPENID_1_0_TYPE, OPENID_1_1_TYPE, OPENID_2_0_TYPE, DiscoveryFailure, OpenIDServiceEndpoint, discover) from openid.dh import DiffieHellman from openid.message import BARE_NS, IDENTIFIER_SELECT, OPENID1_NS, OPENID2_NS, OPENID_NS, Message, no_default +from openid.oidutil import string_to_text from openid.store.nonce import mkNonce, split as splitNonce from openid.yadis.manager import Discovery @@ -373,7 +377,7 @@ class Consumer(object): try: auth_req.setAnonymous(anonymous) except ValueError as why: - raise ProtocolError(str(why)) + raise ProtocolError(six.text_type(why)) return auth_req @@ -437,7 +441,7 @@ class Consumer(object): (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)] + @type association_preferences: List[Tuple[six.text_type, six.text_type]], six.binary_type is deprecated @returns: None @@ -1054,7 +1058,7 @@ class GenericConsumer(object): self._verifyDiscoverySingle( endpoint, to_match_endpoint) except ProtocolError as why: - failure_messages.append(str(why)) + failure_messages.append(six.text_type(why)) else: # It matches, so discover verification has # succeeded. Return this endpoint. @@ -1258,20 +1262,23 @@ class GenericConsumer(object): @param assoc_type: The association type that the request should ask for. - @type assoc_type: str + @type assoc_type: six.text_type, six.binary_type is deprecated @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 + @type session_type: six.text_type, six.binary_type is deprecated @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) """ + assoc_type = string_to_text(assoc_type, "Binary values for assoc_type are deprecated. Use text input instead.") + session_type = string_to_text(session_type, + "Binary values for assoc_type are deprecated. Use text input instead.") session_type_class = self.session_types[session_type] assoc_session = session_type_class() @@ -1303,7 +1310,7 @@ class GenericConsumer(object): return 'no-encryption' @returns: The association type for this message - @rtype: str + @rtype: six.text_type @raises KeyError: when the session_type field is absent. """ @@ -1472,20 +1479,20 @@ class AuthRequest(object): @param namespace: The namespace for the extension. For example, the simple registration extension uses the namespace C{sreg}. - - @type namespace: str + @type namespace: six.text_type, six.binary_type is deprecated @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 + @type key: six.text_type, six.binary_type is deprecated @param value: The value to provide to the server for this argument. - - @type value: str + @type value: six.text_type, six.binary_type is deprecated """ + namespace = string_to_text(namespace, "Binary values for namespace are deprecated. Use text input instead.") + key = string_to_text(key, "Binary values for key are deprecated. Use text input instead.") + value = string_to_text(value, "Binary values for value are deprecated. Use text input instead.") self.message.setArg(namespace, key, value) def getMessage(self, realm, return_to=None, immediate=False): @@ -1493,8 +1500,7 @@ class AuthRequest(object): @param realm: The URL (or URL pattern) that identifies your web site to the user when she is authorizing it. - - @type realm: str + @type realm: six.text_type, six.binary_type is deprecated @param return_to: The URL that the OpenID provider will send the user back to after attempting to verify her identity. @@ -1502,8 +1508,7 @@ class AuthRequest(object): 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 + @type return_to: six.text_type, six.binary_type is deprecated @param immediate: If True, the OpenID provider is to send back a response immediately, useful for behind-the-scenes @@ -1517,7 +1522,9 @@ class AuthRequest(object): @returntype: L{openid.message.Message} """ + realm = string_to_text(realm, "Binary values for realm are deprecated. Use text input instead.") if return_to: + return_to = string_to_text(return_to, "Binary values for return_to are deprecated. Use text input instead.") return_to = oidutil.appendArgs(return_to, self.return_to_args) elif immediate: raise ValueError( @@ -1580,8 +1587,7 @@ class AuthRequest(object): @param realm: The URL (or URL pattern) that identifies your web site to the user when she is authorizing it. - - @type realm: str + @type realm: six.text_type, six.binary_type is deprecated @param return_to: The URL that the OpenID provider will send the user back to after attempting to verify her identity. @@ -1589,8 +1595,7 @@ class AuthRequest(object): 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 + @type return_to: six.text_type, six.binary_type is deprecated @param immediate: If True, the OpenID provider is to send back a response immediately, useful for behind-the-scenes @@ -1604,7 +1609,7 @@ class AuthRequest(object): @returns: The URL to redirect the user agent to. - @returntype: str + @returntype: six.text_type """ message = self.getMessage(realm, return_to, immediate) return message.toURL(self.endpoint.server_url) @@ -1627,7 +1632,7 @@ class AuthRequest(object): @see: formMarkup - @returns: str + @returns: six.text_type """ return oidutil.autoSubmitHTML(self.formMarkup(realm, return_to, immediate, form_tag_attrs)) @@ -1772,7 +1777,7 @@ class SuccessResponse(Response): initial request, or C{None} if the response did not contain an C{openid.return_to} argument. - @returntype: str + @returntype: six.text_type """ return self.getSigned(OPENID_NS, 'return_to') diff --git a/openid/consumer/discover.py b/openid/consumer/discover.py index 08af0a6..a3ffa59 100644 --- a/openid/consumer/discover.py +++ b/openid/consumer/discover.py @@ -1,17 +1,5 @@ -# -*- 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', -] +"""Functions to discover OpenID endpoints from identifiers.""" +from __future__ import unicode_literals import logging import urlparse @@ -21,11 +9,23 @@ from lxml.html import document_fromstring from openid import fetchers, urinorm from openid.message import OPENID1_NS as OPENID_1_0_MESSAGE_NS, OPENID2_NS as OPENID_2_0_MESSAGE_NS +from openid.oidutil import string_to_text from openid.yadis import filters, xri, xrires from openid.yadis.discover import DiscoveryFailure, discover as yadisDiscover from openid.yadis.etxrd import XRD_NS_2_0, XRDSError, nsTag from openid.yadis.services import applyFilter as extractServices +__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', +] + _LOGGER = logging.getLogger(__name__) OPENID_1_0_NS = 'http://openid.net/xmlns/1.0' @@ -263,7 +263,7 @@ def findOPLocalIdentifier(service_element, type_uris): @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] + @type type_uris: List[six.text_type], six.binary_type is deprecated @raises DiscoveryFailure: when discovery fails. @@ -272,6 +272,8 @@ def findOPLocalIdentifier(service_element, type_uris): @rtype: six.text_type or NoneType """ # XXX: Test this function on its own! + type_uris = [string_to_text(u, "Binary values for text_uris are deprecated. Use text input instead.") + for u in type_uris] # Build the list of tags that could contain the OP-Local Identifier local_id_tags = [] @@ -367,13 +369,14 @@ def discoverYadis(uri): on old-style <link rel='...'> discovery if Yadis fails. @param uri: normalized identity URL - @type uri: str + @type uri: six.text_type, six.binary_type is deprecated @return: (claimed_id, services) - @rtype: (str, list(OpenIDServiceEndpoint)) + @rtype: (six.text_type, list(OpenIDServiceEndpoint)) @raises DiscoveryFailure: when discovery fails. """ + uri = string_to_text(uri, "Binary values for discoverYadis are deprecated. Use text input instead.") # 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 diff --git a/openid/extension.py b/openid/extension.py index 55e129b..d8c6828 100644 --- a/openid/extension.py +++ b/openid/extension.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import warnings from openid import message as message_module diff --git a/openid/extensions/draft/pape5.py b/openid/extensions/draft/pape5.py index 47cf9b2..3a28dc2 100644 --- a/openid/extensions/draft/pape5.py +++ b/openid/extensions/draft/pape5.py @@ -5,6 +5,8 @@ Extension 1.0, Draft 5 @since: 2.1.0 """ +from __future__ import unicode_literals + import warnings from openid.extensions.pape import (AUTH_MULTI_FACTOR, AUTH_MULTI_FACTOR_PHYSICAL, AUTH_PHISHING_RESISTANT, LEVELS_JISA, diff --git a/openid/fetchers.py b/openid/fetchers.py index 2328fc9..3bcb9d7 100644 --- a/openid/fetchers.py +++ b/openid/fetchers.py @@ -1,11 +1,5 @@ -# -*- 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'] +"""This module contains the HTTP fetcher interface and several implementations.""" +from __future__ import unicode_literals import cStringIO import sys @@ -15,6 +9,10 @@ import urllib2 import openid import openid.urinorm +__all__ = ['fetch', 'getDefaultFetcher', 'setDefaultFetcher', 'HTTPResponse', + 'HTTPFetcher', 'createHTTPFetcher', 'HTTPFetchingError', + 'HTTPError'] + # Try to import httplib2 for caching support # http://bitworking.org/projects/httplib2/ try: @@ -121,7 +119,10 @@ def usingCurl(): class HTTPResponse(object): - """XXX document attributes""" + """XXX document attributes + + @type body: six.binary_type + """ headers = None status = None body = None @@ -154,7 +155,7 @@ class HTTPFetcher(object): @param headers: HTTP headers to include with the request - @type headers: {str:str} + @type headers: Dict[six.text_type, six.text_type] @return: An object representing the server's HTTP response. If there are network or protocol errors, an exception will be diff --git a/openid/server/server.py b/openid/server/server.py index 6afe826..701fbdf 100644 --- a/openid/server/server.py +++ b/openid/server/server.py @@ -115,6 +115,7 @@ From 1.1 to 2.0 @group Response Encodings: ENCODE_KVFORM, ENCODE_HTML_FORM, ENCODE_URL """ +from __future__ import unicode_literals import logging import time @@ -128,6 +129,7 @@ from openid.association import Association, default_negotiator, getSecretSize from openid.dh import DiffieHellman from openid.message import (IDENTIFIER_SELECT, OPENID1_URL_LIMIT, OPENID2_NS, OPENID_NS, InvalidNamespace, InvalidOpenIDNamespace, Message) +from openid.oidutil import string_to_text from openid.server.trustroot import TrustRoot, verifyReturnTo from openid.store.nonce import mkNonce from openid.urinorm import urinorm @@ -151,7 +153,7 @@ class OpenIDRequest(object): """I represent an incoming OpenID request. @cvar mode: the C{X{openid.mode}} of this request. - @type mode: str + @type mode: six.text_type @ivar message: Original request message. @type message: Message @@ -177,16 +179,16 @@ class CheckAuthRequest(OpenIDRequest): """A request to verify the validity of a previous response. @cvar mode: "X{C{check_authentication}}" - @type mode: str + @type mode: six.text_type @ivar assoc_handle: The X{association handle} the response was signed with. - @type assoc_handle: str + @type assoc_handle: six.text_type @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 + @type invalidate_handle: six.text_type @see: U{OpenID Specs, Mode: check_authentication <http://openid.net/specs.bml#mode-check_authentication>} @@ -201,13 +203,17 @@ class CheckAuthRequest(OpenIDRequest): These parameters are assigned directly as class attributes, see my L{class documentation<CheckAuthRequest>} for their descriptions. - @type assoc_handle: str + @type assoc_handle: six.text_type, six.binary_type is deprecated @type signed: L{Message} - @type invalidate_handle: str + @type invalidate_handle: six.text_type, six.binary_type is deprecated """ super(CheckAuthRequest, self).__init__(message=message) - self.assoc_handle = assoc_handle + self.assoc_handle = string_to_text(assoc_handle, + "Binary values for assoc_handle are deprecated. Use text input instead.") self.signed = signed + if invalidate_handle is not None: + invalidate_handle = string_to_text( + invalidate_handle, "Binary values for invalidate_handle are deprecated. Use text input instead.") self.invalidate_handle = invalidate_handle @classmethod @@ -282,7 +288,7 @@ class PlainTextServerSession(object): @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 + @type session_type: six.text_type @see: U{OpenID Specs, Mode: associate <http://openid.net/specs.bml#mode-associate>} @@ -305,7 +311,7 @@ class DiffieHellmanSHA1ServerSession(object): @cvar session_type: The session_type for this association session. - @type session_type: str + @type session_type: six.text_type @ivar dh: The Diffie-Hellman algorithm values for this request @type dh: DiffieHellman @@ -388,11 +394,11 @@ class AssociateRequest(OpenIDRequest): """A request to establish an X{association}. @cvar mode: "X{C{check_authentication}}" - @type mode: str + @type mode: six.text_type @ivar assoc_type: The type of association. The protocol currently only defines one value for this, "X{C{HMAC-SHA1}}". - @type assoc_type: str + @type assoc_type: six.text_type @ivar session: An object that knows how to handle association requests of a certain type. @@ -526,32 +532,32 @@ class CheckIDRequest(OpenIDRequest): and X{C{checkid_setup}}. @cvar mode: "X{C{checkid_immediate}}" or "X{C{checkid_setup}}" - @type mode: str + @type mode: six.text_type @ivar immediate: Is this an immediate-mode request? @type immediate: bool @ivar identity: The OP-local identifier being checked. - @type identity: str + @type identity: six.text_type @ivar claimed_id: The claimed identifier. Not present in OpenID 1.x messages. - @type claimed_id: str or None + @type claimed_id: Optional[six.text_type] @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 + @type trust_root: six.text_type @ivar return_to: The URL to send the user agent back to to reply to this request. - @type return_to: str + @type return_to: six.text_type @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 + @type assoc_handle: six.text_type """ def __init__(self, identity, return_to, trust_root=None, immediate=False, @@ -631,7 +637,7 @@ class CheckIDRequest(OpenIDRequest): @param op_endpoint: The endpoint URL of the server that this message was sent to. - @type op_endpoint: str + @type op_endpoint: Optional[six.text_type], six.binary_type is deprecated @returntype: L{CheckIDRequest} """ @@ -665,6 +671,9 @@ class CheckIDRequest(OpenIDRequest): assoc_handle = message.getArg(OPENID_NS, 'assoc_handle') + if op_endpoint is not None: + op_endpoint = string_to_text(op_endpoint, + "Binary values for op_endpoint are deprecated. Use text input instead.") self = klass(identity, return_to, trust_root=trust_root, immediate=immediate, assoc_handle=assoc_handle, op_endpoint=op_endpoint, claimed_id=claimed_id, message=message) return self @@ -742,12 +751,11 @@ class CheckIDRequest(OpenIDRequest): Optional for requests where C{CheckIDRequest.immediate} is C{False} or C{allow} is C{True}. - - @type server_url: str + @type server_url: Optional[six.text_type], six.binary_type is deprecated @param identity: The OP-local identifier to answer with. Only for use when the relying party requested identifier selection. - @type identity: str or None + @type identity: Optional[six.text_type], six.binary_type is deprecated @param claimed_id: The claimed identifier to answer with, for use with identifier selection in the case where the claimed identifier @@ -760,7 +768,7 @@ class CheckIDRequest(OpenIDRequest): C{claimed_id} will default to that of the request. This parameter is new in OpenID 2.0. - @type claimed_id: str or None + @type claimed_id: Optional[six.text_type], six.binary_type is deprecated @returntype: L{OpenIDResponse} @@ -768,6 +776,12 @@ class CheckIDRequest(OpenIDRequest): @raises NoReturnError: when I do not have a return_to. """ + if identity is not None: + identity = string_to_text(identity, "Binary values for identity are deprecated. Use text input instead.") + if claimed_id is not None: + claimed_id = string_to_text(claimed_id, + "Binary values for claimed_id are deprecated. Use text input instead.") + if not self.return_to: raise NoReturnToError @@ -779,6 +793,9 @@ class CheckIDRequest(OpenIDRequest): "to respond to OpenID 2.0 messages." % (self,)) server_url = self.op_endpoint + else: + server_url = string_to_text(server_url, + "Binary values for server_url are deprecated. Use text input instead.") if allow: mode = 'id_res' @@ -876,9 +893,9 @@ class CheckIDRequest(OpenIDRequest): """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 + @type server_url: six.text_type, six.binary_type is deprecated - @returntype: str + @returntype: six.text_type @raises NoReturnError: when I do not have a return_to. """ @@ -903,6 +920,7 @@ class CheckIDRequest(OpenIDRequest): response = Message(self.message.getOpenIDNamespace()) response.updateArgs(OPENID_NS, q) + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") return response.toURL(server_url) def getCancelURL(self): @@ -915,7 +933,7 @@ class CheckIDRequest(OpenIDRequest): that it knows that the user did make a decision. Or you could simulate this method by doing C{.answer(False).encodeToURL()}) - @returntype: str + @returntype: six.text_type @returns: The return_to URL with openid.mode = cancel. @raises NoReturnError: when I do not have a return_to. @@ -951,7 +969,7 @@ class OpenIDResponse(object): @type fields: L{openid.message.Message} @ivar signed: The names of the fields which should be signed. - @type signed: list of str + @type signed: List[six.text_type] """ # Implementer's note: In a more symmetric client/server @@ -983,7 +1001,7 @@ class OpenIDResponse(object): that can be overridden. If a value is supplied for 'action' or 'method', it will be replaced. - @returntype: str + @returntype: six.text_type @since: 2.1.0 """ @@ -994,7 +1012,7 @@ class OpenIDResponse(object): """Returns an HTML document that auto-submits the form markup for this response. - @returntype: str + @returntype: six.text_type @see: toFormMarkup @@ -1044,7 +1062,7 @@ class OpenIDResponse(object): You will generally use this URL with a HTTP redirect. @returns: A URL to direct the user agent back to. - @returntype: str + @returntype: six.text_type """ return self.fields.toURL(self.request.return_to) @@ -1088,7 +1106,7 @@ class WebResponse(object): @type headers: dict @ivar body: The body of this response. - @type body: str + @type body: six.text_type """ def __init__(self, code=HTTP_OK, headers=None, body=""): @@ -1141,7 +1159,7 @@ class Signatory(object): @param assoc_handle: The handle of the association used to sign the data. - @type assoc_handle: str + @type assoc_handle: six.text_type, six.binary_type is deprecated @param message: The signed message to verify @type message: openid.message.Message @@ -1149,6 +1167,8 @@ class Signatory(object): @returns: C{True} if the signature is valid, C{False} if not. @returntype: bool """ + assoc_handle = string_to_text(assoc_handle, + "Binary values for assoc_handle are deprecated. Use text input instead.") assoc = self.getAssociation(assoc_handle, dumb=True) if not assoc: _LOGGER.error("failed to get assoc with handle %r to verify message %r", assoc_handle, message) @@ -1202,7 +1222,7 @@ class Signatory(object): try: signed_response.fields = assoc.signMessage(signed_response.fields) except kvform.KVFormError as err: - raise EncodingError(response, explanation=str(err)) + raise EncodingError(response, explanation=six.text_type(err)) return signed_response def createAssociation(self, dumb=True, assoc_type='HMAC-SHA1'): @@ -1213,11 +1233,13 @@ class Signatory(object): @param assoc_type: The type of association to create. Currently there is only one type defined, C{HMAC-SHA1}. - @type assoc_type: str + @type assoc_type: six.text_type, six.binary_type is deprecated @returns: the new association. @returntype: L{openid.association.Association} """ + assoc_type = string_to_text(assoc_type, "Binary values for assoc_type are deprecated. Use text input instead.") + secret = cryptutil.getBytes(getSecretSize(assoc_type)) uniq = oidutil.toBase64(cryptutil.getBytes(4)) handle = '{%s}{%x}{%s}' % (assoc_type, int(time.time()), uniq) @@ -1235,7 +1257,7 @@ class Signatory(object): def getAssociation(self, assoc_handle, dumb, checkExpiration=True): """Get the association with the specified handle. - @type assoc_handle: str + @type assoc_handle: six.text_type, six.binary_type is deprecated @param dumb: Is this association used with dumb mode? @type dumb: bool @@ -1252,6 +1274,8 @@ class Signatory(object): if assoc_handle is None: raise ValueError("assoc_handle must not be None") + assoc_handle = string_to_text(assoc_handle, + "Binary values for assoc_handle are deprecated. Use text input instead.") if dumb: key = self._dumb_key @@ -1269,7 +1293,7 @@ class Signatory(object): def invalidate(self, assoc_handle, dumb): """Invalidates the association with the given handle. - @type assoc_handle: str + @type assoc_handle: six.text_type, six.binary_type is deprecated @param dumb: Is this association used with dumb mode? @type dumb: bool @@ -1278,6 +1302,8 @@ class Signatory(object): key = self._dumb_key else: key = self._normal_key + assoc_handle = string_to_text(assoc_handle, + "Binary values for assoc_handle are deprecated. Use text input instead.") self.store.removeAssociation(key, assoc_handle) @@ -1400,13 +1426,13 @@ class Decoder(object): query = query.copy() query['openid.ns'] = OPENID2_NS message = Message.fromPostArgs(query) - raise ProtocolError(message, str(err)) + raise ProtocolError(message, six.text_type(err)) except InvalidNamespace as err: # If openid.ns is OK, but there is problem with other namespaces # We keep only bare parts of query and we try to make a ProtocolError from it query = [(key, value) for key, value in query.items() if key.count('.') < 2] message = Message.fromPostArgs(dict(query)) - raise ProtocolError(message, str(err)) + raise ProtocolError(message, six.text_type(err)) mode = message.getArg(OPENID_NS, 'mode') if not mode: @@ -1469,7 +1495,7 @@ class Server(object): @type encoder: L{Encoder} @ivar op_endpoint: My URL. - @type op_endpoint: str + @type op_endpoint: six.text_type @ivar negotiator: I use this to determine which kinds of associations I can make and how. @@ -1488,7 +1514,7 @@ class Server(object): @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 + @type op_endpoint: six.text_type, six.binary_type is deprecated @change: C{op_endpoint} is new in library version 2.0. It currently defaults to C{None} for compatibility with @@ -1521,7 +1547,8 @@ class Server(object): "for OpenID 2.0 servers" % (self.__class__.__module__, self.__class__.__name__), stacklevel=2) - self.op_endpoint = op_endpoint + self.op_endpoint = string_to_text(op_endpoint, + "Binary values for op_endpoint are deprecated. Use text input instead.") def handleRequest(self, request): """Handle a request. @@ -1621,18 +1648,20 @@ class ProtocolError(Exception): @type message: openid.message.Message @param text: A message about the encountered error. Set as C{args[0]}. - @type text: str + @type text: six.text_type, six.binary_type is deprecated """ self.openid_message = message self.reference = reference self.contact = contact assert not isinstance(message, six.string_types) + if text is not None: + text = string_to_text(text, "Binary values for text are deprecated. Use text input instead.") Exception.__init__(self, text) def getReturnTo(self): """Get the return_to argument from the request, if any. - @returntype: str + @returntype: six.text_type """ if self.openid_message is None: return None @@ -1653,13 +1682,13 @@ class ProtocolError(Exception): namespace = self.openid_message.getOpenIDNamespace() reply = Message(namespace) reply.setArg(OPENID_NS, 'mode', 'error') - reply.setArg(OPENID_NS, 'error', str(self)) + reply.setArg(OPENID_NS, 'error', six.text_type(self)) if self.contact is not None: - reply.setArg(OPENID_NS, 'contact', str(self.contact)) + reply.setArg(OPENID_NS, 'contact', six.text_type(self.contact)) if self.reference is not None: - reply.setArg(OPENID_NS, 'reference', str(self.reference)) + reply.setArg(OPENID_NS, 'reference', six.text_type(self.reference)) return reply diff --git a/openid/server/trustroot.py b/openid/server/trustroot.py index ed25895..7c1b801 100644 --- a/openid/server/trustroot.py +++ b/openid/server/trustroot.py @@ -1,4 +1,3 @@ -# -*- 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 @@ -8,6 +7,17 @@ implementers who wish to use it for additional trust root checking. It also implements relying party return_to URL verification, based on the realm. """ +from __future__ import unicode_literals + +import logging +import re +from urlparse import urlsplit, urlunsplit + +import six + +from openid import urinorm +from openid.oidutil import string_to_text +from openid.yadis import services __all__ = [ 'TrustRoot', @@ -17,12 +27,6 @@ __all__ = [ 'verifyReturnTo', ] -import logging -import re -from urlparse import urlsplit, urlunsplit - -from openid import urinorm -from openid.yadis import services _LOGGER = logging.getLogger(__name__) @@ -176,14 +180,14 @@ class TrustRoot(object): @param url: The URL to check - - @type url: C{str} + @type url: six.text_type, six.binary_type is deprecated @return: Whether the given URL is within this trust root. @rtype: C{bool} """ + url = string_to_text(url, "Binary values for validateURL are deprecated. Use text input instead.") url_parts = _parseURL(url) if url_parts is None: @@ -237,8 +241,7 @@ class TrustRoot(object): @param trust_root: This is the trust root to parse into a C{L{TrustRoot}} object. - - @type trust_root: C{str} + @type trust_root: six.text_type, six.binary_type is deprecated @return: A C{L{TrustRoot}} instance if trust_root parses as a @@ -246,6 +249,7 @@ class TrustRoot(object): @rtype: C{NoneType} or C{L{TrustRoot}} """ + trust_root = string_to_text(trust_root, "Binary values for trust_root are deprecated. Use text input instead.") url_parts = _parseURL(trust_root) if url_parts is None: return None @@ -279,7 +283,7 @@ class TrustRoot(object): @classmethod def checkSanity(cls, trust_root_string): - """str -> bool + """six.text_type -> bool, six.binary_type is deprecated is this a sane trust root? """ @@ -302,7 +306,7 @@ class TrustRoot(object): This function does not check to make sure that the realm is valid. Its behaviour on invalid inputs is undefined. - @rtype: str + @rtype: six.text_type @returns: The URL upon which relying party discovery should be run in order to verify the return_to URL @@ -352,7 +356,7 @@ def _extractReturnURL(endpoint): @returns: The endpoint URL or None if the endpoint is not a relying party endpoint. - @rtype: str or NoneType + @rtype: six.text_type or NoneType """ if endpoint.matchTypes([RP_RETURN_TO_URL_TYPE]): return endpoint.uri @@ -429,7 +433,7 @@ def verifyReturnTo(realm_str, return_to, _vrfy=getAllowedReturnURLs): try: allowable_urls = _vrfy(realm.buildDiscoveryURL()) except RealmVerificationRedirected as err: - _LOGGER.exception(str(err)) + _LOGGER.exception(six.text_type(err)) return False if returnToMatches(allowable_urls, return_to): diff --git a/openid/store/filestore.py b/openid/store/filestore.py index aadf20d..a7a3e7f 100644 --- a/openid/store/filestore.py +++ b/openid/store/filestore.py @@ -1,7 +1,5 @@ -""" -This module contains an C{L{OpenIDStore}} implementation backed by -flat files. -""" +"""This module contains an C{L{OpenIDStore}} implementation backed by flat files.""" +from __future__ import unicode_literals import logging import os @@ -13,6 +11,7 @@ from tempfile import mkstemp from openid import cryptutil, oidutil from openid.association import Association +from openid.oidutil import string_to_text from openid.store import nonce from openid.store.interface import OpenIDStore @@ -23,7 +22,7 @@ _isFilenameSafe = set(_filename_allowed).__contains__ def _safe64(s): - h64 = oidutil.toBase64(cryptutil.sha1(s)) + h64 = oidutil.toBase64(cryptutil.sha1(s.encode('utf-8'))) h64 = h64.replace('+', '_') h64 = h64.replace('/', '.') h64 = h64.replace('=', '') @@ -44,7 +43,7 @@ def _removeIfPresent(filename): """Attempt to remove a file, returning whether the file existed at the time of the call. - str -> bool + six.text_type -> bool """ try: os.unlink(filename) @@ -65,7 +64,7 @@ def _ensureDir(dir_name): Can raise OSError - str -> NoneType + six.text_type -> NoneType """ try: os.makedirs(dir_name) @@ -99,8 +98,7 @@ class FileOpenIDStore(OpenIDStore): @param directory: This is the directory to put the store directories in. - - @type directory: C{str} + @type directory: six.text_type, six.binary_type is deprecated """ # Make absolute directory = os.path.normpath(os.path.abspath(directory)) @@ -136,7 +134,7 @@ class FileOpenIDStore(OpenIDStore): the store, it is safe to remove all of the files in the temporary directory. - () -> (file, str) + () -> (file, six.text_type) """ fd, name = mkstemp(dir=self.temp_dir) try: @@ -155,8 +153,11 @@ class FileOpenIDStore(OpenIDStore): contain the domain name from the server URL for ease of human inspection of the data directory. - (str, str) -> str + (six.text_type, six.text_type) -> six.text_type, six.binary_type is deprecated """ + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") + handle = string_to_text(handle, "Binary values for handle are deprecated. Use text input instead.") + if server_url.find('://') == -1: raise ValueError('Bad server URL: %r' % server_url) @@ -175,15 +176,17 @@ class FileOpenIDStore(OpenIDStore): def storeAssociation(self, server_url, association): """Store an association in the association directory. - (str, Association) -> NoneType + (six.text_type, Association) -> NoneType, six.binary_type is deprecated """ + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") + association_s = association.serialize() filename = self.getAssociationFilename(server_url, association.handle) tmp_file, tmp = self._mktemp() try: try: - tmp_file.write(association_s) + tmp_file.write(association_s.encode('utf-8')) os.fsync(tmp_file.fileno()) finally: tmp_file.close() @@ -218,8 +221,12 @@ class FileOpenIDStore(OpenIDStore): """Retrieve an association. If no handle is specified, return the association with the latest expiration. - (str, str or NoneType) -> Association or NoneType + (six.text_type, Optional[six.text_type]) -> Association or NoneType, six.binary_type is deprecated """ + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") + if handle is not None: + handle = string_to_text(handle, "Binary values for handle are deprecated. Use text input instead.") + if handle is None: handle = '' @@ -287,8 +294,11 @@ class FileOpenIDStore(OpenIDStore): def removeAssociation(self, server_url, handle): """Remove an association if it exists. Do nothing if it does not. - (str, str) -> bool + (six.text_type, six.text_type) -> bool, six.binary_type is deprecated """ + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") + handle = string_to_text(handle, "Binary values for handle are deprecated. Use text input instead.") + assoc = self.getAssociation(server_url, handle) if assoc is None: return 0 @@ -299,8 +309,11 @@ class FileOpenIDStore(OpenIDStore): def useNonce(self, server_url, timestamp, salt): """Return whether this nonce is valid. - str -> bool + @type server_url: six.text_type, six.binary_type is deprecated + @rtype: bool """ + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") + if abs(timestamp - time.time()) > nonce.SKEW: return False diff --git a/openid/store/interface.py b/openid/store/interface.py index 6377657..88fc0e9 100644 --- a/openid/store/interface.py +++ b/openid/store/interface.py @@ -1,7 +1,5 @@ -""" -This module contains the definition of the C{L{OpenIDStore}} -interface. -""" +"""This module contains the definition of the C{L{OpenIDStore}} interface.""" +from __future__ import unicode_literals class OpenIDStore(object): @@ -33,8 +31,7 @@ class OpenIDStore(object): 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} + @type server_url: six.text_type @param association: The C{L{Association @@ -74,16 +71,13 @@ class OpenIDStore(object): 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} - + @type server_url: six.text_type @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} + @type handle: Optional[six.text_type] @return: The C{L{Association @@ -107,16 +101,13 @@ class OpenIDStore(object): 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} - + @type server_url: six.text_type @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} + @type handle: six.text_type @return: Returns whether or not the given association existed. @@ -144,8 +135,7 @@ class OpenIDStore(object): @param server_url: The URL of the server from which the nonce originated. - - @type server_url: C{str} + @type server_url: six.text_type @param timestamp: The time that the nonce was created (to the nearest second), in seconds since January 1 1970 UTC. @@ -153,7 +143,7 @@ class OpenIDStore(object): @param salt: A random string that makes two nonces from the same server issued during the same second unique. - @type salt: str + @type salt: six.text_type @return: Whether or not the nonce was valid. diff --git a/openid/store/memstore.py b/openid/store/memstore.py index 366a596..d2a74f4 100644 --- a/openid/store/memstore.py +++ b/openid/store/memstore.py @@ -1,8 +1,11 @@ """A simple store using only in-process memory.""" +from __future__ import unicode_literals import copy import time +import six + from openid.store import nonce @@ -85,7 +88,7 @@ class MemoryStore(object): if abs(timestamp - time.time()) > nonce.SKEW: return False - anonce = (str(server_url), int(timestamp), str(salt)) + anonce = (six.text_type(server_url), int(timestamp), six.text_type(salt)) if anonce in self.nonces: return False else: diff --git a/openid/store/nonce.py b/openid/store/nonce.py index 60b3a89..f00f4e1 100644 --- a/openid/store/nonce.py +++ b/openid/store/nonce.py @@ -1,14 +1,18 @@ -__all__ = [ - 'split', - 'mkNonce', - 'checkTimestamp', -] +from __future__ import unicode_literals import string from calendar import timegm from time import gmtime, strftime, strptime, time from openid import cryptutil +from openid.oidutil import string_to_text + +__all__ = [ + 'split', + 'mkNonce', + 'checkTimestamp', +] + NONCE_CHARS = (string.ascii_letters + string.digits).encode('utf-8') @@ -25,14 +29,17 @@ 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 + @type nonce_string: six.text_type, six.binary_type is deprecated @returns: A pair of a Unix timestamp and the salt characters - @returntype: (int, str) + @returntype: (int, six.text_type) @raises ValueError: if the nonce does not start with a correctly formatted time string """ + nonce_string = string_to_text(nonce_string, + "Binary values for nonce_string are deprecated. Use text input instead.") + timestamp_str = nonce_string[:time_str_len] timestamp = timegm(strptime(timestamp_str, time_fmt)) if timestamp < 0: @@ -45,7 +52,7 @@ def checkTimestamp(nonce_string, allowed_skew=SKEW, now=None): within the allowed clock-skew of the current time? @param nonce_string: The nonce that is being checked - @type nonce_string: str + @type nonce_string: six.text_type, six.binary_type is deprecated @param allowed_skew: How many seconds should be allowed for completing the request, allowing for clock skew. @@ -84,7 +91,7 @@ def mkNonce(when=None): nonce. Defaults to the current time. @type when: int - @returntype: str + @returntype: six.text_type @returns: A string that should be usable as a one-way nonce @see: time diff --git a/openid/store/sqlstore.py b/openid/store/sqlstore.py index 339931e..1791298 100644 --- a/openid/store/sqlstore.py +++ b/openid/store/sqlstore.py @@ -7,10 +7,15 @@ Example of how to initialize a store database:: python -c 'from openid.store import sqlstore; import pysqlite2.dbapi2; sqlstore.SQLiteStore(pysqlite2.dbapi2.connect("cstore.db")).createTables()' """ +from __future__ import unicode_literals + import re import time +import six + from openid.association import Association +from openid.oidutil import string_to_text from openid.store import nonce from openid.store.interface import OpenIDStore @@ -84,19 +89,20 @@ class SQLStore(OpenIDStore): 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} - + @type associations_table: six.text_type, six.binary_type is deprecated @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} + @type nonces_table: six.text_type, six.binary_type is deprecated """ self.conn = conn self.cur = None self._statement_cache = {} + associations_table = string_to_text( + associations_table, "Binary values for associations_table are deprecated. Use text input instead.") + nonces_table = string_to_text(nonces_table, + "Binary values for nonces_table are deprecated. Use text input instead.") self._table_names = { 'associations': associations_table or self.associations_table, 'nonces': nonces_table or self.nonces_table, @@ -115,13 +121,13 @@ class SQLStore(OpenIDStore): "(Maybe it can't be imported?)") def blobDecode(self, blob): - """Convert a blob as returned by the SQL engine into a str object. + """Convert a blob as returned by the SQL engine into a binary_type object. - str -> str""" + six.binary_type -> six.binary_type""" return blob def blobEncode(self, s): - """Convert a str object into the necessary object for storing + """Convert a six.binary_type object into the necessary object for storing in the database as a blob.""" return s @@ -142,8 +148,8 @@ class SQLStore(OpenIDStore): # so this ought to be safe. def unicode_to_str(arg): - if isinstance(arg, unicode): - return str(arg) + if isinstance(arg, six.text_type): + return arg.encode('utf-8') else: return arg str_args = [unicode_to_str(i) for i in args] @@ -216,8 +222,11 @@ class SQLStore(OpenIDStore): """Get the most recent association that has been set for this server URL and handle. - str -> NoneType or Association + @type server_url: six.text_type, six.binary_type is deprecated + @rtype: Optional[Association] """ + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") + if handle is not None: self.db_get_assoc(server_url, handle) else: @@ -229,8 +238,10 @@ class SQLStore(OpenIDStore): else: associations = [] for values in rows: - assoc = Association(*values) - assoc.secret = self.blobDecode(assoc.secret) + # Decode secret before association is created + handle, secret, issued, lifetime, assoc_type = values + secret = self.blobDecode(secret) + assoc = Association(handle, secret, issued, lifetime, assoc_type) if assoc.getExpiresIn() == 0: self.txn_removeAssociation(server_url, assoc.handle) else: @@ -248,8 +259,11 @@ class SQLStore(OpenIDStore): """Remove the association for the given server URL and handle, returning whether the association existed at all. - (str, str) -> bool + (six.text_type, six.text_type) -> bool, six.binary_type is deprecated """ + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") + handle = string_to_text(handle, "Binary values for handle are deprecated. Use text input instead.") + self.db_remove_assoc(server_url, handle) return self.cur.rowcount > 0 # -1 is undefined @@ -259,7 +273,11 @@ class SQLStore(OpenIDStore): """Return whether this nonce is present, and if it is, then remove it from the set. - str -> bool""" + @type server_url: six.text_type, six.binary_type is deprecated + @rtype: bool + """ + server_url = string_to_text(server_url, "Binary values for server_url are deprecated. Use text input instead.") + if abs(timestamp - time.time()) > nonce.SKEW: return False @@ -342,7 +360,7 @@ class SQLiteStore(SQLStore): clean_nonce_sql = 'DELETE FROM %(nonces)s WHERE timestamp < ?;' def blobDecode(self, buf): - return str(buf) + return six.binary_type(buf) def blobEncode(self, s): return buffer(s) @@ -421,7 +439,7 @@ class MySQLStore(SQLStore): clean_nonce_sql = 'DELETE FROM %(nonces)s WHERE timestamp < %%s;' def blobDecode(self, blob): - if isinstance(blob, str): + if isinstance(blob, six.binary_type): # Versions of MySQLdb >= 1.2.2 return blob else: diff --git a/openid/test/discoverdata.py b/openid/test/discoverdata.py index 32d9619..04990c5 100644 --- a/openid/test/discoverdata.py +++ b/openid/test/discoverdata.py @@ -1,4 +1,6 @@ """Module to make discovery data test cases available""" +from __future__ import unicode_literals + import os.path import urlparse diff --git a/openid/test/test_association_response.py b/openid/test/test_association_response.py index 2df50f4..0e1fc5e 100644 --- a/openid/test/test_association_response.py +++ b/openid/test/test_association_response.py @@ -3,6 +3,8 @@ This duplicates some things that are covered by test_consumer, but this works for now. """ +from __future__ import unicode_literals + import unittest from testfixtures import LogCapture @@ -231,7 +233,7 @@ class TestOpenID1AssociationResponseSessionType(BaseAssocTest): class DummyAssociationSession(object): - secret = "shh! don't tell!" + secret = b"shh! don't tell!" extract_secret_called = False session_type = None diff --git a/openid/test/test_auth_request.py b/openid/test/test_auth_request.py index cc96987..7c21a78 100644 --- a/openid/test/test_auth_request.py +++ b/openid/test/test_auth_request.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import unittest from openid import message diff --git a/openid/test/test_consumer.py b/openid/test/test_consumer.py index 8e63b68..0cd6a62 100644 --- a/openid/test/test_consumer.py +++ b/openid/test/test_consumer.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import time import unittest import urlparse @@ -535,8 +537,7 @@ class TestCheckAuthResponse(TestIdRes): def _createAssoc(self): issued = time.time() lifetime = 1000 - assoc = association.Association( - 'handle', 'secret', issued, lifetime, 'HMAC-SHA1') + assoc = association.Association('handle', b'secret', issued, lifetime, 'HMAC-SHA1') store = self.consumer.store store.storeAssociation(self.server_url, assoc) assoc2 = store.getAssociation(self.server_url) @@ -918,8 +919,7 @@ class TestCheckAuthTriggered(TestIdRes): # handle that is in the message issued = time.time() lifetime = 1000 - assoc = association.Association( - 'handle', 'secret', issued, lifetime, 'HMAC-SHA1') + assoc = association.Association('handle', b'secret', issued, lifetime, 'HMAC-SHA1') self.store.storeAssociation(self.server_url, assoc) self.disableReturnToChecking() message = Message.fromPostArgs({ @@ -942,8 +942,7 @@ class TestCheckAuthTriggered(TestIdRes): issued = time.time() - 10 lifetime = 0 handle = 'handle' - assoc = association.Association( - handle, 'secret', issued, lifetime, 'HMAC-SHA1') + assoc = association.Association(handle, b'secret', issued, lifetime, 'HMAC-SHA1') self.assertLessEqual(assoc.expiresIn, 0) self.store.storeAssociation(self.server_url, assoc) @@ -962,14 +961,12 @@ class TestCheckAuthTriggered(TestIdRes): good_issued = time.time() - 10 good_handle = 'handle' - good_assoc = association.Association( - good_handle, 'secret', good_issued, lifetime, 'HMAC-SHA1') + good_assoc = association.Association(good_handle, b'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') + bad_assoc = association.Association(bad_handle, b'secret', bad_issued, lifetime, 'HMAC-SHA1') self.store.storeAssociation(self.server_url, bad_assoc) query = { diff --git a/openid/test/test_discover.py b/openid/test/test_discover.py index f634b12..414f7ed 100644 --- a/openid/test/test_discover.py +++ b/openid/test/test_discover.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals + import os.path import unittest from urlparse import urlsplit diff --git a/openid/test/test_extension.py b/openid/test/test_extension.py index 640f11a..f851a0f 100644 --- a/openid/test/test_extension.py +++ b/openid/test/test_extension.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import unittest from openid import extension, message diff --git a/openid/test/test_fetchers.py b/openid/test/test_fetchers.py index 57b9089..5594a52 100644 --- a/openid/test/test_fetchers.py +++ b/openid/test/test_fetchers.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import socket import unittest import urllib2 @@ -74,11 +76,11 @@ def test_fetcher(fetcher, exc, server): def plain(path, code): path = '/' + path expected = fetchers.HTTPResponse( - geturl(path), code, expected_headers, path) + geturl(path), code, expected_headers, path.encode('utf-8')) return (path, expected) expect_success = fetchers.HTTPResponse( - geturl('/success'), 200, expected_headers, '/success') + geturl('/success'), 200, expected_headers, b'/success') cases = [ ('/success', expect_success), ('/301redirect', expect_success), @@ -222,7 +224,7 @@ class FetcherTestHandler(BaseHTTPRequestHandler): for k, v in extra_headers: self.send_header(k, v) self.end_headers() - self.wfile.write(body) + self.wfile.write(body.encode('utf-8')) self.wfile.close() def finish(self): @@ -384,19 +386,19 @@ class TestRequestsFetcher(unittest.TestCase): def test_get(self): # Test GET response with responses.RequestsMock() as rsps: - rsps.add(responses.GET, 'http://example.cz/', status=200, body='BODY', + rsps.add(responses.GET, 'http://example.cz/', status=200, body=b'BODY', headers={'Content-Type': 'text/plain'}) response = self.fetcher.fetch('http://example.cz/') - expected = fetchers.HTTPResponse('http://example.cz/', 200, {'Content-Type': 'text/plain'}, 'BODY') + expected = fetchers.HTTPResponse('http://example.cz/', 200, {'Content-Type': 'text/plain'}, b'BODY') assertResponse(expected, response) def test_post(self): # Test POST response with responses.RequestsMock() as rsps: - rsps.add(responses.POST, 'http://example.cz/', status=200, body='BODY', + rsps.add(responses.POST, 'http://example.cz/', status=200, body=b'BODY', headers={'Content-Type': 'text/plain'}) response = self.fetcher.fetch('http://example.cz/', body='key=value') - expected = fetchers.HTTPResponse('http://example.cz/', 200, {'Content-Type': 'text/plain'}, 'BODY') + expected = fetchers.HTTPResponse('http://example.cz/', 200, {'Content-Type': 'text/plain'}, b'BODY') assertResponse(expected, response) def test_redirect(self): @@ -404,19 +406,19 @@ class TestRequestsFetcher(unittest.TestCase): with responses.RequestsMock() as rsps: rsps.add(responses.GET, 'http://example.cz/redirect/', status=302, headers={'Location': 'http://example.cz/target/'}) - rsps.add(responses.GET, 'http://example.cz/target/', status=200, body='BODY', + rsps.add(responses.GET, 'http://example.cz/target/', status=200, body=b'BODY', headers={'Content-Type': 'text/plain'}) response = self.fetcher.fetch('http://example.cz/redirect/') - expected = fetchers.HTTPResponse('http://example.cz/target/', 200, {'Content-Type': 'text/plain'}, 'BODY') + expected = fetchers.HTTPResponse('http://example.cz/target/', 200, {'Content-Type': 'text/plain'}, b'BODY') assertResponse(expected, response) def test_error(self): # Test error responses - returned as obtained with responses.RequestsMock() as rsps: - rsps.add(responses.GET, 'http://example.cz/error/', status=500, body='BODY', + rsps.add(responses.GET, 'http://example.cz/error/', status=500, body=b'BODY', headers={'Content-Type': 'text/plain'}) response = self.fetcher.fetch('http://example.cz/error/') - expected = fetchers.HTTPResponse('http://example.cz/error/', 500, {'Content-Type': 'text/plain'}, 'BODY') + expected = fetchers.HTTPResponse('http://example.cz/error/', 500, {'Content-Type': 'text/plain'}, b'BODY') assertResponse(expected, response) def test_invalid_url(self): diff --git a/openid/test/test_htmldiscover.py b/openid/test/test_htmldiscover.py index b4caeb3..cb354a6 100644 --- a/openid/test/test_htmldiscover.py +++ b/openid/test/test_htmldiscover.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import unittest from openid.consumer.discover import OpenIDServiceEndpoint diff --git a/openid/test/test_negotiation.py b/openid/test/test_negotiation.py index 6c4cf1f..9b23233 100644 --- a/openid/test/test_negotiation.py +++ b/openid/test/test_negotiation.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import unittest from testfixtures import LogCapture, StringComparison @@ -124,8 +126,7 @@ class TestOpenID2SessionNegotiation(unittest.TestCase): 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') + assoc = association.Association('handle', b'secret', 'issued', 10000, 'HMAC-SHA1') self.consumer.return_messages = [msg, assoc] with LogCapture() as logbook: @@ -157,8 +158,7 @@ class TestOpenID2SessionNegotiation(unittest.TestCase): 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') + assoc = association.Association('handle', b'secret', 'issued', 10000, 'HMAC-SHA1') self.consumer.return_messages = [assoc] with LogCapture() as logbook: @@ -241,8 +241,7 @@ class TestOpenID1SessionNegotiation(unittest.TestCase): 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') + assoc = association.Association('handle', b'secret', 'issued', 10000, 'HMAC-SHA1') self.consumer.return_messages = [msg, assoc] with LogCapture() as logbook: @@ -251,8 +250,7 @@ class TestOpenID1SessionNegotiation(unittest.TestCase): ('openid.consumer.consumer', 'ERROR', StringComparison('Server error when requesting an association .*'))) def testValid(self): - assoc = association.Association( - 'handle', 'secret', 'issued', 10000, 'HMAC-SHA1') + assoc = association.Association('handle', b'secret', 'issued', 10000, 'HMAC-SHA1') self.consumer.return_messages = [assoc] with LogCapture() as logbook: diff --git a/openid/test/test_nonce.py b/openid/test/test_nonce.py index 010178f..d274611 100644 --- a/openid/test/test_nonce.py +++ b/openid/test/test_nonce.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import re import unittest diff --git a/openid/test/test_rpverify.py b/openid/test/test_rpverify.py index cbcb6df..4e707d5 100644 --- a/openid/test/test_rpverify.py +++ b/openid/test/test_rpverify.py @@ -1,7 +1,5 @@ -"""Unit tests for verification of return_to URLs for a realm -""" - -__all__ = ['TestBuildDiscoveryURL'] +"""Unit tests for verification of return_to URLs for a realm.""" +from __future__ import unicode_literals import unittest @@ -11,6 +9,8 @@ from openid.server import trustroot from openid.yadis import services from openid.yadis.discover import DiscoveryFailure, DiscoveryResult +__all__ = ['TestBuildDiscoveryURL'] + class TestBuildDiscoveryURL(unittest.TestCase): """Tests for building the discovery URL from a realm and a @@ -75,7 +75,7 @@ class TestExtractReturnToURLs(unittest.TestCase): self.assertDiscoveryFailure('>') def test_noEntries(self): - self.assertReturnURLs('''\ + self.assertReturnURLs(b'''\ <?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" @@ -86,7 +86,7 @@ class TestExtractReturnToURLs(unittest.TestCase): ''', []) def test_noReturnToEntries(self): - self.assertReturnURLs('''\ + self.assertReturnURLs(b'''\ <?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" @@ -101,7 +101,7 @@ class TestExtractReturnToURLs(unittest.TestCase): ''', []) def test_oneEntry(self): - self.assertReturnURLs('''\ + self.assertReturnURLs(b'''\ <?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" @@ -116,7 +116,7 @@ class TestExtractReturnToURLs(unittest.TestCase): ''', ['http://rp.example.com/return']) def test_twoEntries(self): - self.assertReturnURLs('''\ + self.assertReturnURLs(b'''\ <?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" @@ -135,7 +135,7 @@ class TestExtractReturnToURLs(unittest.TestCase): ''', ['http://rp.example.com/return', 'http://other.rp.example.com/return']) def test_twoEntries_withOther(self): - self.assertReturnURLs('''\ + self.assertReturnURLs(b'''\ <?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" diff --git a/openid/test/test_server.py b/openid/test/test_server.py index 0ce5ea8..149508a 100644 --- a/openid/test/test_server.py +++ b/openid/test/test_server.py @@ -1,5 +1,7 @@ """Tests for openid.server. """ +from __future__ import unicode_literals + import unittest import warnings from functools import partial @@ -667,9 +669,7 @@ class TestEncode(unittest.TestCase): self.assertEqual(webresponse.body, body) def test_checkauthReply(self): - request = server.CheckAuthRequest('a_sock_monkey', - 'siggggg', - []) + request = server.CheckAuthRequest('a_sock_monkey', 'siggggg') response = server.OpenIDResponse(request) response.fields = Message.fromOpenIDArgs({ 'is_valid': 'true', @@ -723,8 +723,7 @@ class TestSigningEncode(unittest.TestCase): assoc_handle = '{bicycle}{shed}' self.store.storeAssociation( self._normal_key, - association.Association.fromExpiresIn(60, assoc_handle, - 'sekrit', 'HMAC-SHA1')) + association.Association.fromExpiresIn(60, assoc_handle, b'sekrit', 'HMAC-SHA1')) self.request.assoc_handle = assoc_handle webresponse = self.encode(self.response) self.assertEqual(webresponse.code, server.HTTP_REDIRECT) @@ -980,7 +979,7 @@ class TestCheckID(unittest.TestCase): msg.setArg(OPENID_NS, 'mode', 'checkid_setup') msg.setArg(OPENID_NS, 'assoc_handle', 'bogus') - self.assertRaises(server.ProtocolError, server.CheckIDRequest.fromMessage, msg, self.server) + self.assertRaises(server.ProtocolError, server.CheckIDRequest.fromMessage, msg, self.op_endpoint) def test_fromMessageClaimedIDWithoutIdentityOpenID2(self): name = 'https://example.myopenid.com' @@ -990,7 +989,7 @@ class TestCheckID(unittest.TestCase): msg.setArg(OPENID_NS, 'return_to', 'http://invalid:8000/rt') msg.setArg(OPENID_NS, 'claimed_id', name) - self.assertRaises(server.ProtocolError, server.CheckIDRequest.fromMessage, msg, self.server) + self.assertRaises(server.ProtocolError, server.CheckIDRequest.fromMessage, msg, self.op_endpoint) def test_fromMessageIdentityWithoutClaimedIDOpenID2(self): name = 'https://example.myopenid.com' @@ -1000,7 +999,7 @@ class TestCheckID(unittest.TestCase): msg.setArg(OPENID_NS, 'return_to', 'http://invalid:8000/rt') msg.setArg(OPENID_NS, 'identity', name) - self.assertRaises(server.ProtocolError, server.CheckIDRequest.fromMessage, msg, self.server) + self.assertRaises(server.ProtocolError, server.CheckIDRequest.fromMessage, msg, self.op_endpoint) def test_trustRootOpenID1(self): """Ignore openid.realm in OpenID 1""" @@ -1637,7 +1636,7 @@ class TestServer(unittest.TestCase): self.assertRaises(server.ProtocolError, server.AssociateRequest.fromMessage, msg) def test_checkAuth(self): - request = server.CheckAuthRequest('arrrrrf', '0x3999', []) + request = server.CheckAuthRequest('arrrrrf', '0x3999') response = self.server.openid_check_authentication(request) self.assertTrue(response.fields.hasKey(OPENID_NS, "is_valid")) @@ -1654,8 +1653,7 @@ class TestSignatory(unittest.TestCase): assoc_handle = '{assoc}{lookatme}' self.store.storeAssociation( self._normal_key, - association.Association.fromExpiresIn(60, assoc_handle, - 'sekrit', 'HMAC-SHA1')) + association.Association.fromExpiresIn(60, assoc_handle, b'sekrit', 'HMAC-SHA1')) request.assoc_handle = assoc_handle response = server.OpenIDResponse(request) response.fields = Message.fromOpenIDArgs({ @@ -1708,8 +1706,7 @@ class TestSignatory(unittest.TestCase): assoc_handle = '{assoc}{lookatme}' self.store.storeAssociation( self._normal_key, - association.Association.fromExpiresIn(-10, assoc_handle, - 'sekrit', 'HMAC-SHA1')) + association.Association.fromExpiresIn(-10, assoc_handle, b'sekrit', 'HMAC-SHA1')) self.assertTrue(self.store.getAssociation(self._normal_key, assoc_handle)) request.assoc_handle = assoc_handle @@ -1772,8 +1769,7 @@ class TestSignatory(unittest.TestCase): def test_verify(self): assoc_handle = '{vroom}{zoom}' - assoc = association.Association.fromExpiresIn( - 60, assoc_handle, 'sekrit', 'HMAC-SHA1') + assoc = association.Association.fromExpiresIn(60, assoc_handle, b'sekrit', 'HMAC-SHA1') self.store.storeAssociation(self._dumb_key, assoc) @@ -1792,8 +1788,7 @@ class TestSignatory(unittest.TestCase): def test_verifyBadSig(self): assoc_handle = '{vroom}{zoom}' - assoc = association.Association.fromExpiresIn( - 60, assoc_handle, 'sekrit', 'HMAC-SHA1') + assoc = association.Association.fromExpiresIn(60, assoc_handle, b'sekrit', 'HMAC-SHA1') self.store.storeAssociation(self._dumb_key, assoc) @@ -1826,8 +1821,7 @@ class TestSignatory(unittest.TestCase): 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') + assoc = association.Association.fromExpiresIn(60, assoc_handle, b'sekrit', 'HMAC-SHA1') self.store.storeAssociation(self._dumb_key, assoc) @@ -1891,16 +1885,14 @@ class TestSignatory(unittest.TestCase): def makeAssoc(self, dumb, lifetime=60): assoc_handle = '{bling}' - assoc = association.Association.fromExpiresIn(lifetime, assoc_handle, - 'sekrit', 'HMAC-SHA1') + assoc = association.Association.fromExpiresIn(lifetime, assoc_handle, b'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') + assoc = association.Association.fromExpiresIn(60, assoc_handle, b'sekrit', 'HMAC-SHA1') self.store.storeAssociation(self._dumb_key, assoc) assoc = self.signatory.getAssociation(assoc_handle, dumb=True) diff --git a/openid/test/test_storetest.py b/openid/test/test_storetest.py index 898a406..ef377d1 100644 --- a/openid/test/test_storetest.py +++ b/openid/test/test_storetest.py @@ -1,4 +1,6 @@ """Test `openid.store` module.""" +from __future__ import unicode_literals + import os import random import socket diff --git a/openid/test/test_symbol.py b/openid/test/test_symbol.py index a115937..971b548 100644 --- a/openid/test/test_symbol.py +++ b/openid/test/test_symbol.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import unittest from openid import oidutil diff --git a/openid/test/test_trustroot.py b/openid/test/test_trustroot.py index a470207..9d3e3f3 100644 --- a/openid/test/test_trustroot.py +++ b/openid/test/test_trustroot.py @@ -1,10 +1,12 @@ +from __future__ import unicode_literals + import os import unittest from openid.server.trustroot import TrustRoot with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'trustroot.txt')) as test_data_file: - trustroot_test_data = test_data_file.read() + trustroot_test_data = test_data_file.read().decode('utf-8') class ParseTest(unittest.TestCase): diff --git a/openid/test/test_verifydisco.py b/openid/test/test_verifydisco.py index 12318f3..1217c65 100644 --- a/openid/test/test_verifydisco.py +++ b/openid/test/test_verifydisco.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import unittest from testfixtures import LogCapture, StringComparison diff --git a/openid/test/utils.py b/openid/test/utils.py index 09ae1a9..02199e1 100644 --- a/openid/test/utils.py +++ b/openid/test/utils.py @@ -1,4 +1,6 @@ """Test utilities.""" +from __future__ import unicode_literals + from openid import message diff --git a/openid/urinorm.py b/openid/urinorm.py index abce405..4e1530e 100644 --- a/openid/urinorm.py +++ b/openid/urinorm.py @@ -5,6 +5,8 @@ import string from urllib import quote, unquote, urlencode from urlparse import parse_qsl, urlsplit, urlunsplit +import six + from .oidutil import string_to_text @@ -90,7 +92,8 @@ def urinorm(uri): hostname = unquote(hostname) # Quote IDN domain names try: - hostname = hostname.encode('idna') + # hostname: str --[idna]--> bytes --[utf-8]--> str + hostname = hostname.encode('idna').decode('utf-8') except ValueError as error: raise ValueError('Invalid hostname {!r}: {}'.format(hostname, error)) _check_disallowed_characters(hostname, 'hostname') @@ -103,7 +106,7 @@ def urinorm(uri): netloc = hostname if port: - netloc = netloc + ':' + str(port) + netloc = netloc + ':' + six.text_type(port) userinfo_chunks = [i for i in (split_uri.username, split_uri.password) if i is not None] if userinfo_chunks: userinfo = ':'.join(userinfo_chunks) |