Jelajahi Sumber

Clean support of public calendars, add support of private calendars

Guillaume Ayoub 14 tahun lalu
induk
melakukan
f9836ab093
7 mengubah file dengan 42 tambahan dan 13 penghapusan
  1. 1 1
      NEWS
  2. 4 0
      config
  3. 14 7
      radicale/__init__.py
  4. 3 3
      radicale/acl/LDAP.py
  5. 16 0
      radicale/acl/__init__.py
  6. 2 2
      radicale/acl/htpasswd.py
  7. 2 0
      radicale/config.py

+ 1 - 1
NEWS

@@ -14,7 +14,7 @@
 * Smart, verbose and configurable logs
 * Apple iCal 4 and iPhone support (by Łukasz Langa)
 * LDAP auth backend (by Corentin Le Bail)
-* Owner-less calendars (by René Neumann)
+* Public and private calendars (by René Neumann)
 * PID file
 * Journal entries support
 * Drop Python 2.5 support

+ 4 - 0
config

@@ -36,6 +36,10 @@ stock = utf-8
 # Access method
 # Value: None | htpasswd | LDAP
 type = None
+# Usernames used for public calendars, separated by a comma
+public_users = public
+# Usernames used for private calendars, separated by a comma
+private_users = private
 # Htpasswd filename
 htpasswd_filename = /etc/radicale/users
 # Htpasswd encryption method

+ 14 - 7
radicale/__init__.py

@@ -183,17 +183,24 @@ class Application(object):
                     if last_allowed:
                         calendars.append(calendar)
                     continue
-                log.LOGGER.info(
-                    "Checking rights for calendar owned by %s" % (
-                        calendar.owner or "nobody"))
 
-                if self.acl.has_right(calendar.owner, user, password):
-                    log.LOGGER.info("%s allowed" % (user or "anonymous user"))
+                if calendar.owner in acl.PUBLIC_USERS:
+                    log.LOGGER.info("Public calendar")
                     calendars.append(calendar)
                     last_allowed = True
                 else:
-                    log.LOGGER.info("%s refused" % (user or "anonymous user"))
-                    last_allowed = False
+                    log.LOGGER.info(
+                        "Checking rights for calendar owned by %s" % (
+                            calendar.owner or "nobody"))
+                    if self.acl.has_right(calendar.owner, user, password):
+                        log.LOGGER.info(
+                            "%s allowed" % (user or "Anonymous user"))
+                        calendars.append(calendar)
+                        last_allowed = True
+                    else:
+                        log.LOGGER.info(
+                            "%s refused" % (user or "Anonymous user"))
+                        last_allowed = False
 
             if calendars:
                 status, headers, answer = function(environ, calendars, content)

+ 3 - 3
radicale/acl/LDAP.py

@@ -26,7 +26,7 @@ Authentication based on the ``python-ldap`` module
 """
 
 import ldap
-from radicale import config, log
+from radicale import acl, config, log
 
 
 BASE = config.get("acl", "ldap_base")
@@ -38,8 +38,8 @@ PASSWORD = config.get("acl", "ldap_password")
 
 def has_right(owner, user, password):
     """Check if ``user``/``password`` couple is valid."""
-    if not user or (owner and user != owner):
-        # No user given, or owner is set and is not user, forbidden
+    if not user or (owner not in acl.PRIVATE_USERS and user != owner):
+        # No user given, or owner is not private and is not user, forbidden
         return False
 
     if BINDDN and PASSWORD:

+ 16 - 0
radicale/acl/__init__.py

@@ -29,11 +29,27 @@ configuration.
 from radicale import config
 
 
+PUBLIC_USERS = []
+PRIVATE_USERS = [None]
+
+
+def _config_users(name):
+    """Get an iterable of strings from the configuraton string [acl] ``name``.
+
+    The values must be separated by a comma. The whitespace characters are
+    stripped at the beginning and at the end of the values.
+
+    """
+    return (user.strip() for user in config.get("acl", name).split(","))
+
+
 def load():
     """Load list of available ACL managers."""
     acl_type = config.get("acl", "type")
     if acl_type == "None":
         return None
     else:
+        PUBLIC_USERS.extend(_config_users("public_users"))
+        PRIVATE_USERS.extend(_config_users("private_users"))
         module = __import__("radicale.acl", fromlist=[acl_type])
         return getattr(module, acl_type)

+ 2 - 2
radicale/acl/htpasswd.py

@@ -30,7 +30,7 @@ supported, but md5 is not (see ``htpasswd`` man page to understand why).
 import base64
 import hashlib
 
-from radicale import config
+from radicale import acl, config
 
 
 FILENAME = config.get("acl", "htpasswd_filename")
@@ -63,6 +63,6 @@ def has_right(owner, user, password):
     for line in open(FILENAME).readlines():
         if line.strip():
             login, hash_value = line.strip().split(":")
-            if login == user and (not owner or owner == user):
+            if login == user and (owner in acl.PRIVATE_USERS or owner == user):
                 return globals()["_%s" % ENCRYPTION](hash_value, password)
     return False

+ 2 - 0
radicale/config.py

@@ -50,6 +50,8 @@ INITIAL_CONFIG = {
         "stock": "utf-8"},
     "acl": {
         "type": "None",
+        "public_users": "public",
+        "private_users": "private",
         "httpasswd_filename": "/etc/radicale/users",
         "httpasswd_encryption": "crypt",
         "ldap_url": "ldap://localhost:389/",