예제 #1
0
    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)
예제 #2
0
    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)
예제 #3
0
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]
예제 #4
0
    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
예제 #5
0
    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?)")
예제 #6
0
    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)
예제 #7
0
    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)
예제 #8
0
    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
예제 #9
0
    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?)")
예제 #10
0
    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
예제 #11
0
    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)
예제 #12
0
    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,))
예제 #13
0
    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
예제 #14
0
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
예제 #15
0
    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
예제 #16
0
    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
예제 #17
0
    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, 'ěščřž')
예제 #18
0
    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, 'ěščřž')
예제 #19
0
파일: sreg.py 프로젝트: ziima/python-openid
    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
예제 #20
0
    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
예제 #21
0
    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
예제 #22
0
    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
예제 #23
0
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
예제 #24
0
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()
예제 #25
0
    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
예제 #26
0
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)
예제 #27
0
    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]
예제 #28
0
    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
예제 #29
0
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]
예제 #30
0
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')
예제 #31
0
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))
예제 #32
0
    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]
예제 #33
0
    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
예제 #34
0
    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
예제 #35
0
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:]
예제 #36
0
    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
예제 #37
0
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)
예제 #38
0
    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
예제 #39
0
    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)
예제 #40
0
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:]
예제 #41
0
파일: sreg.py 프로젝트: ziima/python-openid
    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)
예제 #42
0
파일: sreg.py 프로젝트: ziima/python-openid
    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)
예제 #43
0
    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
예제 #44
0
    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
예제 #45
0
    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
예제 #46
0
 def test_text_input(self):
     result = string_to_text('ěščřž', sentinel.msg)
     self.assertIsInstance(result, six.text_type)
     self.assertEqual(result, 'ěščřž')