mirror of
https://github.com/Kozea/Radicale.git
synced 2025-04-03 21:27:36 +03:00
pam: merge+adjust module from v1
This commit is contained in:
parent
c8f650bc2c
commit
855e3743ca
1 changed files with 72 additions and 62 deletions
|
@ -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
|
||||
from radicale import auth
|
||||
from radicale.log import logger
|
||||
|
||||
|
||||
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
|
||||
|
||||
# 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 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
|
||||
|
||||
# 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
|
||||
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:
|
||||
log.LOGGER.debug("Wrong PAM password")
|
||||
else:
|
||||
log.LOGGER.debug(
|
||||
"The PAM user doesn't belong to the required group (%s)" %
|
||||
GROUP_MEMBERSHIP)
|
||||
logger.info("auth.pam_group_membership: (empty, nothing to check / INSECURE)")
|
||||
|
||||
return False
|
||||
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 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 ""
|
||||
|
||||
# Obtain supplementary groups
|
||||
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 the password
|
||||
if self.pam_authenticate(login, password, service=self._service):
|
||||
return login
|
||||
else:
|
||||
logger.debug("PAM authentication not successful for user: %r (service %r)" % (login, self._service))
|
||||
return ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue