我正在寻找一种方法让我的Python程序通过pam处理身份验证。 我正在使用 http://code.google.com/p/web2py/source/browse/gluon/contrib/pam.py 来实现这一点,只要我的 python 程序以 root 身份运行(而不是 root 身份),效果就很好。我认为非常理想。
如何在不需要 root 权限的情况下使用 pam 进行用户名/密码验证?
注意:可能已过时,请参阅 Donovan Baarda 的评论!
简短:使用正确的Python PAM实现,正确设置PAM。
long:在正常的 PAM 设置中,您不需要
root
权限。最后,这就是 PAM 提供的功能之一:权限分离。
pam_unix
有办法帮你查密码。似乎 web2py
的 PAM 实现(注意,它来自某个 contrib 子目录...)没有做正确的事情。也许您的 PAM 设置不正确,在没有进一步信息的情况下很难判断;这也很大程度上取决于操作系统和风格/发行版。
Python 有多个 PAM 绑定(不幸的是标准库中没有),请使用它们。对于配置,有大量教程,找到适合您系统的教程。
旧的/错误的,不要这样做:你不需要成为root,你只需要能够阅读
/etc/shadow
shadow
。因此,您只需将正在运行 PAM
检查的用户添加到 shadow
组中即可。groupadd <user> shadow
我认为
pam
模块是你最好的选择,但你不必将它直接嵌入到你的程序中。您可以编写一个简单的服务,该服务绑定到本地主机上的端口,或者侦听 UNIX 域套接字,并填充同一主机上其他进程的 PAM 请求。然后让您的 web2py 应用程序连接到它以进行用户/密码验证。
例如:
import asyncore
import pam
import socket
class Client(asyncore.dispatcher_with_send):
def __init__(self, sock):
asyncore.dispatcher_with_send.__init__(self, sock)
self._buf = ''
def handle_read(self):
data = self._buf + self.recv(1024)
if not data:
self.close()
return
reqs, data = data.rsplit('\r\n', 1)
self._buf = data
for req in reqs.split('\r\n'):
try:
user, passwd = req.split()
except:
self.send('bad\r\n')
else:
if pam.authenticate(user, passwd):
self.send('ok\r\n')
else:
self.send('fail\r\n')
def handle_close(self):
self.close()
class Service(asyncore.dispatcher_with_send):
def __init__(self, addr):
asyncore.dispatcher_with_send.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(addr)
self.listen(1)
def handle_accept(self):
conn, _ = self.accept()
Client(conn)
def main():
addr = ('localhost', 8317)
Service(addr)
try:
asyncore.loop()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()
用途:
% telnet localhost 8317
bob abc123
ok
larry badpass
fail
incomplete
bad
最后我最终使用了 pexpect 并尝试 su - 用户名。 虽然有点慢,但是效果很好。 下面的示例尚未完善,但您会明白的。
干杯,
杰伊
#!/usr/bin/python
import pexpect
def pam(username, password):
'''Accepts username and password and tried to use PAM for authentication'''
try:
child = pexpect.spawn('/bin/su - %s'%(username))
child.expect('Password:')
child.sendline(password)
result=child.expect(['su: Authentication failure',username])
child.close()
except Exception as err:
child.close()
print ("Error authenticating. Reason: "%(err))
return False
if result == 0:
print ("Authentication failed for user %s."%(username))
return False
else:
print ("Authentication succeeded for user %s."%(username))
return True
if __name__ == '__main__':
print pam(username='default',password='chandgeme')
也许python-pam可以为你工作。
如果您使用常用的系统(unix 风格)登录凭据,则不会。在某些时候,PAM 库必须读取只能由 root 读取的影子文件。但是,如果您使用通过替代方法(例如 LDAP 或数据库)进行身份验证的 PAM 配置文件,则它无需 root 即可工作。
这是我开发自己的框架的原因之一,该框架在不同的用户凭据下运行 URL 路径空间的不同部分。登录部分(仅)可以以 root 身份运行以通过 PAM(系统)进行身份验证,其他路径子树处理程序以不同用户身份运行。
我正在使用 PyPAM 模块来实现此目的。