Просмотр исходного кода

Auth: Introduce login(login, password) method

This deprecates map_login_to_user, is_authenticated and is_authenticated2
Unrud 7 лет назад
Родитель
Сommit
6c9299cf16
2 измененных файлов с 40 добавлено и 33 удалено
  1. 22 23
      radicale/__init__.py
  2. 18 10
      radicale/auth.py

+ 22 - 23
radicale/__init__.py

@@ -440,6 +440,7 @@ class Application:
         authorization = environ.get("HTTP_AUTHORIZATION", "")
         authorization = environ.get("HTTP_AUTHORIZATION", "")
         if external_login:
         if external_login:
             login, password = external_login
             login, password = external_login
+            login, password = login or "", password or ""
         elif authorization.startswith("Basic"):
         elif authorization.startswith("Basic"):
             authorization = authorization[len("Basic"):].strip()
             authorization = authorization[len("Basic"):].strip()
             login, password = self.decode(base64.b64decode(
             login, password = self.decode(base64.b64decode(
@@ -448,30 +449,28 @@ class Application:
             # DEPRECATED: use remote_user backend instead
             # DEPRECATED: use remote_user backend instead
             login = environ.get("REMOTE_USER", "")
             login = environ.get("REMOTE_USER", "")
             password = ""
             password = ""
-        user = self.Auth.map_login_to_user(login)
 
 
-        if not user:
-            is_authenticated = True
-        elif not storage.is_safe_path_component(user):
+        user = self.Auth.login(login, password) or "" if login else ""
+        if user and login == user:
+            self.logger.info("Successful login: %r", user)
+        elif user:
+            self.logger.info("Successful login: %r -> %r", login, user)
+        elif login:
+            self.logger.info("Failed login attempt: %r", login)
+            # Random delay to avoid timing oracles and bruteforce attacks
+            delay = self.configuration.getfloat("auth", "delay")
+            if delay > 0:
+                random_delay = delay * (0.5 + random.random())
+                self.logger.debug("Sleeping %.3f seconds", random_delay)
+                time.sleep(random_delay)
+
+        if user and not storage.is_safe_path_component(user):
             # Prevent usernames like "user/calendar.ics"
             # Prevent usernames like "user/calendar.ics"
             self.logger.info("Refused unsafe username: %r", user)
             self.logger.info("Refused unsafe username: %r", user)
-            is_authenticated = False
-        else:
-            is_authenticated = self.Auth.is_authenticated2(login, user,
-                                                           password)
-            if not is_authenticated:
-                self.logger.info("Failed login attempt: %r", user)
-                # Random delay to avoid timing oracles and bruteforce attacks
-                delay = self.configuration.getfloat("auth", "delay")
-                if delay > 0:
-                    random_delay = delay * (0.5 + random.random())
-                    self.logger.debug("Sleeping %.3f seconds", random_delay)
-                    time.sleep(random_delay)
-            else:
-                self.logger.info("Successful login: %r", user)
+            user = ""
 
 
         # Create principal collection
         # Create principal collection
-        if user and is_authenticated:
+        if user:
             principal_path = "/%s/" % user
             principal_path = "/%s/" % user
             if self.Rights.authorized(user, principal_path, "w"):
             if self.Rights.authorized(user, principal_path, "w"):
                 with self.Collection.acquire_lock("r", user):
                 with self.Collection.acquire_lock("r", user):
@@ -485,7 +484,7 @@ class Application:
                         except ValueError as e:
                         except ValueError as e:
                             self.logger.warning("Failed to create principal "
                             self.logger.warning("Failed to create principal "
                                                 "collection %r: %s", user, e)
                                                 "collection %r: %s", user, e)
-                            is_authenticated = False
+                            user = ""
             else:
             else:
                 self.logger.warning("Access to principal path %r denied by "
                 self.logger.warning("Access to principal path %r denied by "
                                     "rights backend", principal_path)
                                     "rights backend", principal_path)
@@ -500,7 +499,7 @@ class Application:
                     "Request body too large: %d", content_length)
                     "Request body too large: %d", content_length)
                 return response(*REQUEST_ENTITY_TOO_LARGE)
                 return response(*REQUEST_ENTITY_TOO_LARGE)
 
 
-        if is_authenticated:
+        if not login or user:
             status, headers, answer = function(
             status, headers, answer = function(
                 environ, base_prefix, path, user)
                 environ, base_prefix, path, user)
             if (status, headers, answer) == NOT_ALLOWED:
             if (status, headers, answer) == NOT_ALLOWED:
@@ -509,8 +508,8 @@ class Application:
         else:
         else:
             status, headers, answer = NOT_ALLOWED
             status, headers, answer = NOT_ALLOWED
 
 
-        if (status, headers, answer) == NOT_ALLOWED and not (
-                user and is_authenticated) and not external_login:
+        if ((status, headers, answer) == NOT_ALLOWED and not user and
+                not external_login):
             # Unknown or unauthorized user
             # Unknown or unauthorized user
             self.logger.debug("Asking client for authentication")
             self.logger.debug("Asking client for authentication")
             status = client.UNAUTHORIZED
             status = client.UNAUTHORIZED

+ 18 - 10
radicale/auth.py

@@ -102,14 +102,26 @@ class BaseAuth:
         """
         """
         return ()
         return ()
 
 
-    def is_authenticated2(self, login, user, password):
-        """Validate credentials.
+    def login(self, login, password):
+        """Check credentials and map login to internal user
 
 
         ``login`` the login name
         ``login`` the login name
 
 
-        ``user`` the user from ``map_login_to_user(login)``.
+        ``password`` the password
+
+        Returns the user name or ``""`` for invalid credentials.
+
+        """
+
+        user = self.map_login_to_user(login)
+        if user and self.is_authenticated2(login, user, password):
+            return user
+        return ""
 
 
-        ``password`` the login password
+    def is_authenticated2(self, login, user, password):
+        """Validate credentials.
+
+        DEPRECATED: use ``login`` instead
 
 
         """
         """
         return self.is_authenticated(user, password)
         return self.is_authenticated(user, password)
@@ -117,7 +129,7 @@ class BaseAuth:
     def is_authenticated(self, user, password):
     def is_authenticated(self, user, password):
         """Validate credentials.
         """Validate credentials.
 
 
-        DEPRECATED: use ``is_authenticated2`` instead
+        DEPRECATED: use ``login`` instead
 
 
         """
         """
         raise NotImplementedError
         raise NotImplementedError
@@ -125,11 +137,7 @@ class BaseAuth:
     def map_login_to_user(self, login):
     def map_login_to_user(self, login):
         """Map login name to internal user.
         """Map login name to internal user.
 
 
-        ``login`` the login name, ``""`` for anonymous users
-
-        Returns a string with the user name.
-        If a login can't be mapped to an user, return ``login`` and
-        return ``False`` in ``is_authenticated2(...)``.
+        DEPRECATED: use ``login`` instead
 
 
         """
         """
         return login
         return login