<commit_before># Copyright 2013-2014 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Authentication helpers."""

from __future__ import unicode_literals

import hmac

HAVE_KERBEROS = True
try:
    import kerberos
except ImportError:
    HAVE_KERBEROS = False

from base64 import standard_b64decode, standard_b64encode
from collections import namedtuple
from hashlib import md5, sha1
from random import SystemRandom

from bson.binary import Binary
from bson.py3compat import b, string_type, _unicode, PY3
from bson.son import SON
from pymongo.errors import ConfigurationError, OperationFailure


MECHANISMS = frozenset(
    ['GSSAPI', 'MONGODB-CR', 'MONGODB-X509', 'PLAIN', 'SCRAM-SHA-1', 'DEFAULT'])
"""The authentication mechanisms supported by PyMongo."""


MongoCredential = namedtuple(
    'MongoCredential',
    ['mechanism', 'source', 'username', 'password', 'mechanism_properties'])
"""A hashable namedtuple of values used for authentication."""


GSSAPIProperties = namedtuple('GSSAPIProperties', ['service_name'])
"""Mechanism properties for GSSAPI authentication."""


def _build_credentials_tuple(mech, source, user, passwd, extra):
    """Build and return a mechanism specific credentials tuple.
    """
    user = _unicode(user)
    if mech == 'GSSAPI':
        properties = extra.get('authmechanismproperties', {})
        service_name = properties.get('SERVICE_NAME', 'mongodb')
        props = GSSAPIProperties(service_name=service_name)
        # No password, source is always $external.
        return MongoCredential(mech, '$external', user, None, props)
    elif mech == 'MONGODB-X509':
        return MongoCredential(mech, '$external', user, None, None)
    else:
        if passwd is None:
            raise ConfigurationError("A password is required.")
        return MongoCredential(mech, source, user, _unicode(passwd), None)


if PY3:
    def _xor(fir, sec):
        """XOR two byte strings together (python 3.x)."""
        return b"".join([bytes([x ^ y]) for x, y in zip(fir, sec)])


    _from_bytes = int.from_bytes
    _to_bytes = int.to_bytes
else:
    from binascii import (hexlify as _hexlify,
                          unhexlify as _unhexlify)


    def _xor(fir, sec):
        """XOR two byte strings together (python 2.x)."""
        return b"".join([chr(ord(x) ^ ord(y)) for x, y in zip(fir, sec)])


    def _from_bytes(value, dummy, int=int, _hexlify=_hexlify):
        """An implementation of int.from_bytes for python 2.x."""
        return int(_hexlify(value), 16)


    def _to_bytes(value, dummy0, dummy1, _unhexlify=_unhexlify):
        """An implementation of int.to_bytes for python 2.x."""
        return _unhexlify('%040x' % value)


try:
    # The fastest option, if it's been compiled to use OpenSSL's HMAC.
    from backports.pbkdf2 import pbkdf2_hmac

    def _hi(data, salt, iterations):
        return pbkdf2_hmac('sha1', data, salt, iterations)

except ImportError:
    try:
        # Python 2.7.8+, or Python 3.4+.
        from hashlib import pbkdf2_hmac

        def _hi(data, salt, iterations):
            return pbkdf2_hmac('sha1', data, salt, iterations)

    except ImportError:

        def _hi(data, salt, iterations):
            """A simple implementation of PBKDF2."""
            mac = hmac.HMAC(data, None, sha1)

            def _digest(msg, mac=mac):
                """Get a digest for msg."""
                _mac = mac.copy()
                _mac.update(msg)
                return _mac.digest()

            from_bytes = _from_bytes
            to_bytes = _to_bytes
<commit_msg>PYTHON-818 - Work around issues with unicode_literals and pbkdf2_hmac.<commit_after># Copyright 2013-2014 MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Authentication helpers."""

# TODO: We may not want to do this. It causes issues
# with passing the string 'sha1' to hashlib.pbkdf2_hmac
# in cpython 2.x >= 2.8 and pypy >= 2.4.x.
from __future__ import unicode_literals

import hmac

HAVE_KERBEROS = True
try:
    import kerberos
except ImportError:
    HAVE_KERBEROS = False

from base64 import standard_b64decode, standard_b64encode
from collections import namedtuple
from hashlib import md5, sha1
from random import SystemRandom

from bson.binary import Binary
from bson.py3compat import b, string_type, _unicode, PY3
from bson.son import SON
from pymongo.errors import ConfigurationError, OperationFailure


MECHANISMS = frozenset(
    ['GSSAPI', 'MONGODB-CR', 'MONGODB-X509', 'PLAIN', 'SCRAM-SHA-1', 'DEFAULT'])
"""The authentication mechanisms supported by PyMongo."""


MongoCredential = namedtuple(
    'MongoCredential',
    ['mechanism', 'source', 'username', 'password', 'mechanism_properties'])
"""A hashable namedtuple of values used for authentication."""


GSSAPIProperties = namedtuple('GSSAPIProperties', ['service_name'])
"""Mechanism properties for GSSAPI authentication."""


def _build_credentials_tuple(mech, source, user, passwd, extra):
    """Build and return a mechanism specific credentials tuple.
    """
    user = _unicode(user)
    if mech == 'GSSAPI':
        properties = extra.get('authmechanismproperties', {})
        service_name = properties.get('SERVICE_NAME', 'mongodb')
        props = GSSAPIProperties(service_name=service_name)
        # No password, source is always $external.
        return MongoCredential(mech, '$external', user, None, props)
    elif mech == 'MONGODB-X509':
        return MongoCredential(mech, '$external', user, None, None)
    else:
        if passwd is None:
            raise ConfigurationError("A password is required.")
        return MongoCredential(mech, source, user, _unicode(passwd), None)


if PY3:
    def _xor(fir, sec):
        """XOR two byte strings together (python 3.x)."""
        return b"".join([bytes([x ^ y]) for x, y in zip(fir, sec)])


    _from_bytes = int.from_bytes
    _to_bytes = int.to_bytes
else:
    from binascii import (hexlify as _hexlify,
                          unhexlify as _unhexlify)


    def _xor(fir, sec):
        """XOR two byte strings together (python 2.x)."""
        return b"".join([chr(ord(x) ^ ord(y)) for x, y in zip(fir, sec)])


    def _from_bytes(value, dummy, int=int, _hexlify=_hexlify):
        """An implementation of int.from_bytes for python 2.x."""
        return int(_hexlify(value), 16)


    def _to_bytes(value, dummy0, dummy1, _unhexlify=_unhexlify):
        """An implementation of int.to_bytes for python 2.x."""
        return _unhexlify('%040x' % value)


try:
    # The fastest option, if it's been compiled to use OpenSSL's HMAC.
    from backports.pbkdf2 import pbkdf2_hmac

    def _hi(data, salt, iterations):
        return pbkdf2_hmac(str('sha1'), data, salt, iterations)

except ImportError:
    try:
        # Python 2.7.8+, or Python 3.4+.
        from hashlib import pbkdf2_hmac

        def _hi(data, salt, iterations):
            return pbkdf2_hmac(str('sha1'), data, salt, iterations)

    except ImportError:

        def _hi(data, salt, iterations):
            """A simple implementation of PBKDF2."""
            mac = hmac.HMAC(data, None, sha1)

            def _digest(msg, mac=mac):
                """Get a digest for msg."""
                _mac = mac.copy()
                _mac.update(msg)
                return _mac.digest()

            from_bytes = _from_bytes
            to_bytes = _to_bytes

{'fraction_non_alphanumeric': 0.10559080569855142, 'fraction_numerical': 0.014485813480186759, 'mean_word_length': 3.229873417721519, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2173049', 'n_tokens_mistral': 2669, 'n_tokens_neox': 2522, 'n_words': 834}