<commit_before>"""
This module documents the interface to the OpenID server library.  The
only part of the library which has to be used and isn't documented
here is the store for associations.  See the C{L{openid.store}}
package for more information on stores.


OVERVIEW
========

    FIXME


LIBRARY DESIGN
==============

    FIXME


STORES
======

    The OpenID server needs to maintain state between requests in
    order to function.  Its mechanism for doing this is called a
    store.  The store interface is defined in
    C{L{openid.store.interface.OpenIDStore}}.  Additionally, several
    concrete store implementations are provided, so that most sites
    won't need to implement a custom store.  For a store backed by
    flat files on disk, see
    C{L{openid.store.filestore.FileOpenIDStore}}.  For stores based
    on MySQL or SQLite, see the C{L{openid.store.sqlstore}} module.


USING THIS LIBRARY
==================

    FIXME
"""

import time
from copy import deepcopy

from openid import cryptutil
from openid import kvform
from openid import oidutil
from openid.dh import DiffieHellman
from openid.server.trustroot import TrustRoot
from openid.association import Association

HTTP_OK = 200
HTTP_REDIRECT = 302
HTTP_ERROR = 400

BROWSER_REQUEST_MODES = ['checkid_setup', 'checkid_immediate']
OPENID_PREFIX = 'openid.'

ENCODE_KVFORM = ('kvform',)
ENCODE_URL = ('URL/redirect',)

class OpenIDRequest(object):
    mode = None

class CheckAuthRequest(OpenIDRequest):
    """
    @type assoc_handle: str
    @type sig: str
    @type signed: list of pairs
    @type invalidate_handle: str
    """
    mode = "check_authentication"
    invalidate_handle = None

    def __init__(self, assoc_handle, sig, signed, invalidate_handle=None):
        self.assoc_handle = assoc_handle
        self.sig = sig
        self.signed = signed
        if invalidate_handle is not None:
            self.invalidate_handle = invalidate_handle

    def fromQuery(klass, query):
        self = klass.__new__(klass)
        try:
            self.assoc_handle = query[OPENID_PREFIX + 'assoc_handle']
            self.sig = query[OPENID_PREFIX + 'sig']
            signed_list = query[OPENID_PREFIX + 'signed']
        except KeyError, e:
            raise ProtocolError(query,
                                text="%s request missing required parameter %s"
                                " from query %s" %
                                (self.mode, e.args[0], query))
        signed_list = signed_list.split(',')
        signed_pairs = []
        for field in signed_list:
            try:
                if field == 'mode':
                    # XXX KLUDGE HAX WEB PROTOCoL BR0KENNN
                    # openid.mode is currently check_authentication because
                    # that's the mode of this request.  But the signature
                    # was made on something with a different openid.mode.
                    value = "id_res"
                else:
                    value = query[OPENID_PREFIX + field]
            except KeyError, e:
                raise ProtocolError(
                    query,
                    text="Couldn't find signed field %r in query %s"
                    % (field, query))
            else:
                signed_pairs.append((field, value))

        self.signed = signed_pairs
        return self

    fromQuery = classmethod(fromQuery)

    def answer(self, signatory):
        is_valid = signatory.verify(self.assoc_handle, self.sig, self.signed)
        # Now invalidate that assoc_handle so it this checkAuth message cannot
        # be replayed.
        signatory.invalidate(self.assoc_handle, dumb=True)
        response = OpenIDResponse(self)
        response.fields['is_valid'] = (is_valid and "true") or "false"

        if self.invalidate_handle:
            assoc = signatory.getAssociation(self.invalidate_handle, dumb=False)
            if not assoc:
                response.fields['invalidate_handle'] = self.invalidate_handle
        return response

    def __str__(self):
        if self.invalidate_handle:
            ih = " invalidate? %r" % (self.invalidate_handle,)
        else:
            ih = ""
        s = "<%s handle: %r sig: %r: signed: %r%s>" % (
            self.__class__.__name__, self.assoc_handle,
            self.sig, self.signed, ih)
        return s

class AssociateRequest(OpenIDRequest):
    mode = "associate"
    session_type = 'plaintext'
    assoc_type = 'HMAC-SHA1'

    def fromQuery(klass, query):
        self = AssociateRequest()
        session_type = query.get(OPENID_PREFIX + 'session_type')
        if session_type:
            self.session_type = session_type
            if session_type == 'DH-SHA1':
                try:
                    self.pubkey = cryptutil.base64ToLong(
                        query[OPENID_PREFIX + 'dh_consumer_public'])
                except KeyError, e:
                    raise ProtocolError(
                        query,
                        text="Public key for DH-SHA1 session "
                        "not found in query %s" % (query,))
                # FIXME: Missing dh_modulus and dh_gen options.
        return self

    fromQuery = classmethod(fromQuery)

    def answer(self, assoc):
        response = OpenIDResponse(self)
        response.fields.update({
            'expires_in': '%d' % (assoc.getExpiresIn(),),
            'assoc_type': 'HMAC-SHA1',
            'assoc_handle': assoc.handle,
            })
        if self.session_type == 'DH-SHA1':
            # XXX - get dh_modulus and dh_gen
            dh = DiffieHellman()
            mac_key = dh.xorSecret(self.pubkey, assoc.secret)
            response.fields.update({
                'session_type': self.session_type,
                'dh_server_public': cryptutil.longToBase64(dh.public),
                'enc_mac_key': oidutil.toBase64(mac_key),
                })
        elif self.session_type == 'plaintext':
            response.fields['mac_key'] = oidutil.toBase64(assoc.secret)
        else:
            # XXX - kablooie
            pass
        return response

class CheckIDRequest(OpenIDRequest):
    """A CheckID Request.

    @type mode: str
    @type immediate: bool
    @type identity: str
    @type trust_root: str
    @type return_to: str
    @type assoc_handle: str
    """
    mode = "checkid_setup" or "checkid_immediate"

    immediate = False

    trust_root = None
    assoc_handle = None

    def __init__(self, identity, return_to, trust_root=None,
                 immediate=False):
        self.identity = identity
        self.return_to = return_to
        self.trust_root = trust_root
        if immediate:
            self.immediate = True
            self.mode = "checkid_immediate"
        else:
            self.immediate = False
            self.mode = "checkid_setup"

        if not TrustRoot.parse(self.return_to):
            raise MalformedReturnURL(self.return_to)


    def fromQuery(klass, query):
        self = klass.__new__(klass)
        mode = query[OPENID_PREFIX + 'mode']
        if mode == "checkid_immediate":
            self.immediate = True
            self.mode = "checkid_immediate"
        else:
            self.immediate = False
            self.mode = "checkid_setup"

        required = [
            'identity',
            'return_to',
            ]
        optional = [
            'trust_root',
            'assoc_handle',
            ]

        for field in required:
            value = query.get(OPENID_PREFIX + field)
            if not value:
                raise ProtocolError(
                    query,
                    text="Missing required field %s from %r"
                    % (field, query))
            setattr(self, field, value)

        for field in optional:
            value = query.get(OPENID_PREFIX + field)
            if value:
                setattr(self, field, value)

        if not TrustRoot.parse(self.return_to):
            raise MalformedReturnURL(query, self.return_to)

        return self

    fromQuery = classmethod(fromQuery)


    def trustRootValid(self):
        """Is my return_to under my trust_root?

        @returntype: bool
        """
        if not self.trust_root:
            return True
        tr = TrustRoot.parse(self.trust_root)
        if tr is None:
            raise MalformedTrustRoot(self.trust_root)
        return tr.validateURL(self.return_to)

    def answer(self, allow, setup_url=None):
        if allow or self.immediate:
            mode = 'id_res'
        else:
            mode = 'cancel'

        response = CheckIDResponse(self, mode)

        if allow:
            response.fields['identity'] = self.identity
            response.fields['return_to'] = self.return_to
            if not self.trustRootValid():
                raise UntrustedReturnURL(self.return_to, self.trust_root)
        else:
            response.signed[:] = []
            if self.immediate:
                if not setup_url:
                    raise ValueError("setup_url is required for allow=False "
                                     "in immediate mode.")
                response.fields['user_setup_url'] = setup_url

        return response

<commit_msg>[project @ Fixed protocol error instantiations]<commit_after>"""
This module documents the interface to the OpenID server library.  The
only part of the library which has to be used and isn't documented
here is the store for associations.  See the C{L{openid.store}}
package for more information on stores.


OVERVIEW
========

    FIXME


LIBRARY DESIGN
==============

    FIXME


STORES
======

    The OpenID server needs to maintain state between requests in
    order to function.  Its mechanism for doing this is called a
    store.  The store interface is defined in
    C{L{openid.store.interface.OpenIDStore}}.  Additionally, several
    concrete store implementations are provided, so that most sites
    won't need to implement a custom store.  For a store backed by
    flat files on disk, see
    C{L{openid.store.filestore.FileOpenIDStore}}.  For stores based
    on MySQL or SQLite, see the C{L{openid.store.sqlstore}} module.


USING THIS LIBRARY
==================

    FIXME
"""

import time
from copy import deepcopy

from openid import cryptutil
from openid import kvform
from openid import oidutil
from openid.dh import DiffieHellman
from openid.server.trustroot import TrustRoot
from openid.association import Association

HTTP_OK = 200
HTTP_REDIRECT = 302
HTTP_ERROR = 400

BROWSER_REQUEST_MODES = ['checkid_setup', 'checkid_immediate']
OPENID_PREFIX = 'openid.'

ENCODE_KVFORM = ('kvform',)
ENCODE_URL = ('URL/redirect',)

class OpenIDRequest(object):
    mode = None

class CheckAuthRequest(OpenIDRequest):
    """
    @type assoc_handle: str
    @type sig: str
    @type signed: list of pairs
    @type invalidate_handle: str
    """
    mode = "check_authentication"
    invalidate_handle = None

    def __init__(self, assoc_handle, sig, signed, invalidate_handle=None):
        self.assoc_handle = assoc_handle
        self.sig = sig
        self.signed = signed
        if invalidate_handle is not None:
            self.invalidate_handle = invalidate_handle

    def fromQuery(klass, query):
        self = klass.__new__(klass)
        try:
            self.assoc_handle = query[OPENID_PREFIX + 'assoc_handle']
            self.sig = query[OPENID_PREFIX + 'sig']
            signed_list = query[OPENID_PREFIX + 'signed']
        except KeyError, e:
            raise ProtocolError(query,
                                text="%s request missing required parameter %s"
                                " from query %s" %
                                (self.mode, e.args[0], query))
        signed_list = signed_list.split(',')
        signed_pairs = []
        for field in signed_list:
            try:
                if field == 'mode':
                    # XXX KLUDGE HAX WEB PROTOCoL BR0KENNN
                    # openid.mode is currently check_authentication because
                    # that's the mode of this request.  But the signature
                    # was made on something with a different openid.mode.
                    value = "id_res"
                else:
                    value = query[OPENID_PREFIX + field]
            except KeyError, e:
                raise ProtocolError(
                    query,
                    text="Couldn't find signed field %r in query %s"
                    % (field, query))
            else:
                signed_pairs.append((field, value))

        self.signed = signed_pairs
        return self

    fromQuery = classmethod(fromQuery)

    def answer(self, signatory):
        is_valid = signatory.verify(self.assoc_handle, self.sig, self.signed)
        # Now invalidate that assoc_handle so it this checkAuth message cannot
        # be replayed.
        signatory.invalidate(self.assoc_handle, dumb=True)
        response = OpenIDResponse(self)
        response.fields['is_valid'] = (is_valid and "true") or "false"

        if self.invalidate_handle:
            assoc = signatory.getAssociation(self.invalidate_handle, dumb=False)
            if not assoc:
                response.fields['invalidate_handle'] = self.invalidate_handle
        return response

    def __str__(self):
        if self.invalidate_handle:
            ih = " invalidate? %r" % (self.invalidate_handle,)
        else:
            ih = ""
        s = "<%s handle: %r sig: %r: signed: %r%s>" % (
            self.__class__.__name__, self.assoc_handle,
            self.sig, self.signed, ih)
        return s

class AssociateRequest(OpenIDRequest):
    mode = "associate"
    session_type = 'plaintext'
    assoc_type = 'HMAC-SHA1'

    def fromQuery(klass, query):
        self = AssociateRequest()
        session_type = query.get(OPENID_PREFIX + 'session_type')
        if session_type:
            self.session_type = session_type
            if session_type == 'DH-SHA1':
                try:
                    self.pubkey = cryptutil.base64ToLong(
                        query[OPENID_PREFIX + 'dh_consumer_public'])
                except KeyError, e:
                    raise ProtocolError(
                        query,
                        text="Public key for DH-SHA1 session "
                        "not found in query %s" % (query,))
                # FIXME: Missing dh_modulus and dh_gen options.
        return self

    fromQuery = classmethod(fromQuery)

    def answer(self, assoc):
        response = OpenIDResponse(self)
        response.fields.update({
            'expires_in': '%d' % (assoc.getExpiresIn(),),
            'assoc_type': 'HMAC-SHA1',
            'assoc_handle': assoc.handle,
            })
        if self.session_type == 'DH-SHA1':
            # XXX - get dh_modulus and dh_gen
            dh = DiffieHellman()
            mac_key = dh.xorSecret(self.pubkey, assoc.secret)
            response.fields.update({
                'session_type': self.session_type,
                'dh_server_public': cryptutil.longToBase64(dh.public),
                'enc_mac_key': oidutil.toBase64(mac_key),
                })
        elif self.session_type == 'plaintext':
            response.fields['mac_key'] = oidutil.toBase64(assoc.secret)
        else:
            # XXX - kablooie
            pass
        return response

class CheckIDRequest(OpenIDRequest):
    """A CheckID Request.

    @type mode: str
    @type immediate: bool
    @type identity: str
    @type trust_root: str
    @type return_to: str
    @type assoc_handle: str
    """
    mode = "checkid_setup" or "checkid_immediate"

    immediate = False

    trust_root = None
    assoc_handle = None

    def __init__(self, identity, return_to, trust_root=None,
                 immediate=False):
        self.identity = identity
        self.return_to = return_to
        self.trust_root = trust_root
        if immediate:
            self.immediate = True
            self.mode = "checkid_immediate"
        else:
            self.immediate = False
            self.mode = "checkid_setup"

        if not TrustRoot.parse(self.return_to):
            raise MalformedReturnURL(None, self.return_to)


    def fromQuery(klass, query):
        self = klass.__new__(klass)
        mode = query[OPENID_PREFIX + 'mode']
        if mode == "checkid_immediate":
            self.immediate = True
            self.mode = "checkid_immediate"
        else:
            self.immediate = False
            self.mode = "checkid_setup"

        required = [
            'identity',
            'return_to',
            ]
        optional = [
            'trust_root',
            'assoc_handle',
            ]

        for field in required:
            value = query.get(OPENID_PREFIX + field)
            if not value:
                raise ProtocolError(
                    query,
                    text="Missing required field %s from %r"
                    % (field, query))
            setattr(self, field, value)

        for field in optional:
            value = query.get(OPENID_PREFIX + field)
            if value:
                setattr(self, field, value)

        if not TrustRoot.parse(self.return_to):
            raise MalformedReturnURL(query, self.return_to)

        return self

    fromQuery = classmethod(fromQuery)


    def trustRootValid(self):
        """Is my return_to under my trust_root?

        @returntype: bool
        """
        if not self.trust_root:
            return True
        tr = TrustRoot.parse(self.trust_root)
        if tr is None:
            raise MalformedTrustRoot(None, self.trust_root)
        return tr.validateURL(self.return_to)

    def answer(self, allow, setup_url=None):
        if allow or self.immediate:
            mode = 'id_res'
        else:
            mode = 'cancel'

        response = CheckIDResponse(self, mode)

        if allow:
            response.fields['identity'] = self.identity
            response.fields['return_to'] = self.return_to
            if not self.trustRootValid():
                raise UntrustedReturnURL(self.return_to, self.trust_root)
        else:
            response.signed[:] = []
            if self.immediate:
                if not setup_url:
                    raise ValueError("setup_url is required for allow=False "
                                     "in immediate mode.")
                response.fields['user_setup_url'] = setup_url

        return response


{'fraction_non_alphanumeric': 0.08799956677136359, 'fraction_numerical': 0.0025993718184772014, 'mean_word_length': 1.8818664169787764, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1037808', 'n_tokens_mistral': 5278, 'n_tokens_neox': 5035, 'n_words': 1368}