Merge branch 'master' of github.com:Kozea/radicale

This commit is contained in:
Guillaume Ayoub 2016-05-06 17:57:58 +02:00
commit 2ce9fceaff
4 changed files with 22 additions and 19 deletions

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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