# (c) 2009-2024 Martin Wendt and contributors; see WsgiDAV https://github.com/mar10/wsgidav# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php"""Implementation of a domain controller that allows users to authenticate againsta Pluggable Authentication Module ('PAM').Used by HTTPAuthenticator. Only available on linux and macOS.See https://wsgidav.readthedocs.io/en/latest/user_guide_configure.html"""importosimportthreadingfromwsgidavimportutilfromwsgidav.dc.base_dcimportBaseDomainController__docformat__="reStructuredText"_logger=util.get_module_logger(__name__)try:importpamexceptImportError:_logger.error("pam_dc requires the `python-pam` module. Try `pip install wsgidav[pam]`.")raise
[docs]classPAMDomainController(BaseDomainController):def__init__(self,wsgidav_app,config):super().__init__(wsgidav_app,config)self.lock=threading.RLock()self.pam=pam.pam()dc_conf=util.get_dict_value(config,"pam_dc",as_dict=True)self.pam_service=dc_conf.get("service","login")self.pam_encoding=dc_conf.get("encoding","utf-8")self.pam_resetcreds=dc_conf.get("resetcreds",True)self.allow_users=dc_conf.get("allow_users","all")ifnot(self.allow_usersin("all","current")orisinstance(self.allow_users,list)):raiseValueError(f"Invalid 'allow_users' value: {self.allow_users!r}, expected 'all', 'current' or list of allowed users.")self.deny_users=dc_conf.get("deny_users",[])ifnotisinstance(self.deny_users,list):raiseValueError(f"Invalid 'deny_users' value: {self.deny_users!r}, expected list of denied users.")def__str__(self):returnf"{self.__class__.__name__}({self.pam_service!r})"
[docs]defbasic_auth_user(self,realm,user_name,password,environ):# Seems that python_pam is not threadsafe (#265)ifnotself._validate_user(user_name):_logger.warning(f"User {user_name!r} is not allowed.")returnFalsewithself.lock:is_ok=self.pam.authenticate(user_name,password,service=self.pam_service,resetcreds=self.pam_resetcreds,encoding=self.pam_encoding,)ifnotis_ok:_logger.warning(f"pam.authenticate({user_name!r}, '<redacted>', {self.pam_service!r}) failed with code {self.pam.code}: {self.pam.reason}")returnFalse_logger.debug(f"User {user_name!r} logged on.")returnTrue
[docs]defsupports_http_digest_auth(self):# We don't have access to a plaintext password (or stored hash)returnFalse