===========
Passlib 1.7
===========

.. rst-class:: without-title

.. warning::

    **Passlib 1.8 will drop support for Python 2.x, 3.3, and 3.4**;
    and will require Python >= 3.5.  The 1.7 series will be the last
    to support Python 2.7.  (See :issue:`119` for rationale).

**1.7.4** (2020-10-08)
======================

Small followup to 1.7.3 release.

Bugfixes
--------

* Fixed some Python 2.6 errors from last release (:issue:`128`)

Other Changes
-------------

* :mod:`passlib.ext.django` -- updated tests to pass for Django 1.8 - 3.1 (:issue:`98`);
  along with some internal refactoring of the test classes.

* .. py:currentmodule:: passlib.context

  :class:`CryptContext` will now throw :exc:`~passlib.exc.UnknownHashError` when it can't identify
  a hash provided to methods such as :meth:`!CryptContext.verify`.
  Previously it would throw a generic :exc:`ValueError`.


Deprecations
------------

* :mod:`passlib.ext.django`: This extension will require Django 2.2 or newer as of Passlib 1.8.


**1.7.3** (2020-10-06)
======================

This release rolls up assorted bug & compatibility fixes since 1.7.2.

Administrative Changes
----------------------

.. rst-class:: without-title

.. note::

  **Passlib has moved to Heptapod!**

  Due to BitBucket deprecating Mercurial support, Passlib's public repository and issue tracker
  has been relocated.  It's now located at `<https://foss.heptapod.net/python-libs/passlib>`_,
  and is powered by `Heptapod <https://heptapod.net/>`_.

  Hosting for this and other open-source projects graciously provided by the people at
  `Octobus <https://octobus.net/>`_ and `CleverCloud <https://clever-cloud.com/>`_!

  The mailing list and documentation urls remain the same.

New Features
------------

* .. py:currentmodule:: passlib.hash

  :class:`ldap_salted_sha512`: LDAP "salted hash" support added for SHA-256 and SHA-512 (:issue:`124`).

Bugfixes
--------

* .. py:currentmodule:: passlib.hash

  :class:`bcrypt`: Under python 3, OS native backend wasn't being detected on BSD platforms.
  This was due to a few internal issues in feature-detection code, which have been fixed.

* :func:`passlib.utils.safe_crypt`: Support :func:`crypt.crypt` unexpectedly
  returning bytes under Python 3 (:issue:`113`).

* :func:`passlib.utils.safe_crypt`: Support :func:`crypt.crypt` throwing :exc:`OSError`,
  which can happen as of Python 3.9 (:issue:`115`).

* :mod:`passlib.ext.django`: fixed lru_cache import (django 3 compatibility)

* :mod:`!passlib.tests`: fixed bug where :meth:`HandlerCase.test_82_crypt_support` wasn't
  being run on systems lacking support for the hasher being tested.
  This test now runs regardless of system support.

Deprecations
------------

* Support for Python 2.x, 3.3, and 3.4 is deprecated; and will be dropped in Passlib 1.8.

Other Changes
-------------

* .. py:currentmodule:: passlib.hash

  :class:`bcrypt_sha256`:  Internal algorithm has been changed to use HMAC-SHA256 instead of
  plain SHA256.  This should strengthen the hash against brute-force attempts which bypass
  the intermediary hash by using known-sha256-digest lookup tables (:issue:`114`).

* .. py:currentmodule:: passlib.hash

  :class:`bcrypt`: OS native backend ("os_crypt") now raises the new :exc:`~passlib.exc.PasswordValueError`
  if password is provided as non-UTF8 bytes under python 3
  (These can't be passed through, due to limitation in stdlib's :func:`!crypt.crypt`).
  Prior to this release, it confusingly raised :exc:`~passlib.exc.MissingBackendError` instead.

  Also improved legacy bcrypt format workarounds, to support a few more UTF8 edge cases than before.

* Modified some internals to help run on FIPS systems (:issue:`116`):

  In particular, when MD5 hash is not available, :class:`~passlib.hash.hex_md5`
  will now return a dummy hasher which throws an error if used; rather than throwing
  an uncaught :exc:`!ValueError` when an application attempts to import it.  (Similar behavior
  added for the other unsalted digest hashes).

  .. py:currentmodule:: passlib.crypto.digest

  Also, :func:`lookup_hash`'s ``required=False`` kwd was modified to report unsupported hashes
  via the :attr:`HashInfo.supported` attribute; rather than letting ValueErrors through uncaught.

  This should allow CryptContext instances to be created on FIPS systems without having
  a load-time error (though they will still receive an error if an attempt is made to actually
  *use* a FIPS-disabled hash).

* Internal errors calling stdlib's :func:`crypt.crypt`, or third party libraries,
  will now raise the new :exc:`~passlib.exc.InternalBackendError` (a RuntimeError);
  where previously it would raise an :exc:`AssertionError`.

* Various Python 3.9 compatibility fixes (including ``NotImplemented``-related warning, :issue:`125`)


**1.7.2** (2019-11-22)
======================

This release rolls up assorted bug & compatibility fixes since 1.7.1.

New Features
------------

* .. py:currentmodule:: passlib.hash

  :class:`argon2`: Now supports Argon2 "ID" and "D" hashes (assuming new enough backend library).
  Now defaults to "ID" hashes instead of "I" hashes, but this can be overridden via ``type`` keyword.
  (:issue:`101`)

* .. py:currentmodule:: passlib.hash

  :class:`scrypt`: Now uses python 3.6 stdlib's :func:`hashlib.scrypt` as backend,
  if present (:issue:`86`).

Bugfixes
--------

* Python 3.8 compatibility fixes

* :class:`passlib.apache.HtpasswdFile`: Now generates bcrypt hashes using
  the ``"$2y$"`` prefix,  which should work properly with Apache 2.4's ``htpasswd`` tool.
  Previous releases used the functionally equivalent ``"$2b$"`` prefix,
  which ``htpasswd`` was unable to read (:issue:`95`).

* .. py:currentmodule:: passlib.totp

  :mod:`passlib.totp`: The :meth:`TOTP.to_uri` method now prepends the issuer to URI label,
  (per the KeyURI spec).  This should fix some compatibility issues with older TOTP clients
  (:issue:`92`)

* .. py:currentmodule:: passlib.hash

  Fixed error in :meth:`argon2.parsehash` (:issue:`97`)

* **unittests**: ``crypt()`` unittests now account for linux systems running libxcrypt
  (such as recent Fedora releases)

Deprecations
------------

.. rst-class:: float-center

.. warning::

    Due to lack of ``pip`` and ``venv`` support, Passlib is no longer fully tested on Python
    2.6 & 3.3.  There are no known issues, and bugfixes against these versions will still be
    accepted for the Passlib 1.7.x series.
    However, **Passlib 1.8 will drop support for Python 2.x, 3.3, & 3.4,** and require Python >= 3.5.

* Support for Python 2.x, 3.3, and 3.4 is deprecated; and will be dropped in Passlib 1.8.
  *(2020-10-06: Updated to include all of Python 2.x, 3.3, and 3.4; when 1.7.2 was released,
  only Python 2.6 and 3.3 support was deprecated)*

* .. py:currentmodule:: passlib.hash

  :class:`bcrypt`: ``py-bcrypt`` and ``bcryptor`` backends are deprecated, and support
  will be removed in Passlib 1.8.  Please switch to the ``bcrypt`` backend.

Other Changes
-------------

* **setup.py**: now honors ``$SOURCE_DATE_EPOCH`` to help with reproducible builds

* .. py:currentmodule:: passlib.hash

  :class:`argon2`: Now throws helpful error if "argon2" package is actually an incompatible
  or supported version of argon2_cffi (:issue:`99`).

* **documentation**: Various updates & corrections.  
  building the documentation now requires Sphinx 1.6 or newer.
  

**1.7.1** (2017-1-30)
=====================

This release rolls up assorted bug & compatibility fixes since 1.7.0.

Bugfixes
--------
* .. py:currentmodule:: passlib.hash

  :class:`cisco_asa` and :class:`cisco_pix`: Fixed a number of issues
  which under :ref:`certain conditions <passlib-asa96-bug>`
  caused prior releases to generate hashes that were unverifiable
  on Cisco systems.

* .. py:currentmodule:: passlib.ifc

  :meth:`PasswordHash.hash` will now warn if passed any settings
  keywords.  This usage was deprecated in 1.7.0, but warning wasn't properly enabled.
  See :ref:`hash-configuring` for the preferred way to pass settings.

* **setup.py**: Don't append timestamp when run from an sdist.
  This should fix some downstream build issues.

* :mod:`!passlib.tests.test_totp`: Test suite now traps additional errors that :func:`datetime.utcfromtimestamp`
  may throw under python 3, which should fix some test failures on architectures with rarer ILP sizes.
  It also works around Python 3.6 bug `29100 <https://bugs.python.org/issue29100>`_.

Deprecations
------------

* :class:`~passlib.context.CryptContext`: The ``harden_verify`` flag has been turned into a NOOP and deprecated.
  It will be removed in passlib 1.8 along with the already-deprecated ``min_verify_time`` (:issue:`83`).

Other Changes
-------------

* :mod:`!passlib.tests.utils`: General truncation policy details were hammered out,
  and additional hasher tests were added to enforce them.

* **documentation**: Various updates & corrections.

.. rst-class:: emphasize-children toc-always-open

**1.7.0** (2016-11-22)
======================

Overview
--------

    *Welcome to Passlib 1.7!*

    This release includes a number of new features, cleans up
    some long-standing design issues, and contains a number of internal
    improvements; all part of the roadmap towards a leaner and simpler Passlib 2.0.

    *Highlights include:*

    * Support for :class:`~passlib.hash.argon2` and
      :class:`~passlib.hash.scrypt` hashes.

    * TOTP Two-Factor Authentications helpers in the :mod:`passlib.totp` module.

    .. currentmodule:: passlib.ifc

    * The misnamed :meth:`PasswordHash.encrypt` method has been renamed to  :meth:`PasswordHash.hash`
      (and the old alias deprecated).  This is part of a much
      larger project to clean up passlib's password hashing API,
      see the :ref:`hash-tutorial` for a walkthrough.

    * Large speedup of the internal PBKDF2 routines.

    * Updated documentation

Requirements
------------

   * **Passlib now requires Python 2.6, 2.7, or >= 3.3**.
     Support for Python versions 2.5 and 3.0 through 3.2 have been dropped.
     Support for PyPy 1.x has also been dropped.

   * The :mod:`passlib.ext.django` extension now requires Django 1.8 or better.
     Django 1.7 and earlier are no longer supported.

New Features
------------

*New Hashes*

    * :doc:`passlib.hash.argon2 </lib/passlib.hash.argon2>` --
      Support for the Argon2 password hash (:issue:`69`).

    * :doc:`passlib.hash.scrypt </lib/passlib.hash.scrypt>` --
      New password hash format which uses the SCrypt KDF (:issue:`8`).

    * :doc:`passlib.hash.cisco_asa </lib/passlib.hash.cisco_asa>` --
      Support for Cisco ASA 7.0 and newer hashes (:issue:`51`).
      *Note: this should be considered experimental, and needs verification
      of it's test vectors.*

*New Modules*

    * New :mod:`passlib.totp` module provides full support for TOTP tokens
      on both client and server side.  This module contains both low-level primitives,
      and high-level helpers for persisting and tracking client state.

    * New :mod:`passlib.pwd` module added to aid in password generation.
      Features support for alphanumeric passwords, or generation
      of phrases using the EFF's password generation wordlist.

*CryptContext Features*

    * The :class:`~passlib.context.CryptContext` object now has helper
      methods for dealing with hashes representing
      :ref:`disabled accounts <context-disabled-hashes>` (:issue:`45`).

    * All hashers which truncate passwords (e.g. :class:`~passlib.hash.bcrypt`
      and :class:`~passlib.hash.des_crypt`) can now be configured to raise
      a :exc:`~passlib.exc.PasswordTruncateError` when a overly-large password is provided.
      This configurable via (for example) ``bcrypt.using(truncate_error=True).hash(secret)``,
      or globally as an option to CryptContext (:issue:`59`).

*Cryptographic Backends*

    * The :func:`~passlib.crypto.digest.pbkdf2_hmac` function and all PBKDF2-based
      hashes have been sped up by ~20% compared to Passlib 1.6. For an even greater
      speedup, it will now take advantage of the external `fastpbk2 <https://pypi.python.org/pypi/fastpbkdf2>`_
      library, or stdlib's :func:`hashlib.pbkdf2_hmac` (when available).

Other Changes
-------------

*Other changes of note in Passlib 1.7:*

    .. currentmodule:: passlib.ifc

    * New workflows have been for configuring the hashers through :meth:`PasswordHash.using`,
      and testing hashes through :meth:`PasswordHash.needs_update`.
      See the :ref:`hash-tutorial` for a walkthrough.

    * :class:`~passlib.hash.bcrypt` and :class:`~passlib.hash.bcrypt_sha256`
      now default to the "2b" format.

    * Added support for Django's Argon2 wrapper (:class:`~passlib.hash.django_argon2`)

    * :class:`passlib.apache.HtpasswdFile` has been updated to support all of Apache 2.4's
      hash schemes, as well as all host OS crypt formats; allowing for much more
      secure hashes in htpasswd files.

      You can now specify if the default hash should be compatible with apache 2.2 or 2.4, and host-specific or portable.
      See the ``default_schemes`` keyword for details.

    * Large parts of the documentation have been rewritten, to separate
      tutorial & api reference content, and provide more detail on various features.

    * Official documentation is now at https://passlib.readthedocs.io

*Internal Changes*

    .. currentmodule:: passlib.ifc

    * The majority of CryptContext's internal rounds handling & migration code has been
      moved to the password hashes themselves, taking advantage of the new :meth:`PasswordHash.using`
      and :meth:`PasswordHash.needs_update` methods.

      This allows much more flexibility when configuring a hasher directly,
      as well making it easier for CryptContext to support hash-specific parameters.

    * The shared :class:`!PasswordHash` unittests now check all hash handlers for
      basic thread-safety (motivated by the pybcrypt 0.2 concurrency bug).

    * :func:`~passlib.utils.consteq` is now wraps stdlib's :func:`hmac.compare_digest`
      when available (python 2.7.11, python 3.3 and up).

Bugfixes
--------
    * :class:`~passlib.hash.bcrypt`: Passlib will now detect and work around
      a fatal concurrency bug in py-bcrypt 0.2 and earlier
      (a :exc:`~passlib.exc.PasslibSecurityWarning` will also be issued).
      Nevertheless, users are *strongly* encouraged to upgrade to py-bcrypt 0.3
      or another bcrypt library if you are using the
      :doc:`bcrypt </lib/passlib.hash.bcrypt>` hash.

    * :class:`~passlib.CryptContext` instances now pass contextual keywords (such as `"user"`)
      to the hashes that support them, but ignore them for hashes that don't (:issue:`63`).

    * The :mod:`passlib.apache` htpasswd helpers now preserve blank lines and comments,
      rather than throwing a parse error (:issue:`73`).

    * :mod:`passlib.ext.django` and unittests: compatibility fixes for Django 1.9 / 1.10,
      and some internal refactoring (:issue:`68`).

    * The :class:`~passlib.hash.django_disabled` hash now appends
      a 40-char alphanumeric string, to match Django's behavior.

.. _encrypt-method-cleanup:

Deprecations
------------
As part of a long-range plan to restructure and simplify both the API and the internals of Passlib,
a number of methods have been deprecated & replaced.  The eventually goal is a large cleanup
and overhaul as part of Passlib 2.0. There will be at least one more 1.x version
before Passlib 2.0, to provide a final transitional release
(see the `Project Roadmap <https://foss.heptapod.net/python-libs/passlib/wikis/roadmap>`_).

Password Hash API Deprecations
..............................
    .. currentmodule:: passlib.ifc

    As part of this cleanup, the :class:`~passlib.ifc.PasswordHash` API (used by all hashes in passlib),
    has had a number of changes:

    .. rst-class:: float-right

    .. seealso::

        :ref:`hash-tutorial`, which walks through using the new hasher interface.

    * **[major]** The :meth:`!PasswordHash.encrypt` method
      has been renamed to :meth:`PasswordHash.hash`,
      to clarify that it's performing one-way hashing rather than reversiable encryption.
      A compatibility alias will remain in place until Passlib 2.0.
      This should fix the longstanding :issue:`21`.

    * **[major]** Passing explicit configuration options to the :meth:`!PasswordHash.encrypt` method
      (now called :meth:`PasswordHash.hash`) is deprecated.
      To provide settings such as ``rounds`` and ``salt_size``, callers
      should use the new :meth:`PasswordHash.using`
      method, which generates a new hasher with a customized configuration.
      For example, instead of::

        >>>  sha256_crypt.encrypt("secret", rounds=12345)

      ... applications should now use::

        >>>  sha256_crypt.using(rounds=12345).hash("secret")

      Support for the old syntax will be removed in Passlib 2.0.

      .. note::

         This doesn't apply to contextual options such as :class:`~passlib.hash.cisco_pix`'s
         ``user`` keyword, which should still be passed into the :meth:`!hash` method.

    * **[minor]** The little-used :meth:`PasswordHash.genhash` and
      :meth:`PasswordHash.genconfig` methods have been deprecated.
      Compatibility aliases will remain in place until Passlib 2.0,
      at which point they will be removed entirely.

Crypt Context API Deprecations
..............................
    .. currentmodule:: passlib.context

    Applications which use passlib's :class:`~passlib.context.CryptContext` should not be
    greatly affected by this release; only one major deprecation was made:

    * **[major]** To match the :class:`!PasswordHash` API changes above,
      the :meth:`!CryptContext.encrypt` method was renamed to :meth:`CryptContext.hash`.
      A compatibility alias will remain until Passlib 2.0.

    A fewer internal options and infrequently used features have been deprecated:

    * **[minor]** :meth:`CryptContext.hash`, :meth:`~CryptContext.verify`,
      :meth:`~CryptContext.verify_and_update`, and
      :meth:`~CryptContext.needs_update`:
      The ``scheme`` keyword is now deprecated; support will be removed in Passlib 2.0.

    * **[minor]** :meth:`CryptContext.hash`: Passing
      settings keywords to :meth:`!hash` such as ``rounds`` and ``salt`` is deprecated.
      Code should now get ahold of the default hasher, and invoke it explicitly::

        >>>  # for example, calls that did this:
        >>>  context.hash(secret, rounds=1234)

        >>>  # should use this instead:
        >>>  context.handler().using(rounds=1234).hash(secret)

    * **[minor]** The ``vary_rounds`` option has been deprecated,
      and will be removed in Passlib 2.0.  It provided very little security benefit,
      and was judged not worth the additional code complexity it requires.

    * **[minor]** The special wildcard ``all`` scheme name
      has been deprecated, and will be removed in Passlib 2.0.  The only legitimate use
      was to support ``vary_rounds``, which itself will be removed in 2.0.

Other Deprecations
..................
    A few other assorted deprecations have been made:

    * The :func:`passlib.utils.generate_secret` function has been deprecated
      in favor of the new :mod:`passlib.pwd` module, and the old function will be removed
      in Passlib 2.0.

    * Most of passlib's internal cryptography helpers have been moved from
      :mod:`passlib.utils` to :mod:`passlib.crypto`, and the APIs refactored.
      This allowed unification of various hash management routines,
      some speed ups to the HMAC and PBKDF2 primitives, and opens up the architecture
      to support more optional backend libraries.

      Compatibility wrappers will be kept in place at the old location until Passlib 2.0.

    * Some deprecations and internal changes have been made to the :mod:`passlib.utils.handlers`
      module, which provides the common framework Passlib uses to implement hashers.

    .. caution::

      More backwards-incompatible relocations are planned for the internal
      :mod:`!passlib.utils` module in the Passlib 1.8 / 1.9 releases.

Backwards Incompatibilities
---------------------------
Changes in existing behavior:

    * **[minor]** M2Crypto no longer used to accelerate pbkdf2-hmac-sha1; applications relying on this
      to speed up :class:`~passlib.hash.pbkdf2_sha1` should install
      `fastpbkdf2 <https://pypi.python.org/pypi/fastpbkdf2>`_.

Scheduled removal of features:

    * **[minor]** :mod:`passlib.context`: The ``min_verify_time`` keyword
      that was deprecated in release 1.6, is now completely ignored.
      Support will be removed entirely in release 1.8.

    * **[trivial]** :mod:`passlib.hash`: The internal :meth:`!PasswordHash.parse_rounds` method, deprecated in 1.6, has been removed.

Minor incompatibilities:

    * **[minor]** :mod:`passlib.hash`: The little-used method :meth:`~passlib.ifc.PasswordHash.genconfig`
      will now always return a valid hash, rather than a truncated configuration
      string or ``None``.

    * **[minor]** :mod:`passlib.hash`: The little-used method :meth:`~passlib.ifc.PasswordHash.genhash` no longer accepts
      ``None`` as a config argument.

    * **[trivial]** :func:`passlib.utils.pbkdf2.pbkdf2` no longer supports custom PRF callables.
      this was an unused feature, and prevented some useful optimizations.
