Procházet zdrojové kódy

pam: merge+adjust module from v1

Peter Bieringer před 1 rokem
rodič
revize
855e3743ca
1 změnil soubory, kde provedl 70 přidání a 60 odebrání
  1. 70 60
      radicale/auth/pam.py

+ 70 - 60
radicale/auth/pam.py

@@ -21,75 +21,85 @@
 """
 PAM authentication.
 
-Authentication based on the ``pam-python`` module.
+Authentication using the ``pam-python`` module.
 
+Important: radicale user need access to /etc/shadow by e.g.
+    chgrp radicale /etc/shadow
+    chmod g+r
 """
 
 import grp
-import pam
 import pwd
 
-from .. import config, log
-
-
-GROUP_MEMBERSHIP = config.get("auth", "pam_group_membership")
-
-
-# Compatibility for old versions of python-pam.
-if hasattr(pam, "pam"):
-    def pam_authenticate(*args, **kwargs):
-        return pam.pam().authenticate(*args, **kwargs)
-else:
-    def pam_authenticate(*args, **kwargs):
-        return pam.authenticate(*args, **kwargs)
-
-
-def is_authenticated(user, password):
-    """Check if ``user``/``password`` couple is valid."""
-    if user is None or password is None:
-        return False
+from radicale import auth
+from radicale.log import logger
+
+
+class Auth(auth.BaseAuth):
+    def __init__(self, configuration) -> None:
+        super().__init__(configuration)
+        try:
+            import pam
+            self.pam = pam
+        except ImportError as e:
+            raise RuntimeError("PAM authentication requires the Python pam module") from e
+        self._service = configuration.get("auth", "pam_service")
+        logger.info("auth.pam_service: %s" % self._service)
+        self._group_membership = configuration.get("auth", "pam_group_membership")
+        if (self._group_membership):
+            logger.info("auth.pam_group_membership: %s" % self._group_membership)
+        else:
+            logger.info("auth.pam_group_membership: (empty, nothing to check / INSECURE)")
+
+    def pam_authenticate(self, *args, **kwargs):
+        return self.pam.authenticate(*args, **kwargs)
+
+    def _login(self, login: str, password: str) -> str:
+        """Check if ``user``/``password`` couple is valid."""
+        if login is None or password is None:
+            return ""
+
+        # Check whether the user exists in the PAM system
+        try:
+            pwd.getpwnam(login).pw_uid
+        except KeyError:
+            logger.debug("PAM user not found: %r" % login)
+            return ""
+        else:
+            logger.debug("PAM user found: %r" % login)
 
-    # Check whether the user exists in the PAM system
-    try:
-        pwd.getpwnam(user).pw_uid
-    except KeyError:
-        log.LOGGER.debug("User %s not found" % user)
-        return False
-    else:
-        log.LOGGER.debug("User %s found" % user)
+        # Check whether the user has a primary group (mandatory)
+        try:
+            # Get user primary group
+            primary_group = grp.getgrgid(pwd.getpwnam(login).pw_gid).gr_name
+            logger.debug("PAM user %r has primary group: %r" % (login, primary_group))
+        except KeyError:
+            logger.debug("PAM user has no primary group: %r" % login)
+            return ""
 
-    # Check whether the group exists
-    try:
         # Obtain supplementary groups
-        members = grp.getgrnam(GROUP_MEMBERSHIP).gr_mem
-    except KeyError:
-        log.LOGGER.debug(
-            "The PAM membership required group (%s) doesn't exist" %
-            GROUP_MEMBERSHIP)
-        return False
+        members = []
+        if (self._group_membership):
+            try:
+                members = grp.getgrnam(self._group_membership).gr_mem
+            except KeyError:
+                logger.debug(
+                    "PAM membership required group doesn't exist: %r" %
+                    self._group_membership)
+                return ""
+
+        # Check whether the user belongs to the required group
+        # (primary or supplementary)
+        if (self._group_membership):
+            if (primary_group != self._group_membership) and (login not in members):
+                logger.warning("PAM user %r belongs not to the required group: %r" % (login, self._group_membership))
+                return ""
+            else:
+                logger.debug("PAM user %r belongs to the required group: %r" % (login, self._group_membership))
 
-    # Check whether the user exists
-    try:
-        # Get user primary group
-        primary_group = grp.getgrgid(pwd.getpwnam(user).pw_gid).gr_name
-    except KeyError:
-        log.LOGGER.debug("The PAM user (%s) doesn't exist" % user)
-        return False
-
-    # Check whether the user belongs to the required group
-    # (primary or supplementary)
-    if primary_group == GROUP_MEMBERSHIP or user in members:
-        log.LOGGER.debug(
-            "The PAM user belongs to the required group (%s)" %
-            GROUP_MEMBERSHIP)
         # Check the password
-        if pam_authenticate(user, password, service='radicale'):
-            return True
+        if self.pam_authenticate(login, password, service=self._service):
+            return login
         else:
-            log.LOGGER.debug("Wrong PAM password")
-    else:
-        log.LOGGER.debug(
-            "The PAM user doesn't belong to the required group (%s)" %
-            GROUP_MEMBERSHIP)
-
-    return False
+            logger.debug("PAM authentication not successful for user: %r (service %r)" % (login, self._service))
+            return ""