From acc06587ce3dab130443f6457f13ea9b6df25bbd Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Tue, 12 Mar 2024 06:06:40 +0100 Subject: [PATCH 1/4] extend htpasswd_encryption options with sha256/512/autodetect --- config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config b/config index 5767dc9c..18a8ff40 100644 --- a/config +++ b/config @@ -59,7 +59,7 @@ #htpasswd_filename = /etc/radicale/users # Htpasswd encryption method -# Value: plain | bcrypt | md5 +# Value: plain | bcrypt | md5 | sha256 | sha512 | autodetect # bcrypt requires the installation of 'bcrypt' module. #htpasswd_encryption = md5 From 29a2a80bfd0f1a10931eac880279cef00e481041 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Tue, 12 Mar 2024 06:08:26 +0100 Subject: [PATCH 2/4] extend htpasswd_encryption options with sha256/512/autodetect --- radicale/auth/htpasswd.py | 56 ++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/radicale/auth/htpasswd.py b/radicale/auth/htpasswd.py index 8bba1f78..098f7b78 100644 --- a/radicale/auth/htpasswd.py +++ b/radicale/auth/htpasswd.py @@ -3,6 +3,7 @@ # Copyright © 2008 Pascal Halter # Copyright © 2008-2017 Guillaume Ayoub # Copyright © 2017-2019 Unrud +# Copyright © 2024 Peter Bieringer # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,12 +23,12 @@ Authentication backend that checks credentials with a htpasswd file. Apache's htpasswd command (httpd.apache.org/docs/programs/htpasswd.html) manages a file for storing user credentials. It can encrypt passwords using -different the methods BCRYPT or MD5-APR1 (a version of MD5 modified for -Apache). MD5-APR1 provides medium security as of 2015. Only BCRYPT can be +different the methods BCRYPT/SHA256/SHA512 or MD5-APR1 (a version of MD5 modified for +Apache). MD5-APR1 provides medium security as of 2015. Only BCRYPT/SHA256/SHA512 can be considered secure by current standards. MD5-APR1-encrypted credentials can be written by all versions of htpasswd (it -is the default, in fact), whereas BCRYPT requires htpasswd 2.4.x or newer. +is the default, in fact), whereas BCRYPT/SHA256/SHA512 requires htpasswd 2.4.x or newer. The `is_authenticated(user, password)` function provided by this module verifies the user-given credentials by parsing the htpasswd credential file @@ -37,13 +38,13 @@ configuration value. The following htpasswd password encrpytion methods are supported by Radicale out-of-the-box: - - - plain-text (created by htpasswd -p...) -- INSECURE - - MD5-APR1 (htpasswd -m...) -- htpasswd's default method + - plain-text (created by htpasswd -p ...) -- INSECURE + - MD5-APR1 (htpasswd -m ...) -- htpasswd's default method, INSECURE + - SHA256 (htpasswd -2 ...) + - SHA512 (htpasswd -5 ...) When bcrypt is installed: - - - BCRYPT (htpasswd -B...) -- Requires htpasswd 2.4.x + - BCRYPT (htpasswd -B ...) -- Requires htpasswd 2.4.x """ @@ -51,9 +52,9 @@ import functools import hmac from typing import Any -from passlib.hash import apr_md5_crypt +from passlib.hash import apr_md5_crypt, sha256_crypt, sha512_crypt -from radicale import auth, config +from radicale import auth, config, logger class Auth(auth.BaseAuth): @@ -67,18 +68,24 @@ class Auth(auth.BaseAuth): self._encoding = configuration.get("encoding", "stock") encryption: str = configuration.get("auth", "htpasswd_encryption") + logger.info("auth password encryption: %s", encryption) + if encryption == "plain": self._verify = self._plain elif encryption == "md5": self._verify = self._md5apr1 - elif encryption == "bcrypt": + elif encryption == "bcrypt" or encryption == "autodetect": try: import bcrypt except ImportError as e: raise RuntimeError( - "The htpasswd encryption method 'bcrypt' requires " + "The htpasswd encryption method 'bcrypt' or 'auto' requires " "the bcrypt module.") from e - self._verify = functools.partial(self._bcrypt, bcrypt) + if encryption == "bcrypt": + self._verify = functools.partial(self._bcrypt, bcrypt) + else: + self._verify = self._autodetect + self._verify_bcrypt = functools.partial(self._bcrypt, bcrypt) else: raise RuntimeError("The htpasswd encryption method %r is not " "supported." % encryption) @@ -93,6 +100,29 @@ class Auth(auth.BaseAuth): def _md5apr1(self, hash_value: str, password: str) -> bool: return apr_md5_crypt.verify(password, hash_value.strip()) + def _sha256(self, hash_value: str, password: str) -> bool: + return sha256_crypt.verify(password, hash_value.strip()) + + def _sha512(self, hash_value: str, password: str) -> bool: + return sha512_crypt.verify(password, hash_value.strip()) + + def _autodetect(self, hash_value: str, password: str) -> bool: + if hash_value.startswith("$apr1$", 0, 6) and len(hash_value) == 37: + # MD5-APR1 + return self._md5apr1(hash_value, password) + elif hash_value.startswith("$2y$", 0, 4) and len(hash_value) == 60: + # BCRYPT + return self._verify_bcrypt(hash_value, password) + elif hash_value.startswith("$5$", 0, 3) and len(hash_value) == 63: + # SHA-256 + return self._sha256(hash_value, password) + elif hash_value.startswith("$6$", 0, 3) and len(hash_value) == 106: + # SHA-512 + return self._sha512(hash_value, password) + else: + # assumed plaintext + return self._plain(hash_value, password) + def login(self, login: str, password: str) -> str: """Validate credentials. From dba399bce34179e907a3f3157f2eaaf163793649 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Tue, 12 Mar 2024 06:10:16 +0100 Subject: [PATCH 3/4] extend htpasswd_encryption options with sha256/512/autodetect --- DOCUMENTATION.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index b9c715c9..9078681f 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -761,7 +761,16 @@ Available methods: The installation of **bcrypt** is required for this. `md5` -: This uses an iterated md5 digest of the password with a salt. +: This uses an iterated MD5 digest of the password with a salt. + +`sha256` +: This uses an iterated SHA-256 digest of the password with a salt. + +`sha512` +: This uses an iterated SHA-512 digest of the password with a salt. + +`autodetect` +: This selects autodetection of method per entry. Default: `md5` From 213ab0fcfa2eec42b5324095abff1ee38329b2e9 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Tue, 12 Mar 2024 06:13:54 +0100 Subject: [PATCH 4/4] extend htpasswd_encryption options with sha256/512/autodetect --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d64fa25..a2659bb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ * Enhancement: autodetect logging to systemd journal * Enhancement: test code * Enhancement: option for global permit to delete collection +* Enhancement: auth type 'htpasswd' supports now 'htpasswd_encryption' sha256/sha512 and "autodetect" for smooth transition * Improve: Dockerfiles * Update: documentations + examples * Dependency: limit typegard version < 3