Cut long lines
This commit is contained in:
parent
36ad6bd021
commit
a8fda1aedf
@ -482,7 +482,8 @@ class Application:
|
|||||||
"DAV": "1, 2, 3, calendar-access, addressbook, extended-mkcol",
|
"DAV": "1, 2, 3, calendar-access, addressbook, extended-mkcol",
|
||||||
"Content-Type": "text/xml"}
|
"Content-Type": "text/xml"}
|
||||||
answer = xmlutils.propfind(
|
answer = xmlutils.propfind(
|
||||||
environ["PATH_INFO"], content, read_collections, write_collections, user)
|
environ["PATH_INFO"], content, read_collections, write_collections,
|
||||||
|
user)
|
||||||
return client.MULTI_STATUS, headers, answer
|
return client.MULTI_STATUS, headers, answer
|
||||||
|
|
||||||
def do_PROPPATCH(self, environ, read_collections, write_collections,
|
def do_PROPPATCH(self, environ, read_collections, write_collections,
|
||||||
|
@ -21,12 +21,13 @@ Authentication management.
|
|||||||
|
|
||||||
Default is htpasswd authentication.
|
Default is htpasswd authentication.
|
||||||
|
|
||||||
Apache's htpasswd command (httpd.apache.org/docs/programs/htpasswd.html) manages
|
Apache's htpasswd command (httpd.apache.org/docs/programs/htpasswd.html)
|
||||||
a file for storing user credentials. It can encrypt passwords using different
|
manages a file for storing user credentials. It can encrypt passwords using
|
||||||
methods, e.g. BCRYPT, MD5-APR1 (a version of MD5 modified for Apache), SHA1, or
|
different methods, e.g. BCRYPT, MD5-APR1 (a version of MD5 modified for
|
||||||
by using the system's CRYPT routine. The CRYPT and SHA1 encryption methods
|
Apache), SHA1, or by using the system's CRYPT routine. The CRYPT and SHA1
|
||||||
implemented by htpasswd are considered as insecure. MD5-APR1 provides medium
|
encryption methods implemented by htpasswd are considered as insecure. MD5-APR1
|
||||||
security as of 2015. Only BCRYPT can be considered secure by current standards.
|
provides medium security as of 2015. Only BCRYPT can be considered secure by
|
||||||
|
current standards.
|
||||||
|
|
||||||
MD5-APR1-encrypted credentials can be written by all versions of htpasswd (it
|
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 requires htpasswd 2.4.x or newer.
|
||||||
@ -80,9 +81,9 @@ class BaseAuth:
|
|||||||
def is_authenticated(self, user, password):
|
def is_authenticated(self, user, password):
|
||||||
"""Validate credentials.
|
"""Validate credentials.
|
||||||
|
|
||||||
Iterate through htpasswd credential file until user matches, extract hash
|
Iterate through htpasswd credential file until user matches, extract
|
||||||
(encrypted password) and check hash against user-given password, using the
|
hash (encrypted password) and check hash against user-given password,
|
||||||
method specified in the Radicale config.
|
using the method specified in the Radicale config.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@ -135,30 +136,33 @@ class Auth(BaseAuth):
|
|||||||
"supported." % self.encryption)
|
"supported." % self.encryption)
|
||||||
|
|
||||||
def _plain(self, hash_value, password):
|
def _plain(self, hash_value, password):
|
||||||
"""Check if ``hash_value`` and ``password`` match, using plain method."""
|
"""Check if ``hash_value`` and ``password`` match, plain method."""
|
||||||
return hash_value == password
|
return hash_value == password
|
||||||
|
|
||||||
def _crypt(self, crypt, hash_value, password):
|
def _crypt(self, crypt, hash_value, password):
|
||||||
"""Check if ``hash_value`` and ``password`` match, using crypt method."""
|
"""Check if ``hash_value`` and ``password`` match, 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, sha1 method."""
|
||||||
hash_value = hash_value.replace("{SHA}", "").encode("ascii")
|
hash_value = hash_value.replace("{SHA}", "").encode("ascii")
|
||||||
password = password.encode(self.configuration.get("encoding", "stock"))
|
password = password.encode(self.configuration.get("encoding", "stock"))
|
||||||
sha1 = hashlib.sha1() # pylint: disable=E1101
|
sha1 = hashlib.sha1() # pylint: disable=E1101
|
||||||
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_value, password):
|
||||||
"""Check if ``hash_salt_value`` and ``password`` match, using salted sha1
|
"""Check if ``hash_value`` and ``password`` match, salted sha1 method.
|
||||||
method. This method is not directly supported by htpasswd, but it can be
|
|
||||||
written with e.g. openssl, and nginx can parse it."""
|
This method is not directly supported by htpasswd, but it can be
|
||||||
hash_salt_value = hash_salt_value.replace(
|
written with e.g. openssl, and nginx can parse it.
|
||||||
|
|
||||||
|
"""
|
||||||
|
hash_value = hash_value.replace(
|
||||||
"{SSHA}", "").encode("ascii").decode('base64')
|
"{SSHA}", "").encode("ascii").decode('base64')
|
||||||
password = password.encode(self.configuration.get("encoding", "stock"))
|
password = password.encode(self.configuration.get("encoding", "stock"))
|
||||||
hash_value = hash_salt_value[:20]
|
hash_value = hash_value[:20]
|
||||||
salt_value = hash_salt_value[20:]
|
salt_value = hash_value[20:]
|
||||||
sha1 = hashlib.sha1() # pylint: disable=E1101
|
sha1 = hashlib.sha1() # pylint: disable=E1101
|
||||||
sha1.update(password)
|
sha1.update(password)
|
||||||
sha1.update(salt_value)
|
sha1.update(salt_value)
|
||||||
|
@ -181,9 +181,9 @@ def _prop_match(item, filter_):
|
|||||||
filter_.remove(filter_[0])
|
filter_.remove(filter_[0])
|
||||||
elif filter_[0].tag == _tag("C", "text-match"):
|
elif filter_[0].tag == _tag("C", "text-match"):
|
||||||
# Point #4 of rfc4791-9.7.2
|
# Point #4 of rfc4791-9.7.2
|
||||||
# TODO: collations are not supported, but the default ones needed for DAV
|
# TODO: collations are not supported, but the default ones needed
|
||||||
# servers are actually pretty useless. Texts are lowered to be
|
# for DAV servers are actually pretty useless. Texts are lowered to
|
||||||
# case-insensitive, almost as the "i;ascii-casemap" value.
|
# be case-insensitive, almost as the "i;ascii-casemap" value.
|
||||||
match = next(filter_[0].itertext()).lower()
|
match = next(filter_[0].itertext()).lower()
|
||||||
value = vobject_item.getChildValue(filter_.get("name").lower())
|
value = vobject_item.getChildValue(filter_.get("name").lower())
|
||||||
if value is None:
|
if value is None:
|
||||||
@ -296,7 +296,8 @@ def delete(path, collection):
|
|||||||
return _pretty_xml(multistatus)
|
return _pretty_xml(multistatus)
|
||||||
|
|
||||||
|
|
||||||
def propfind(path, xml_request, read_collections, write_collections, user=None):
|
def propfind(path, xml_request, read_collections, write_collections,
|
||||||
|
user=None):
|
||||||
"""Read and answer PROPFIND requests.
|
"""Read and answer PROPFIND requests.
|
||||||
|
|
||||||
Read rfc4918-9.1 for info.
|
Read rfc4918-9.1 for info.
|
||||||
@ -324,12 +325,14 @@ def propfind(path, xml_request, read_collections, write_collections, user=None):
|
|||||||
collections = []
|
collections = []
|
||||||
for collection in write_collections:
|
for collection in write_collections:
|
||||||
collections.append(collection)
|
collections.append(collection)
|
||||||
response = _propfind_response(path, collection, props, user, write=True)
|
response = _propfind_response(
|
||||||
|
path, collection, props, user, write=True)
|
||||||
multistatus.append(response)
|
multistatus.append(response)
|
||||||
for collection in read_collections:
|
for collection in read_collections:
|
||||||
if collection in collections:
|
if collection in collections:
|
||||||
continue
|
continue
|
||||||
response = _propfind_response(path, collection, props, user, write=False)
|
response = _propfind_response(
|
||||||
|
path, collection, props, user, write=False)
|
||||||
multistatus.append(response)
|
multistatus.append(response)
|
||||||
|
|
||||||
return _pretty_xml(multistatus)
|
return _pretty_xml(multistatus)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user