From cd0ac7a7bd78fd1d386661237f62a6ae35351e8f Mon Sep 17 00:00:00 2001 From: Evgenii Alekseev Date: Sat, 5 Oct 2024 15:59:51 +0300 Subject: [PATCH] chore: replace passlib with bcrypt passlib uses deprecated crypt module which is deprecated and scheduled for removal in 3.13. Unfortunately, this module seems to be unmaintained, so this commit replaces passlib with bcrypt, unfortunately breaking current passwords --- .github/workflows/setup.sh | 2 +- Dockerfile | 2 +- docs/architecture.rst | 2 +- docs/index.rst | 2 +- docs/{migration.rst => migrations/2.12.0.rst} | 22 +------------------ docs/migrations/2.16.0.rst | 16 ++++++++++++++ docs/migrations/2.9.0.rst | 11 ++++++++++ docs/migrations/index.rst | 14 ++++++++++++ package/archlinux/PKGBUILD | 2 +- package/archlinux/ahriman.install | 14 ++++++++++-- pyproject.toml | 2 +- src/ahriman/models/user.py | 14 +++++------- 12 files changed, 66 insertions(+), 37 deletions(-) rename docs/{migration.rst => migrations/2.12.0.rst} (65%) create mode 100644 docs/migrations/2.16.0.rst create mode 100644 docs/migrations/2.9.0.rst create mode 100644 docs/migrations/index.rst diff --git a/.github/workflows/setup.sh b/.github/workflows/setup.sh index bd3e8fe8..0d3cc807 100755 --- a/.github/workflows/setup.sh +++ b/.github/workflows/setup.sh @@ -10,7 +10,7 @@ echo -e '[arcanisrepo]\nServer = https://repo.arcanis.me/$arch\nSigLevel = Never # refresh the image pacman -Syyu --noconfirm # main dependencies -pacman -S --noconfirm devtools git pyalpm python-inflection python-passlib python-pyelftools python-requests python-systemd sudo +pacman -S --noconfirm devtools git pyalpm python-bcrypt python-inflection python-pyelftools python-requests python-systemd sudo # make dependencies pacman -S --noconfirm --asdeps base-devel python-build python-flit python-installer python-tox python-wheel # optional dependencies diff --git a/Dockerfile b/Dockerfile index a58229f5..54b84656 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,8 +35,8 @@ RUN pacman -S --noconfirm --asdeps \ devtools \ git \ pyalpm \ + python-bcrypt \ python-inflection \ - python-passlib \ python-pyelftools \ python-requests \ && \ diff --git a/docs/architecture.rst b/docs/architecture.rst index cab793ed..780d10ef 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -147,7 +147,7 @@ There are multiple subdirectories, some of them are commons for any repository, * ``pacman/{repository}/{architecture}`` is the repository and architecture specific caches for pacman's databases. * ``repository/{repository}/{architecture}`` is a repository packages directory. -Normally you should avoid direct interaction with the application tree. For tree migration process refer to the :doc:`migration notes `. +Normally you should avoid direct interaction with the application tree. For tree migration process refer to the :doc:`migration notes `. Database -------- diff --git a/docs/index.rst b/docs/index.rst index 7c1625d0..977647bd 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -34,7 +34,7 @@ Contents configuration command-line faq/index - migration + migrations/index architecture advanced-usage triggers diff --git a/docs/migration.rst b/docs/migrations/2.12.0.rst similarity index 65% rename from docs/migration.rst rename to docs/migrations/2.12.0.rst index 9d1a5c5c..47f9e6d4 100644 --- a/docs/migration.rst +++ b/docs/migrations/2.12.0.rst @@ -1,25 +1,5 @@ -Manual migrations -================= - -Normally the most of migrations are handled automatically after application start, however, some upgrades require manual interventions; this document describes them. - -Upgrades to breakpoints ------------------------ - -To 2.9.0 -^^^^^^^^ - -This release includes major upgrade for the newest devtools and archlinux repository structure. In order to upgrade package need to: - -#. Upgrade to the latest major release of python (3.11) (required by other changes). -#. Upgrade devtools to the latest release. -#. Backup local settings, ``/etc/ahriman.ini.d/00-setup-overrides.ini`` by default. -#. Run setup command (i.e. ``ahriman service-setup``) again with the same arguments as used before. This step can be done manually by moving ``devtools`` configuration (something like ``/usr/share/devtools/pacman-ahriman*.conf``) to new location ``/usr/share/devtools/pacman.conf.d/`` under name ``ahriman.conf``. After that make sure to remove any ``community`` mentions from configurations (e.g. ``/usr/share/devtools/pacman.conf.d/ahriman.conf``, ``/etc/ahriman.ini``) if there were any. The only thing which will change is ``devtools`` configuration. -#. Remove build chroot as it is incompatible, e.g. ``sudo ahriman service-clean --chroot``. -#. Run ``sudo -u ahriman ahriman update --no-aur --no-local --no-manual -yy`` in order to update local databases. - To 2.12.0 -^^^^^^^^^ +--------- This release includes paths migration. Unlike usual case, no automatic migration is performed because it might break user configuration. The following noticeable changes have been made: diff --git a/docs/migrations/2.16.0.rst b/docs/migrations/2.16.0.rst new file mode 100644 index 00000000..14de9b53 --- /dev/null +++ b/docs/migrations/2.16.0.rst @@ -0,0 +1,16 @@ +To 2.16.0 +--------- + +This release replaces ``passlib`` dependency with ``bcrypt``. + +The reason behind this change is that python developers have deprecated and scheduled for removal ``crypt`` module, which is used by ``passlib``. (By the way, they recommend to use ``passlib`` as a replacement.) Unfortunately, it appears that ``passlib`` is unmaintained (see `the issue `__), so the only solution is to migrate to anoher library. + +Because passwords are stored as hashes, it is near to impossible to shadow change passwords in database, the manual intervention is required if: + +#. Authentication is used. +#. Notification provider is ``configuration`` or a user with explicitly set password exists. + +Manual steps might look as: + +#. Get list of users with their roles ``ahriman user-list``. +#. For each user run update command, i.e. ``ahriman user-add -R ``. Type password when it will be requested. diff --git a/docs/migrations/2.9.0.rst b/docs/migrations/2.9.0.rst new file mode 100644 index 00000000..31d842f3 --- /dev/null +++ b/docs/migrations/2.9.0.rst @@ -0,0 +1,11 @@ +To 2.9.0 +-------- + +This release includes major upgrade for the newest devtools and archlinux repository structure. In order to upgrade package need to: + +#. Upgrade to the latest major release of python (3.11) (required by other changes). +#. Upgrade devtools to the latest release. +#. Backup local settings, ``/etc/ahriman.ini.d/00-setup-overrides.ini`` by default. +#. Run setup command (i.e. ``ahriman service-setup``) again with the same arguments as used before. This step can be done manually by moving ``devtools`` configuration (something like ``/usr/share/devtools/pacman-ahriman*.conf``) to new location ``/usr/share/devtools/pacman.conf.d/`` under name ``ahriman.conf``. After that make sure to remove any ``community`` mentions from configurations (e.g. ``/usr/share/devtools/pacman.conf.d/ahriman.conf``, ``/etc/ahriman.ini``) if there were any. The only thing which will change is ``devtools`` configuration. +#. Remove build chroot as it is incompatible, e.g. ``sudo ahriman service-clean --chroot``. +#. Run ``sudo -u ahriman ahriman update --no-aur --no-local --no-manual -yy`` in order to update local databases. diff --git a/docs/migrations/index.rst b/docs/migrations/index.rst new file mode 100644 index 00000000..64dafb50 --- /dev/null +++ b/docs/migrations/index.rst @@ -0,0 +1,14 @@ +Manual migrations +================= + +Normally the most of migrations are handled automatically after application start, however, some upgrades require manual interventions; this document describes them. + +Upgrades to breakpoints +----------------------- + +.. toctree:: + :maxdepth: 2 + + 2.9.0 + 2.12.0 + 2.16.0 diff --git a/package/archlinux/PKGBUILD b/package/archlinux/PKGBUILD index 1617a83f..2834b3af 100644 --- a/package/archlinux/PKGBUILD +++ b/package/archlinux/PKGBUILD @@ -7,7 +7,7 @@ pkgdesc="ArcH linux ReposItory MANager" arch=('any') url="https://github.com/arcan1s/ahriman" license=('GPL3') -depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-inflection' 'python-passlib' 'python-pyelftools' 'python-requests') +depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-bcrypt' 'python-inflection' 'python-pyelftools' 'python-requests') makedepends=('python-build' 'python-flit' 'python-installer' 'python-wheel') optdepends=('python-aioauth-client: web server with OAuth2 authorization' 'python-aiohttp: web server' diff --git a/package/archlinux/ahriman.install b/package/archlinux/ahriman.install index a8ec42d7..da9a0d70 100644 --- a/package/archlinux/ahriman.install +++ b/package/archlinux/ahriman.install @@ -21,7 +21,7 @@ It was found that there was an upgrade from old devtools package to the new one, * remove build chroot, e.g.: ahriman service-clean --chroot; * update local databases: ahriman update --no-aur --no-local --no-manual -yy. -For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migration.html. +For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migrations/2.9.0.html. EOF } @@ -37,6 +37,16 @@ Whereas old local tree is still supported it is highly recommended to migrate to * enable web and timer services again by using x86_64-aur suffix, where x86_64 is the repository architecture and aur is the repository name. -For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migration.html. +For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migrations/2.12.0.html. +EOF +} + +_2_16_0_1_changes() { + cat << EOF +In order to prepare to python 3.13 the project now uses bcrypt instead of passlib for generating and validating +passwords, because the passlib seems to be unmaintained and will be broken since then. If you are using password +authentication, you'd need to generate passwords again. + +For more information kindly refer to migration notes https://ahriman.readthedocs.io/en/stable/migrations/2.16.0.html. EOF } diff --git a/pyproject.toml b/pyproject.toml index c72d137c..d0c65831 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,8 +17,8 @@ authors = [ ] dependencies = [ + "bcrypt", "inflection", - "passlib", "pyelftools", "requests", ] diff --git a/src/ahriman/models/user.py b/src/ahriman/models/user.py index e83deac3..4e3daa5f 100644 --- a/src/ahriman/models/user.py +++ b/src/ahriman/models/user.py @@ -17,8 +17,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +import bcrypt + from dataclasses import dataclass, replace -from passlib.hash import sha512_crypt from secrets import token_urlsafe as generate_password from typing import Self @@ -67,8 +68,6 @@ class User: packager_id: str | None = None key: str | None = None - _HASHER = sha512_crypt - def __post_init__(self) -> None: """ remove empty fields @@ -101,10 +100,9 @@ class User: bool: ``True`` in case if password matches, ``False`` otherwise """ try: - verified: bool = self._HASHER.verify(password + salt, self.password) + return bcrypt.checkpw((password + salt).encode("utf8"), self.password.encode("utf8")) except ValueError: - verified = False # the absence of evidence is not the evidence of absence (c) Gin Rummy - return verified + return False # the absence of evidence is not the evidence of absence (c) Gin Rummy def hash_password(self, salt: str) -> Self: """ @@ -120,8 +118,8 @@ class User: # in case of empty password we leave it empty. This feature is used by any external (like OAuth) provider # when we do not store any password here return self - password_hash: str = self._HASHER.hash(self.password + salt) - return replace(self, password=password_hash) + password_hash = bcrypt.hashpw((self.password + salt).encode("utf8"), bcrypt.gensalt()) + return replace(self, password=password_hash.decode("utf8")) def verify_access(self, required: UserAccess) -> bool: """