Merge branch 'master' of github.com:Kozea/radicale
This commit is contained in:
commit
2ce9fceaff
@ -52,6 +52,7 @@ following significantly more secure schemes are parsable by Radicale:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import functools
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
@ -102,15 +103,15 @@ class Auth(BaseAuth):
|
|||||||
self.verify = self._plain
|
self.verify = self._plain
|
||||||
elif self.encryption == "md5":
|
elif self.encryption == "md5":
|
||||||
try:
|
try:
|
||||||
from passlib.hash import apr_md5_crypt as _passlib_md5apr1
|
from passlib.hash import apr_md5_crypt
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"The htpasswd encryption method 'md5' requires "
|
"The htpasswd encryption method 'md5' requires "
|
||||||
"the passlib module.")
|
"the passlib module.")
|
||||||
self.verify = self._md5apr1
|
self.verify = functools.partial(self._md5apr1, apr_md5_crypt)
|
||||||
elif self.encryption == "bcrypt":
|
elif self.encryption == "bcrypt":
|
||||||
try:
|
try:
|
||||||
from passlib.hash import bcrypt as _passlib_bcrypt
|
from passlib.hash import bcrypt
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"The htpasswd encryption method 'bcrypt' requires "
|
"The htpasswd encryption method 'bcrypt' requires "
|
||||||
@ -118,8 +119,8 @@ class Auth(BaseAuth):
|
|||||||
# A call to `encrypt` raises passlib.exc.MissingBackendError with a
|
# A call to `encrypt` raises passlib.exc.MissingBackendError with a
|
||||||
# good error message if bcrypt backend is not available. Trigger
|
# good error message if bcrypt backend is not available. Trigger
|
||||||
# this here.
|
# this here.
|
||||||
_passlib_bcrypt.encrypt("test-bcrypt-backend")
|
bcrypt.encrypt("test-bcrypt-backend")
|
||||||
self.verify = self._bcrypt
|
self.verify = functools.partial(self._bcrypt, bcrypt)
|
||||||
elif self.encryption == "crypt":
|
elif self.encryption == "crypt":
|
||||||
try:
|
try:
|
||||||
import crypt
|
import crypt
|
||||||
@ -127,7 +128,7 @@ class Auth(BaseAuth):
|
|||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"The htpasswd encryption method 'crypt' requires "
|
"The htpasswd encryption method 'crypt' requires "
|
||||||
"the crypt() system support.")
|
"the crypt() system support.")
|
||||||
self.verify = self._crypt
|
self.verify = functools.partial(self._crypt, crypt)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"The htpasswd encryption method '%s' is not "
|
"The htpasswd encryption method '%s' is not "
|
||||||
@ -137,12 +138,10 @@ class Auth(BaseAuth):
|
|||||||
"""Check if ``hash_value`` and ``password`` match, using plain method."""
|
"""Check if ``hash_value`` and ``password`` match, using plain method."""
|
||||||
return hash_value == password
|
return hash_value == password
|
||||||
|
|
||||||
|
def _crypt(self, crypt, hash_value, password):
|
||||||
def _crypt(self, hash_value, password):
|
|
||||||
"""Check if ``hash_value`` and ``password`` match, using crypt method."""
|
"""Check if ``hash_value`` and ``password`` match, using crypt method."""
|
||||||
return crypt.crypt(password, hash_value) == hash_value
|
return crypt.crypt(password, hash_value) == hash_value
|
||||||
|
|
||||||
|
|
||||||
def _sha1(self, hash_value, password):
|
def _sha1(self, hash_value, password):
|
||||||
"""Check if ``hash_value`` and ``password`` match, using sha1 method."""
|
"""Check if ``hash_value`` and ``password`` match, using sha1 method."""
|
||||||
hash_value = hash_value.replace("{SHA}", "").encode("ascii")
|
hash_value = hash_value.replace("{SHA}", "").encode("ascii")
|
||||||
@ -151,7 +150,6 @@ class Auth(BaseAuth):
|
|||||||
sha1.update(password)
|
sha1.update(password)
|
||||||
return sha1.digest() == base64.b64decode(hash_value)
|
return sha1.digest() == base64.b64decode(hash_value)
|
||||||
|
|
||||||
|
|
||||||
def _ssha(self, hash_salt_value, password):
|
def _ssha(self, hash_salt_value, password):
|
||||||
"""Check if ``hash_salt_value`` and ``password`` match, using salted sha1
|
"""Check if ``hash_salt_value`` and ``password`` match, using salted sha1
|
||||||
method. This method is not directly supported by htpasswd, but it can be
|
method. This method is not directly supported by htpasswd, but it can be
|
||||||
@ -166,13 +164,11 @@ class Auth(BaseAuth):
|
|||||||
sha1.update(salt_value)
|
sha1.update(salt_value)
|
||||||
return sha1.digest() == hash_value
|
return sha1.digest() == hash_value
|
||||||
|
|
||||||
|
def _bcrypt(self, bcrypt, hash_value, password):
|
||||||
|
return bcrypt.verify(password, hash_value)
|
||||||
|
|
||||||
def _bcrypt(self, hash_value, password):
|
def _md5apr1(self, md5_apr1, hash_value, password):
|
||||||
return _passlib_bcrypt.verify(password, hash_value)
|
return md5_apr1.verify(password, hash_value)
|
||||||
|
|
||||||
|
|
||||||
def _md5apr1(self, hash_value, password):
|
|
||||||
return _passlib_md5apr1.verify(password, hash_value)
|
|
||||||
|
|
||||||
def is_authenticated(self, user, password):
|
def is_authenticated(self, user, password):
|
||||||
# The content of the file is not cached because reading is generally a
|
# The content of the file is not cached because reading is generally a
|
||||||
@ -186,4 +182,3 @@ class Auth(BaseAuth):
|
|||||||
if login == user:
|
if login == user:
|
||||||
return self.verify(hash_value, password)
|
return self.verify(hash_value, password)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -97,11 +97,12 @@ class BaseRights:
|
|||||||
|
|
||||||
class Rights(BaseRights):
|
class Rights(BaseRights):
|
||||||
def __init__(self, configuration, logger):
|
def __init__(self, configuration, logger):
|
||||||
super().__init__()
|
super().__init__(configuration, logger)
|
||||||
self.filename = os.path.expanduser(configuration.get("rights", "file"))
|
self.filename = os.path.expanduser(configuration.get("rights", "file"))
|
||||||
self.rights_type = configuration.get("rights", "type").lower()
|
self.rights_type = configuration.get("rights", "type").lower()
|
||||||
|
|
||||||
def authorized(self, user, collection, permission):
|
def authorized(self, user, collection, permission):
|
||||||
|
user = user or ''
|
||||||
collection_url = collection.path.rstrip("/") or "/"
|
collection_url = collection.path.rstrip("/") or "/"
|
||||||
if collection_url in (".well-known/carddav", ".well-known/caldav"):
|
if collection_url in (".well-known/carddav", ".well-known/caldav"):
|
||||||
return permission == "r"
|
return permission == "r"
|
||||||
|
@ -45,6 +45,7 @@ def load(configuration, logger):
|
|||||||
collection_class = Collection
|
collection_class = Collection
|
||||||
else:
|
else:
|
||||||
collection_class = import_module(storage_type).Collection
|
collection_class = import_module(storage_type).Collection
|
||||||
|
|
||||||
class CollectionCopy(collection_class):
|
class CollectionCopy(collection_class):
|
||||||
"""Collection copy, avoids overriding the original class attributes."""
|
"""Collection copy, avoids overriding the original class attributes."""
|
||||||
CollectionCopy.configuration = configuration
|
CollectionCopy.configuration = configuration
|
||||||
|
8
tox.ini
8
tox.ini
@ -7,9 +7,12 @@ deps =
|
|||||||
nose-cov
|
nose-cov
|
||||||
pam
|
pam
|
||||||
requests
|
requests
|
||||||
|
flake8
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
commands = nosetests []
|
commands =
|
||||||
|
flake8
|
||||||
|
nosetests []
|
||||||
|
|
||||||
[testenv:py33]
|
[testenv:py33]
|
||||||
deps =
|
deps =
|
||||||
@ -25,3 +28,6 @@ deps =
|
|||||||
deps =
|
deps =
|
||||||
git+https://github.com/eberle1080/dulwich-py3k.git
|
git+https://github.com/eberle1080/dulwich-py3k.git
|
||||||
{[base]deps}
|
{[base]deps}
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
max-line-length = 100
|
||||||
|
Loading…
Reference in New Issue
Block a user