def getAssociationFilename(self, server_url, handle): """Create a unique filename for a given server url and handle. This implementation does not assume anything about the format of the handle. The filename that is returned will contain the domain name from the server URL for ease of human inspection of the data directory. (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) proto, rest = server_url.split('://', 1) domain = _filenameEscape(rest.split('/', 1)[0]) url_hash = _safe64(server_url) if handle: handle_hash = _safe64(handle) else: handle_hash = '' filename = '%s-%s-%s-%s' % (proto, domain, url_hash, handle_hash) return os.path.join(self.association_dir, filename)
def matchTypes(accept_types, have_types): """Given the result of parsing an Accept: header, and the available MIME types, return the acceptable types with their quality markdowns. For example: >>> acceptable = parseAcceptHeader('text/html, text/plain; q=0.5') >>> matchTypes(acceptable, ['text/plain', 'text/html', 'image/jpeg']) [('text/html', 1.0), ('text/plain', 0.5)] Type signature: ([(six.text_type, six.text_type, float)], [six.text_type]) -> [(six.text_type, float)] """ if not accept_types: # Accept all of them default = 1 else: default = 0 match_main = {} match_sub = {} for (main, sub, qvalue) in accept_types: main = string_to_text( main, "Binary values for matchTypes accept_types are deprecated. Use text input instead." ) sub = string_to_text( sub, "Binary values for matchTypes accept_types are deprecated. Use text input instead." ) if main == '*': default = max(default, qvalue) continue elif sub == '*': match_main[main] = max(match_main.get(main, 0), qvalue) else: match_sub[(main, sub)] = max(match_sub.get((main, sub), 0), qvalue) accepted_list = [] order_maintainer = 0 for mtype in have_types: mtype = string_to_text( mtype, "Binary values for matchTypes have_types are deprecated. Use text input instead." ) main, sub = mtype.split('/') if (main, sub) in match_sub: quality = match_sub[(main, sub)] else: quality = match_main.get(main, default) if quality: accepted_list.append( (1 - quality, order_maintainer, quality, mtype)) order_maintainer += 1 accepted_list.sort() return [(match, q) for (_, _, q, match) in accepted_list]
def txn_removeAssociation(self, server_url, handle): """Remove the association for the given server URL and handle, returning whether the association existed at all. (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
def __init__(self, conn, associations_table=None, nonces_table=None): """ This creates a new SQLStore instance. It requires an established database connection be given to it, and it allows overriding the default table names. @param conn: This must be an established connection to a database of the correct type for the SQLStore subclass you're using. @type conn: A python database API compatible connection object. @param associations_table: This is an optional parameter to specify the name of the table used for storing associations. The default value is specified in C{L{SQLStore.associations_table}}. @type associations_table: 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: 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, } self.max_nonce_age = 6 * 60 * 60 # Six hours, in seconds # DB API extension: search for "Connection Attributes .Error, # .ProgrammingError, etc." in # http://www.python.org/dev/peps/pep-0249/ if hasattr(self.conn, 'IntegrityError') and hasattr( self.conn, 'OperationalError'): self.exceptions = self.conn if not (hasattr(self.exceptions, 'IntegrityError') and hasattr(self.exceptions, 'OperationalError')): raise RuntimeError("Error using database connection module " "(Maybe it can't be imported?)")
def removeAssociation(self, server_url, handle): """Remove an association if it exists. Do nothing if it does not. (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 else: filename = self.getAssociationFilename(server_url, handle) return _removeIfPresent(filename)
def parseExtensionArgs(self, args, strict=False): """Parse the unqualified simple registration request parameters and add them to this object. This method is essentially the inverse of C{L{getExtensionArgs}}. This method restores the serialized simple registration request fields. If you are extracting arguments from a standard OpenID checkid_* request, you probably want to use C{L{fromOpenIDRequest}}, which will extract the sreg namespace and arguments from the OpenID request. This method is intended for cases where the OpenID server needs more control over how the arguments are parsed than that method provides. >>> args = message.getArgs(ns_uri) >>> request.parseExtensionArgs(args) @param args: The unqualified simple registration arguments @type args: Dict[six.text_type, six.text_type], six.binary_type is deprecated @param strict: Whether requests with fields that are not defined in the simple registration specification should be tolerated (and ignored) @type strict: bool @returns: None; updates this object """ for list_name in ['required', 'optional']: required = (list_name == 'required') items = args.get(list_name) if items: items = string_to_text( items, "Binary values for args are deprecated. Use text input instead." ) for field_name in items.split(','): try: self.requestField(field_name, required, strict) except ValueError: if strict: raise policy_url = args.get('policy_url') if policy_url is not None: policy_url = string_to_text( args.get('policy_url'), "Binary values for args are deprecated. Use text input instead." ) self.policy_url = policy_url
def __init__(self, conn, associations_table=None, nonces_table=None): """ This creates a new SQLStore instance. It requires an established database connection be given to it, and it allows overriding the default table names. @param conn: This must be an established connection to a database of the correct type for the SQLStore subclass you're using. @type conn: A python database API compatible connection object. @param associations_table: This is an optional parameter to specify the name of the table used for storing associations. The default value is specified in C{L{SQLStore.associations_table}}. @type associations_table: 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: 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, } self.max_nonce_age = 6 * 60 * 60 # Six hours, in seconds # DB API extension: search for "Connection Attributes .Error, # .ProgrammingError, etc." in # http://www.python.org/dev/peps/pep-0249/ if hasattr(self.conn, 'IntegrityError') and hasattr(self.conn, 'OperationalError'): self.exceptions = self.conn if not (hasattr(self.exceptions, 'IntegrityError') and hasattr(self.exceptions, 'OperationalError')): raise RuntimeError("Error using database connection module " "(Maybe it can't be imported?)")
def queryURL(self, xri, service_type=None): """Build a URL to query the proxy resolver. @param xri: An XRI to resolve. @type xri: six.text_type @param service_type: The service type to resolve, if you desire service endpoint selection. A service type is a URI. @type service_type: Optional[six.text_type], six.binary_type is deprecated @returns: a URL @returntype: six.text_type """ # Trim off the xri:// prefix. The proxy resolver didn't accept it # when this code was written, but that may (or may not) change for # XRI Resolution 2.0 Working Draft 11. qxri = toURINormal(xri)[6:] hxri = self.proxy_url + qxri args = { # XXX: If the proxy resolver will ensure that it doesn't return # bogus CanonicalIDs (as per Steve's message of 15 Aug 2006 # 11:13:42), then we could ask for application/xrd+xml instead, # which would give us a bit less to process. '_xrd_r': 'application/xrds+xml', } if service_type: service_type = string_to_text(service_type, "Binary values for service_type are deprecated. Use text input instead.") args['_xrd_t'] = service_type else: # Don't perform service endpoint selection. args['_xrd_r'] += ';sep=false' query = _appendArgs(hxri, args) return query
def requestFields(self, field_names, required=False, strict=False): """Add the given list of fields to the request @param field_names: The simple registration data fields to request @type field_names: List[six.text_type], six.binary_type is deprecated @param required: Whether these values should be presented to the user as required @param strict: whether to raise an exception when a field is added to a request more than once @raise ValueError: when a field requested is not a simple registration field or strict is set and a field was requested more than once """ if isinstance(field_names, six.string_types): raise TypeError('Fields should be passed as a list of ' 'strings (not %r)' % (type(field_names), )) for field_name in field_names: field_name = string_to_text( field_name, "Binary values for field_names are deprecated. Use text input instead." ) self.requestField(field_name, required, strict=strict)
def getSingle(self, type_uri, default=None): """Get a single value for an attribute. If no value was sent for this attribute, use the supplied default. If there is more than one value for this attribute, this method will fail. @param type_uri: The URI for the attribute @type type_uri: six.text_type, six.binary_type is deprecated @param default: The value to return if the attribute was not sent in the fetch_response. @returns: The value of the attribute in the fetch_response message, or the default supplied @rtype: six.text_type or NoneType @raises ValueError: If there is more than one value for this parameter in the fetch_response message. @raises KeyError: If the attribute was not sent in this response """ type_uri = string_to_text(type_uri, "Binary values for type_uri are deprecated. Use text input instead.") values = self.data.get(type_uri) if not values: return default elif len(values) == 1: return values[0] else: raise AXError( 'More than one value present for %r' % (type_uri,))
def extractResponse(cls, request, data): """Take a C{L{SRegRequest}} and a dictionary of simple registration values and create a C{L{SRegResponse}} object containing that data. @param request: The simple registration request object @type request: SRegRequest @param data: The simple registration data for this response, as a dictionary from unqualified simple registration field name to string (unicode) value. For instance, the nickname should be stored under the key 'nickname'. @type data: Dict[six.text_type, six.text_type], six.binary_type is deprecated @returns: a simple registration response object @rtype: SRegResponse """ self = cls() self.ns_uri = request.ns_uri for field in request.allRequestedFields(): value = data.get(field) if value is not None: value = string_to_text( value, "Binary values for data are deprecated. Use text input instead." ) self.data[field] = value return self
def toTypeURIs(namespace_map, alias_list_s): """Given a namespace mapping and a string containing a comma-separated list of namespace aliases, return a list of type URIs that correspond to those aliases. @param namespace_map: The mapping from namespace URI to alias @type namespace_map: openid.message.NamespaceMap @param alias_list_s: The string containing the comma-separated list of aliases. May also be None for convenience. @type alias_list_s: Optional[six.text_type], six.binary_type is deprecated @returns: The list of namespace URIs that corresponds to the supplied list of aliases. If the string was zero-length or None, an empty list will be returned. @raise KeyError: If an alias is present in the list of aliases but is not present in the namespace map. """ uris = [] if alias_list_s: alias_list_s = string_to_text(alias_list_s, "Binary values for alias_list_s are deprecated. Use text input instead.") for alias in alias_list_s.split(','): type_uri = namespace_map.getNamespaceURI(alias) if type_uri is None: raise KeyError( 'No type is defined for attribute name %r' % (alias,)) else: uris.append(type_uri) return uris
def txn_getAssociation(self, server_url, handle=None): """Get the most recent association that has been set for this server URL and handle. @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: self.db_get_assocs(server_url) rows = self.cur.fetchall() if len(rows) == 0: return None else: associations = [] for values in rows: # 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: associations.append((assoc.issued, assoc)) if associations: associations.sort() return associations[-1][1] else: return None
def validateURL(self, url): """ Validates a URL against this trust root. @param url: The URL to check @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: return False proto, host, port, path = url_parts if proto != self.proto: return False if port != self.port: return False if '*' in host: return False if not self.wildcard: if host != self.host: return False elif ((not host.endswith(self.host)) and ('.' + host) != self.host): return False if path != self.path: path_len = len(self.path) trust_prefix = self.path[:path_len] url_prefix = path[:path_len] # must be equal up to the length of the path, at least if trust_prefix != url_prefix: return False # These characters must be on the boundary between the end # of the trust root's path and the start of the URL's # path. if '?' in self.path: allowed = '&' else: allowed = '?/' return (self.path[-1] in allowed or path[path_len] in allowed) return True
def test_binary_input(self): warning_msg = 'Conversion warning' with ShouldWarn(DeprecationWarning(warning_msg)): warnings.simplefilter('always') result = string_to_text('ěščřž'.encode('utf-8'), warning_msg) self.assertIsInstance(result, six.text_type) self.assertEqual(result, 'ěščřž')
def parseExtensionArgs(self, args, strict=False): """Parse the unqualified simple registration request parameters and add them to this object. This method is essentially the inverse of C{L{getExtensionArgs}}. This method restores the serialized simple registration request fields. If you are extracting arguments from a standard OpenID checkid_* request, you probably want to use C{L{fromOpenIDRequest}}, which will extract the sreg namespace and arguments from the OpenID request. This method is intended for cases where the OpenID server needs more control over how the arguments are parsed than that method provides. >>> args = message.getArgs(ns_uri) >>> request.parseExtensionArgs(args) @param args: The unqualified simple registration arguments @type args: Dict[six.text_type, six.text_type], six.binary_type is deprecated @param strict: Whether requests with fields that are not defined in the simple registration specification should be tolerated (and ignored) @type strict: bool @returns: None; updates this object """ for list_name in ['required', 'optional']: required = (list_name == 'required') items = args.get(list_name) if items: items = string_to_text(items, "Binary values for args are deprecated. Use text input instead.") for field_name in items.split(','): try: self.requestField(field_name, required, strict) except ValueError: if strict: raise policy_url = args.get('policy_url') if policy_url is not None: policy_url = string_to_text(args.get('policy_url'), "Binary values for args are deprecated. Use text input instead.") self.policy_url = policy_url
def getAssociation(self, server_url, handle=None): """Retrieve an association. If no handle is specified, return the association with the latest expiration. (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 = '' # The filename with the empty handle is a prefix of all other # associations for the given server URL. filename = self.getAssociationFilename(server_url, handle) if handle: return self._getAssociation(filename) else: association_files = os.listdir(self.association_dir) matching_files = [] # strip off the path to do the comparison name = os.path.basename(filename) for association_file in association_files: if association_file.startswith(name): matching_files.append(association_file) matching_associations = [] # read the matching files and sort by time issued for name in matching_files: full_name = os.path.join(self.association_dir, name) association = self._getAssociation(full_name) if association is not None: matching_associations.append( (association.issued, association)) matching_associations.sort() # return the most recently issued one. if matching_associations: (_, assoc) = matching_associations[-1] return assoc else: return None
def validateURL(self, url): """ Validates a URL against this trust root. @param url: The URL to check @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: return False proto, host, port, path = url_parts if proto != self.proto: return False if port != self.port: return False if '*' in host: return False if not self.wildcard: if host != self.host: return False elif ((not host.endswith(self.host)) and ('.' + host) != self.host): return False if path != self.path: path_len = len(self.path) trust_prefix = self.path[:path_len] url_prefix = path[:path_len] # must be equal up to the length of the path, at least if trust_prefix != url_prefix: return False # These characters must be on the boundary between the end # of the trust root's path and the start of the URL's # path. if '?' in self.path: allowed = '&' else: allowed = '?/' return (self.path[-1] in allowed or path[path_len] in allowed) return True
def findOPLocalIdentifier(service_element, type_uris): """Find the OP-Local Identifier for this xrd:Service element. This considers openid:Delegate to be a synonym for xrd:LocalID if both OpenID 1.X and OpenID 2.0 types are present. If only OpenID 1.X is present, it returns the value of openid:Delegate. If only OpenID 2.0 is present, it returns the value of xrd:LocalID. If there is more than one LocalID tag and the values are different, it raises a DiscoveryFailure. This is also triggered when the xrd:LocalID and openid:Delegate tags are different. @param service_element: The xrd:Service element @type service_element: ElementTree.Node @param type_uris: The xrd:Type values present in this service element. This function could extract them, but higher level code needs to do that anyway. @type type_uris: List[six.text_type], six.binary_type is deprecated @raises DiscoveryFailure: when discovery fails. @returns: The OP-Local Identifier for this service element, if one is present, or None otherwise. @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 = [] if (OPENID_1_1_TYPE in type_uris or OPENID_1_0_TYPE in type_uris): local_id_tags.append(nsTag(OPENID_1_0_NS, 'Delegate')) if OPENID_2_0_TYPE in type_uris: local_id_tags.append(nsTag(XRD_NS_2_0, 'LocalID')) # Walk through all the matching tags and make sure that they all # have the same value local_id = None for local_id_tag in local_id_tags: for local_id_element in service_element.findall(local_id_tag): if local_id is None: local_id = local_id_element.text elif local_id != local_id_element.text: format = 'More than one %r tag found in one service element' message = format % (local_id_tag, ) raise DiscoveryFailure(message, None) return local_id
def hmacSha256(key, text): """ Return a SHA256 HMAC. @type key: six.binary_type @type text: six.text_type, six.binary_type is deprecated @rtype: six.binary_type """ text = string_to_text( text, "Binary values for text are deprecated. Use text input instead.") return hmac.new(key, text.encode('utf-8'), sha256_module).digest()
def parse(cls, trust_root): """ This method creates a C{L{TrustRoot}} instance from the given input, if possible. @param trust_root: This is the trust root to parse into a C{L{TrustRoot}} object. @type trust_root: six.text_type, six.binary_type is deprecated @return: A C{L{TrustRoot}} instance if trust_root parses as a trust root, C{None} otherwise. @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 proto, host, port, path = url_parts # check for URI fragment if path.find('#') != -1: return None # extract wildcard if it is there if host.find('*', 1) != -1: # wildcard must be at start of domain: *.foo.com, not foo.*.com return None if host.startswith('*'): # Starts with star, so must have a dot after it (if a # domain is specified) if len(host) > 1 and host[1] != '.': return None host = host[1:] wilcard = True else: wilcard = False # we have a valid trust root tr = cls(trust_root, proto, wilcard, host, port, path) return tr
def generateAcceptHeader(*elements): """Generate an accept header value [six.text_type or (six.text_type, float)] -> six.text_type """ parts = [] for element in elements: if isinstance(element, six.string_types): qs = "1.0" mtype = string_to_text( element, "Binary values for generateAcceptHeader are deprecated. Use text input instead." ) else: mtype, q = element mtype = string_to_text( mtype, "Binary values for generateAcceptHeader are deprecated. Use text input instead." ) q = float(q) if q > 1 or q <= 0: raise ValueError('Invalid preference factor: %r' % q) qs = '%0.1f' % (q, ) parts.append((qs, mtype)) parts.sort() chunks = [] for q, mtype in parts: if q == '1.0': chunks.append(mtype) else: chunks.append('%s; q=%s' % (mtype, q)) return ', '.join(chunks)
def matchTypes(self, type_uris): """Query this endpoint to see if it has any of the given type URIs. This is useful for implementing other endpoint classes that e.g. need to check for the presence of multiple versions of a single protocol. @param type_uris: The URIs that you wish to check @type type_uris: Iterable[six.text_type], six.binary_type is deprecated @return: all types that are in both in type_uris and self.type_uris """ type_uris = [string_to_text(u, "Binary values for matchTypes are deprecated. Use text input instead.") for u in type_uris] return [uri for uri in type_uris if uri in self.type_uris]
def parse(cls, trust_root): """ This method creates a C{L{TrustRoot}} instance from the given input, if possible. @param trust_root: This is the trust root to parse into a C{L{TrustRoot}} object. @type trust_root: six.text_type, six.binary_type is deprecated @return: A C{L{TrustRoot}} instance if trust_root parses as a trust root, C{None} otherwise. @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 proto, host, port, path = url_parts # check for URI fragment if path.find('#') != -1: return None # extract wildcard if it is there if host.find('*', 1) != -1: # wildcard must be at start of domain: *.foo.com, not foo.*.com return None if host.startswith('*'): # Starts with star, so must have a dot after it (if a # domain is specified) if len(host) > 1 and host[1] != '.': return None host = host[1:] wilcard = True else: wilcard = False # we have a valid trust root tr = cls(trust_root, proto, wilcard, host, port, path) return tr
def getAcceptable(accept_header, have_types): """Parse the accept header and return a list of available types in preferred order. If a type is unacceptable, it will not be in the resulting list. This is a convenience wrapper around matchTypes and parseAcceptHeader. (six.text_type, [six.text_type]) -> [six.text_type] """ accept_header = string_to_text( accept_header, "Binary values for getAcceptable accept_header are deprecated. Use text input instead." ) accepted = parseAcceptHeader(accept_header) preferred = matchTypes(accepted, have_types) return [mtype for (mtype, _) in preferred]
def iriToURI(iri): """Transform an IRI to a URI by escaping unicode. According to RFC 3987, section 3.1, "Mapping of IRIs to URIs" @type iri: six.text_type, six.binary_type deprecated. @rtype: six.text_type """ iri = string_to_text(iri, "Binary input for iriToURI is deprecated. Use text input instead.") # This is hackish. `quote` requires `str` in both py27 and py3+. if isinstance(iri, str): # Python 3 branch return quote(iri, GEN_DELIMS + SUB_DELIMS + PERCENT_ENCODING_CHARACTER) else: # Python 2 branch return quote(iri.encode('utf-8'), (GEN_DELIMS + SUB_DELIMS + PERCENT_ENCODING_CHARACTER).encode('utf-8')).decode('utf-8')
def discoverYadis(uri): """Discover OpenID services for a URI. Tries Yadis and falls back on old-style <link rel='...'> discovery if Yadis fails. @param uri: normalized identity URL @type uri: six.text_type, six.binary_type is deprecated @return: (claimed_id, services) @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 # bother to catch it. response = yadisDiscover(uri) yadis_url = response.normalized_uri body = response.response_text try: openid_services = OpenIDServiceEndpoint.fromXRDS(yadis_url, body) except XRDSError: # Does not parse as a Yadis XRDS file openid_services = [] if not openid_services: # Either not an XRDS or there are no OpenID services. if response.isXRDS(): # if we got the Yadis content-type or followed the Yadis # header, re-fetch the document without following the Yadis # header, with no Accept header. return discoverNoYadis(uri) # Try to parse the response as HTML. # <link rel="..."> openid_services = OpenIDServiceEndpoint.fromHTML(yadis_url, body) return (yadis_url, getOPOrUserServices(openid_services))
def matchTypes(self, type_uris): """Query this endpoint to see if it has any of the given type URIs. This is useful for implementing other endpoint classes that e.g. need to check for the presence of multiple versions of a single protocol. @param type_uris: The URIs that you wish to check @type type_uris: Iterable[six.text_type], six.binary_type is deprecated @return: all types that are in both in type_uris and self.type_uris """ type_uris = [ string_to_text( u, "Binary values for matchTypes are deprecated. Use text input instead." ) for u in type_uris ] return [uri for uri in type_uris if uri in self.type_uris]
def storeAssociation(self, server_url, association): """Store an association in the association directory. (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.encode('utf-8')) os.fsync(tmp_file.fileno()) finally: tmp_file.close() try: os.rename(tmp, filename) except OSError as why: if why.errno != EEXIST: raise # We only expect EEXIST to happen only on Windows. It's # possible that we will succeed in unlinking the existing # file, but not in putting the temporary file in place. try: os.unlink(filename) except OSError as why: if why.errno == ENOENT: pass else: raise # Now the target should not exist. Try renaming again, # giving up if it fails. os.rename(tmp, filename) except Exception: # If there was an error, don't leave the temporary file # around. _removeIfPresent(tmp) raise
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: six.text_type, six.binary_type is deprecated @returns: A pair of a Unix timestamp and the salt characters @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: raise ValueError('time out of range') return timestamp, nonce_string[time_str_len:]
def txn_useNonce(self, server_url, timestamp, salt): """Return whether this nonce is present, and if it is, then remove it from the set. @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 try: self.db_add_nonce(server_url, timestamp, salt) except self.exceptions.IntegrityError: # The key uniqueness check failed return False else: # The nonce was successfully added return True
def parseAcceptHeader(value): """Parse an accept header, ignoring any accept-extensions returns a list of tuples containing main MIME type, MIME subtype, and quality markdown. six.text_type -> [(six.text_type, six.text_type, float)] """ value = string_to_text( value, "Binary values for parseAcceptHeader are deprecated. Use text input instead." ) chunks = [chunk.strip() for chunk in value.split(',')] accept = [] for chunk in chunks: parts = [s.strip() for s in chunk.split(';')] mtype = parts.pop(0) if '/' not in mtype: # This is not a MIME type, so ignore the bad data continue main, sub = mtype.split('/', 1) for ext in parts: if '=' in ext: k, v = ext.split('=', 1) if k == 'q': try: q = float(v) break except ValueError: # Ignore poorly formed q-values pass else: q = 1.0 accept.append((main, sub, q)) # Sort in order q, main, sub return sorted(accept, key=itemgetter(2, 0, 1), reverse=True)
def __init__(self, request=None, update_url=None): """ @param request: When supplied, I will use namespace aliases that match those in this request. I will also check to make sure I do not respond with attributes that were not requested. @type request: L{FetchRequest} @param update_url: By default, C{update_url} is taken from the request. But if you do not supply the request, you may set the C{update_url} here. @type update_url: Optional[six.text_type], six.binary_type is deprecated """ AXKeyValueMessage.__init__(self) if update_url is not None: update_url = string_to_text(update_url, "Binary values for update_url are deprecated. Use text input instead.") self.update_url = update_url self.request = request
def requestField(self, field_name, required=False, strict=False): """Request the specified field from the OpenID user @param field_name: the unqualified simple registration field name @type field_name: six.text_type, six.binary_type is deprecated @param required: whether the given field should be presented to the user as being a required to successfully complete the request @param strict: whether to raise an exception when a field is added to a request more than once @raise ValueError: when the field requested is not a simple registration field or strict is set and the field was requested more than once """ field_name = string_to_text( field_name, "Binary values for field_name are deprecated. Use text input instead." ) checkFieldName(field_name) if strict: if field_name in self.required or field_name in self.optional: raise ValueError('That field has already been requested') else: if field_name in self.required: return if field_name in self.optional: if required: self.optional.remove(field_name) else: return if required: self.required.append(field_name) else: self.optional.append(field_name)
def 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: six.text_type, six.binary_type is deprecated @returns: A pair of a Unix timestamp and the salt characters @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: raise ValueError('time out of range') return timestamp, nonce_string[time_str_len:]
def requestField(self, field_name, required=False, strict=False): """Request the specified field from the OpenID user @param field_name: the unqualified simple registration field name @type field_name: six.text_type, six.binary_type is deprecated @param required: whether the given field should be presented to the user as being a required to successfully complete the request @param strict: whether to raise an exception when a field is added to a request more than once @raise ValueError: when the field requested is not a simple registration field or strict is set and the field was requested more than once """ field_name = string_to_text(field_name, "Binary values for field_name are deprecated. Use text input instead.") checkFieldName(field_name) if strict: if field_name in self.required or field_name in self.optional: raise ValueError('That field has already been requested') else: if field_name in self.required: return if field_name in self.optional: if required: self.optional.remove(field_name) else: return if required: self.required.append(field_name) else: self.optional.append(field_name)
def requestFields(self, field_names, required=False, strict=False): """Add the given list of fields to the request @param field_names: The simple registration data fields to request @type field_names: List[six.text_type], six.binary_type is deprecated @param required: Whether these values should be presented to the user as required @param strict: whether to raise an exception when a field is added to a request more than once @raise ValueError: when a field requested is not a simple registration field or strict is set and a field was requested more than once """ if isinstance(field_names, six.string_types): raise TypeError('Fields should be passed as a list of ' 'strings (not %r)' % (type(field_names),)) for field_name in field_names: field_name = string_to_text(field_name, "Binary values for field_names are deprecated. Use text input instead.") self.requestField(field_name, required, strict=strict)
def queryURL(self, xri, service_type=None): """Build a URL to query the proxy resolver. @param xri: An XRI to resolve. @type xri: six.text_type @param service_type: The service type to resolve, if you desire service endpoint selection. A service type is a URI. @type service_type: Optional[six.text_type], six.binary_type is deprecated @returns: a URL @returntype: six.text_type """ # Trim off the xri:// prefix. The proxy resolver didn't accept it # when this code was written, but that may (or may not) change for # XRI Resolution 2.0 Working Draft 11. qxri = toURINormal(xri)[6:] hxri = self.proxy_url + qxri args = { # XXX: If the proxy resolver will ensure that it doesn't return # bogus CanonicalIDs (as per Steve's message of 15 Aug 2006 # 11:13:42), then we could ask for application/xrd+xml instead, # which would give us a bit less to process. '_xrd_r': 'application/xrds+xml', } if service_type: service_type = string_to_text( service_type, "Binary values for service_type are deprecated. Use text input instead." ) args['_xrd_t'] = service_type else: # Don't perform service endpoint selection. args['_xrd_r'] += ';sep=false' query = _appendArgs(hxri, args) return query
def useNonce(self, server_url, timestamp, salt): """Return whether this nonce is valid. @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 if server_url: proto, rest = server_url.split('://', 1) else: # Create empty proto / rest values for empty server_url, # which is part of a consumer-generated nonce. proto, rest = '', '' domain = _filenameEscape(rest.split('/', 1)[0]) url_hash = _safe64(server_url) salt_hash = _safe64(salt) filename = '%08x-%s-%s-%s-%s' % (timestamp, proto, domain, url_hash, salt_hash) filename = os.path.join(self.nonce_dir, filename) try: fd = os.open(filename, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o200) except OSError as why: if why.errno == EEXIST: return False else: raise else: os.close(fd) return True
def test_text_input(self): result = string_to_text('ěščřž', sentinel.msg) self.assertIsInstance(result, six.text_type) self.assertEqual(result, 'ěščřž')